使用反向字段时自动创建一对一关系
Automatically create One-To-One relation when using reverse field
创建模型的两个实例并使用 OneToOneField 连接它们时,连接会在创建对象时自动创建并保存:
from django.db import models
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)
>>> m2 = MyModel.objects.create(name="2")
>>> m1 = MyModel.objects.create(name="1", next=m2)
>>> m2.prev
<MyModel: 1>
>>> m2.refresh_from_db()
>>> m2.prev
<MyModel: 2>
但是,当创建相同的连接但使用反向字段时,创建也会自动完成,但不会保存。
>>> m1 = MyModel.objects.create(name="1")
>>> m2 = MyModel.objects.create(name="2", prev=m1)
>>> m1.next
<MyModel: 2>
>>> m1.refresh_from_db()
>>> m1.next
请注意,最后一条语句不会打印任何内容,因为它 returns None
如何在使用反向字段创建关系时始终保存关系,而不必每次都手动使用 .save()
?
可能实现此目的的简单方法是使用您认为可行的 pre_save/post_save 信号。但不确定这个答案是否可行,尝试制作一些模组,看看是否可行!
from django.db.models.signals import post_save
from django.dispatch import receiver
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)
@receiver(post_save, sender=MyModel)
def mymodel_post_save(sender, instance, **kwargs):
if hasattr(instance, 'prev'): # if prev exists
# now check if prev is added next
if not instance.prev.next: # if next is not present
instance.prev.next = instance
MyModel.objects.filter(
pk=instance.prev.pk
).update(next=instance)
这是个糟糕的主意。
你会让所有看你代码的人感到困惑。
我什至感到惊讶 MyModel.objects.create
有效而不是抛出无效的关键字参数。我可能会为此打个勾。
当你打电话时:
m2 = MyModel.objects.create(name="2", prev=m1)
为了按预期工作,.create
方法需要在 m1
实例上调用保存,因为 m1
是保存关系的实例(通过 next
)
谁会想到呢?您正在隐藏功能。 PEP 20
的一些引述
Explicit is better than implicit.
There should be one-- and preferably only one --obvious way to do it.
我的建议是将关系更改为:
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
prev = models.OneToOneField('self',
null=True,
blank=True,
related_name='next',
on_delete=models.SET_NULL)
因为,它更有可能在创建时知道 prev
是什么。
创建模型的两个实例并使用 OneToOneField 连接它们时,连接会在创建对象时自动创建并保存:
from django.db import models
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)
>>> m2 = MyModel.objects.create(name="2")
>>> m1 = MyModel.objects.create(name="1", next=m2)
>>> m2.prev
<MyModel: 1>
>>> m2.refresh_from_db()
>>> m2.prev
<MyModel: 2>
但是,当创建相同的连接但使用反向字段时,创建也会自动完成,但不会保存。
>>> m1 = MyModel.objects.create(name="1")
>>> m2 = MyModel.objects.create(name="2", prev=m1)
>>> m1.next
<MyModel: 2>
>>> m1.refresh_from_db()
>>> m1.next
请注意,最后一条语句不会打印任何内容,因为它 returns None
如何在使用反向字段创建关系时始终保存关系,而不必每次都手动使用 .save()
?
可能实现此目的的简单方法是使用您认为可行的 pre_save/post_save 信号。但不确定这个答案是否可行,尝试制作一些模组,看看是否可行!
from django.db.models.signals import post_save
from django.dispatch import receiver
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
next = models.OneToOneField('self', on_delete=models.SET_NULL, related_name='prev', null=True, blank=True)
@receiver(post_save, sender=MyModel)
def mymodel_post_save(sender, instance, **kwargs):
if hasattr(instance, 'prev'): # if prev exists
# now check if prev is added next
if not instance.prev.next: # if next is not present
instance.prev.next = instance
MyModel.objects.filter(
pk=instance.prev.pk
).update(next=instance)
这是个糟糕的主意。
你会让所有看你代码的人感到困惑。
我什至感到惊讶 MyModel.objects.create
有效而不是抛出无效的关键字参数。我可能会为此打个勾。
当你打电话时:
m2 = MyModel.objects.create(name="2", prev=m1)
为了按预期工作,.create
方法需要在 m1
实例上调用保存,因为 m1
是保存关系的实例(通过 next
)
谁会想到呢?您正在隐藏功能。 PEP 20
Explicit is better than implicit.
There should be one-- and preferably only one --obvious way to do it.
我的建议是将关系更改为:
class MyModel(models.Model):
name = models.CharField(primary_key=True, max_length=255)
prev = models.OneToOneField('self',
null=True,
blank=True,
related_name='next',
on_delete=models.SET_NULL)
因为,它更有可能在创建时知道 prev
是什么。