Django中不要求参照完整性的ForeignKey?

12 投票
6 回答
8624 浏览
提问于 2025-04-16 03:14

我想在Django模型中设置一个ForeignKey字段,这个字段有时候指向另一张表。但我希望能在这个字段中插入一个ID,这个ID可能指向另一张表中的某个条目,而这个条目不一定存在。所以如果在另一张表中找到了这个条目,我希望能享受到ForeignKey关系带来的所有好处。但如果没有找到,我希望这个字段就仅仅被当作一个数字来处理。

这可能吗?这就是所谓的通用关系吗?

6 个回答

3

这其实很简单,就是声明一个外键(ForeignKey),然后创建这个列,但不把它真正声明为外键。这样的话,如果对象存在,你就可以用 o.obj_id 和 o.obj 来访问它;如果你试图加载一个不存在的对象,系统会抛出一个异常(大概是 DoesNotExist)。

不过,我觉得没有办法让 syncdb 自动帮你做到这一点。我发现 syncdb 的功能有限,甚至有点没用,所以我完全绕过它,自己写代码来创建数据库结构。你可以先用 syncdb 创建数据库,然后直接修改表,比如用 ALTER TABLE tablename DROP CONSTRAINT fk_constraint_name 来去掉外键约束。

当然,这样做的话,你也会失去 ON DELETE CASCADE 和所有的引用完整性检查。

3

我刚开始学习Django,所以不太确定它是否自带你想要的功能。我想到的一个方法是这样的:

from django.db import models

class YourModel(models.Model):
    my_fk = models.PositiveIntegerField()

    def set_fk_obj(self, obj):
        my_fk = obj.id

    def get_fk_obj(self):
        if my_fk == None:
            return None
        try:
            obj = YourFkModel.objects.get(pk = self.my_fk)
            return obj
        except YourFkModel.DoesNotExist:
            return None

我不确定你是否在使用Django自带的管理应用。如果用PositiveIntegerField代替ForeignKey,这样在管理网站上这个字段就会显示为一个文本输入框。

10

这个问题很早以前就有人问过了,但现在对于新手来说,有一种简单的方法可以处理这个问题,就是在你的外键(ForeignKey)上设置 db_constraint=False。

你可以在这里查看相关文档

customer = models.ForeignKey('Customer', db_constraint=False)

或者,如果你希望这个外键可以为空,并且不强制要求引用完整性的话:

customer = models.ForeignKey('Customer', null=True, blank=True, db_constraint=False) 

我们在一些情况下使用这个方法,因为我们无法保证这些关系会按照正确的顺序创建。

编辑:更新了链接

撰写回答