我想将 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 也能工作的外键?
是的。您已经有了关键要求,即 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 的约定,以表明它是那些不完全理解它的人应该留下的东西。
警告 - 我从未尝试过这个。它应该可以工作,但要对可选型号进行大量的试用安装和卸载!