Автоматическое создание связанных объектов при создании модели в Django

Я новичок в Django, поэтому извините мое невежество:)

скажем, у меня есть модель, которая имеет пару отношений внешнего ключа, и когда я создаю экземпляр модели, я хочу, чтобы он автоматически создавал новые экземпляры для объектов внешнего ключа. В этом случае я моделирую регистрацию курса как группу, и я ссылаюсь на конкретную группу как на внешний ключ в модели.

class Course(models.Model):
    student_group = models.OneToOneField(Group, related_name="course_taken")
    teacher_group = models.OneToOneField(Group, related_name="course_taught")

    def clean(self):
        if self.id:
            try:
                self.student_group
            except Group.DoesNotExist:
                self.student_group, _ = Group.objects.get_or_create(name='_course_' + self.id + '_student')

            try:
                self.teacher_group
            except Group.DoesNotExist:
                self.teacher_group, _ = Group.objects.get_or_create(name='_course_' + self.id + '_teacher')

Кажется, что я могу подключиться к чистому методу модели, чтобы сделать это, но Я хотел бы иметь возможность обернуть все это в одну транзакцию, так что если он не сможет создать курс позже, он не будет создавать связанные объекты группы. Есть ли способ достичь этого?

кроме того, я делаю что-то неправильно здесь? Предоставляет ли Django лучший способ сделать это?

4 ответов


В конце концов я остановился на:

from django.db import models, transaction
class Course(models.Model):
    student_group = models.OneToOneField(Group, related_name="course_taken")

    @transaction.commit_on_success
    def save(self, *args, **kwargs):
        if not self.student_group_id:
            self.student_group, _ = Group.objects.get_or_create(name='_course_' + self.id + '_student')

        super(Course, self).save(*args, **kwargs)

Edit (2014/12/01): @Shasanoglu правильно, приведенный выше код на самом деле не работает из-за id еще не существует. Вы должны сделать Связанный объект creation после вы называете save (так что вы называете super.сохраните, создайте Связанный объект, обновите этот объект и вызовите super.сохранить снова - не идеально. Это или вы опускаете идентификатор из имени группы, и все в порядке). В конечном счете, я переместил создание автоматического связанного объекта из модели полностью. Я сделал все это в методе сохранения пользовательской формы, которая была намного чище, и отказался от использования этой модели в интерфейсе администратора (именно поэтому я настоял на том, чтобы сделать все это в методе модели в первую очередь)


можно использовать модели.сигналы.post_save сигнал для обработки такой случай:

from django.db import models

class Course(models.Model):
    student_group = models.OneToOneField(Group, related_name="course_taken")
    teacher_group = models.OneToOneField(Group, related_name="course_taught")


def create_course_groups(instance, created, raw, **kwargs):
    # Ignore fixtures and saves for existing courses.
    if not created or raw:
        return

    if not instance.student_group_id:
        group, _ = Group.objects.get_or_create(name='_course_' + self.id + '_student')
        instance.student_group = group

    if not instance.teacher_group_id:
        teacher_group, _ = Group.objects.get_or_create(name='_course_' + self.id + '_teacher')
        instance.teacher_group = teacher_group

    instance.save()

models.signals.post_save.connect(create_course_groups, sender=Course, dispatch_uid='create_course_groups')

я использовал решение wjin в аналогичной проблеме в Django 1.7. Мне просто нужно было внести 2 изменения:

  1. пришлось менять commit_on_success С atomic
  2. self.id не работает, потому что код запускается до установки идентификатора при создании нового объекта. Я должен был использовать что-то еще в качестве названия группы.

вот что я делал:

from django.db import models
from django.contrib.auth.models import Group

class Audit(models.Model):

    @transaction.atomic
    def save(self, *args, **kwargs):
        if not hasattr(self,"reAssessmentTeam"):
            self.reAssessmentTeam, _ = Group.objects.get_or_create(name='_audit_{}_{}'.format(self.project.id,self.name))

        super(Audit, self).save(*args, **kwargs)

    project = models.ForeignKey(Project, related_name = 'audits')
    name = models.CharField(max_length=100)
    reAssessmentTeam = models.OneToOneField(Group)

Я знаю, что это может вызвать проблемы, если имя слишком длинное или кто-то умудряется использовать то же имя, но я позабочусь о них позже.


проверьте мой проект для этого в https://chris-lamb.co.uk/projects/django-auto-one-to-one который может автоматически создавать экземпляры дочерней модели при создании родительского класса.

например, учитывая следующее определение модели:

from django.db import models
from django_auto_one_to_one import AutoOneToOneModel

class Parent(models.Model):
    field_a = models.IntegerField(default=1)

class Child(AutoOneToOneModel(Parent)):
    field_b = models.IntegerField(default=2)

... создание Parent экземпляр автоматически создает соответствующие Child например:

>>> p = Parent.objects.create()
>>> p.child
<Child: parent=assd>
>>> p.child.field_b
2

A PerUserData helper предоставляется для общего случая создания экземпляров, когда User создается экземпляр.