Django ForeignKey 到一个可能不存在的模型

问题描述 投票:0回答:1

我想将 app1 中的外键设置为 app2 的模型,该模型是可选依赖项。为了实现松散耦合,我希望 app1 即使没有安装 app2 也能正常工作,只需停用该外键即可。

举个例子:

# app1/models.py
class model1(models.Model):
    optional_field = models.ForeignKey(
        "app2.model2", null=True, blank=True, on_delete=models.SET_NULL
    )

如果没有安装 app2,上面会引发以下异常:

app1.model1: (fields.E307) The field model1.optional_field was 
declared with a lazy reference to 'app2.model2', but app 'app2' 
isn't installed.

有没有办法声明一个即使没有安装 app2 也能工作的外键?

django
1个回答
0
投票

是的。您已经有了关键要求,即 ForeignKey 字段可以为 null。

如果您不为其分配任何内容,它将被初始化并存储为 None/null。所以你的代码应该相当干净。如果安装了可选的东西,在保存新的 app1 模型实例之前,执行代码将此字段初始化为 app2 模型实例。如果没有,它应该不需要做任何特别的事情就可以正常工作。

同样,处理 app1 实例的代码必须测试是否

instance.optional_field is None
如果是,则不对链接数据做任何事情。

只有你能判断这是不是个好主意。我想不出有什么理由说它不好。

根据评论更新

有两种方法可以处理根本不存在的 app2 模型。

我要做的是创建一个 app2“存根”,除了模型定义之外什么都没有。这将导致创建一个数据库表,但它不会包含任何数据行。我不知道以后安装实际的app2有什么影响。

另一个是不在 app1 模型上创建字段,除非作为 app2 安装的一部分(迁移,创建字段并创建一个充满空值的列)。然后你可以用一个属性来填补“洞”:

class model1(models.Model):

    # defined only if app2 is installed
    #internal_optional_field = models.ForeignKey(
    #    "app2.model2", null=True, blank=True,
    #     on_delete=models.SET_NULL,
    #     # DO NOT ACCESS EXCEPT THROUGH optional_field property
    #)  
    
    ...
    @property
    def optional_field(self):
        if not hasattr( self, 'internal_optional_field'):
            return None
        return self.internal_optional_field
    @optional_field.setter( self, value):
        assert hasattr( self, 'internal_optional_field'),
            'Trying to set optional_field, but app2 is not installed'
        self.internal_optional_field = value

你可以让它

_internal_optional_field
符合 Python 的约定,以表明它是那些不完全理解它的人应该留下的东西。

警告 - 我从未尝试过这个。它应该可以工作,但要对可选型号进行大量的试用安装和卸载!

© www.soinside.com 2019 - 2024. All rights reserved.