models.ForeignKey 是否接受自身的实例作为默认值?

问题描述

我有一个与自身具有多对一关系的模型:

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}} 还没有主键。

您可以做的是覆盖 itemcreate(…) 方法,让它处理大部分逻辑。因此我们定义了一个 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 更好。