问题描述
class Foo(models.Model):
b = models.CharField(max_length=10)
parent = models.ForeignKey('self',on_delete=models.CASCADE)
这个 Foo.parent 默认值应该是同一个实例。 我的意思是如果用户没有指定父字段,它需要引用正在创建的对象。
我该如何实施?
解决方法
默认情况下您不能引用对象本身。这样做的主要问题之一是,即使您可以设置 item.parent = item
,如果您将其保存到数据库中,item.parent
也会出现问题,因为那时 {{ 1}} 还没有主键。
您可以做的是覆盖 item
的 create(…)
方法,让它处理大部分逻辑。因此我们定义了一个 QuerySet
的子类:
QuerySet
然后在模型中我们使字段可以为空并默认设置为class TreeQuerySet(QuerySet):
def create(self,*args,**kwargs):
item = super().create(*args,**kwargs)
if item.parent is None:
item.parent_id = item.pk
return super().create(*args,**kwargs)
return item
:
None
然后您可以创建这样的 class Foo(models.Model):
b = models.CharField(max_length=10)
parent = models.ForeignKey(
'self',null=True,on_delete=models.CASCADE,default=None
)
objects = TreeQuerySet.as_manager()
对象:
Foo
以不同的方式创建 # no parent specified ↓
Foo.objects.create(b='foobar')
对象是行不通的。
话虽如此,如果不再有父项,您最好将该字段设置为 Foo
,这也将避免陷入无限循环。它还简化了建模,因为 None
可以用作默认值。
您也可以将 None
/NULL
存储在对象中,但使用将引用节点的属性,以防父节点没有其他父节点,例如:
None
然后使用 class Foo(models.Model):
b = models.CharField(max_length=10)
parent = models.ForeignKey(
'self',default=None
)
@property
def parent_or_self(self):
if self.parent is not None:
return self.parent
return self
,尽管我不相信这比仅使用 item.parent_or_self
/None
更好。