15

我是 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')

似乎我可以使用模型的 clean 方法来执行此操作,但我希望能够将整个事情包装在一个事务中,这样如果它稍后无法创建课程,它就赢了'不创建相关的组对象。有什么办法可以做到这一点?

另外,我在这里做错了吗?Django 是否提供了更好的方法来做到这一点?

4

4 回答 4

10

您可以使用models.signals.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')
于 2013-09-22T13:52:40.003 回答
7

最终我决定:

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)

编辑(2014 年 12 月 1 日):@Shasanoglu 是正确的,由于 id 尚不存在,上述代码并不能真正工作。您必须在调用 save创建相关对象(因此您调用 super.save,创建相关对象,更新此对象并再次调用 super.save - 不理想。或者您从组名称中省略 id,它是美好的)。但最终,我将自动相关对象的创建完全移出模型。我在一个更简洁的自定义表单的保存方法中完成了这一切,并放弃了在管理界面中使用这个模型(这就是为什么我坚持首先在模型方法中做所有这些)

于 2013-09-29T20:56:04.913 回答
1

我在 Django 1.7 中的一个类似问题中使用了 wjin 的解决方案。我只需要进行 2 处更改:

  1. 不得不commit_on_success改变atomic
  2. self.id不起作用,因为代码在创建新对象时设置 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)

我知道如果名称太长或有人设法使用相同的名称,这可能会导致问题,但我稍后会处理这些问题。

于 2014-10-13T19:47:11.763 回答
1

在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

PerUserData为创建实例时创建实例的常见情况提供了帮助程序User

于 2015-10-05T07:31:14.190 回答