Python 在Django中创建模型时自动创建相关对象
我是Django的新手,请原谅我的无知:) 假设我有一个具有两个外键关系的模型,当我创建该模型的实例时,我希望它也自动为外键对象生成新实例。在本例中,我将课程注册建模为一个组,并将特定组作为模型上的外键引用Python 在Django中创建模型时自动创建相关对象,python,django,django-models,Python,Django,Django Models,我是Django的新手,请原谅我的无知:) 假设我有一个具有两个外键关系的模型,当我创建该模型的实例时,我希望它也自动为外键对象生成新实例。在本例中,我将课程注册建模为一个组,并将特定组作为模型上的外键引用 class Course(models.Model): student_group = models.OneToOneField(Group, related_name="course_taken") teacher_group = models.OneToOneField(
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提供了更好的方法吗?您可以使用信号来处理这种情况:
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')
最终我决定:
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/01):@Shasanoglu是正确的,由于id不存在,上述代码实际上不起作用。您必须在调用save之后创建相关对象(因此,您可以调用super.save,创建相关对象,更新此对象,然后再次调用super.save,这并不理想。否则,您可以从组名中省略id,这样就可以了)。但最终,我将自动相关对象创建完全移出了模型。我在自定义表单的save方法中完成了这一切,该方法更加简洁,并放弃了在管理界面中使用该模型(这就是为什么我坚持首先在model方法中完成所有这一切)我在Django 1.7中的一个类似问题中使用了wjin的解决方案。我只需要做两个改变:
commit\u
使用atomic
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)
我知道,如果名称太长或有人设法使用相同的名称,这可能会导致问题,但我稍后会处理这些问题。请查看我的项目,在该项目中,可以在创建父类时自动创建子模型实例 例如,给定以下模型定义:
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)
。。。创建父实例会自动创建相关的
Child
实例:
>>> p = Parent.objects.create()
>>> p.child
<Child: parent=assd>
>>> p.child.field_b
2
p=Parent.objects.create()
>>>p.儿童
>>>p.child.field_b
2.
为创建
用户
实例时创建实例的常见情况提供了PerUserData
帮助程序。调用实例.save的可能重复将触发另一个post\u save信号,该信号将再次调用函数?我认为这也要求字段可为空。对于已创建的对象,created
关键字被设置为True,并且由于回调在db save之后运行,因此该对象已经创建。您可以将代码移动到pre_save
,但必须使用try:except:
子句来检查组和处理异常。由于您创建的组与课程是一体的,因此我认为在post_save中根本不需要进行检查。我最终在pre_save中进行了验证,并启用了事务中间件将每个请求包装在单个事务中,因为我不想使字段为空。但您的回答在其他方面是有帮助的。我认为,当您想要确保保存过程的原子性时,这种方法效果很差。您可以将保存
包装到原子
装饰器中,但它有两个问题。首先,原子的
装饰器存在的原因并不明显。第二,当您有另一个信号处理程序时,例如发送电子邮件,如果该处理程序引发异常,您的整个事务将回滚,这可能不是您想要的。我有一个类似的问题,我正在尝试用表单解决它。你能链接到你的表格答案吗?我知道这是4年前的事了,但也许你有一些答案。AttributeError:“module”对象没有属性“commit\u on\u success”