是否可以使用自定义方法/属性覆盖外键关系
Posted
技术标签:
【中文标题】是否可以使用自定义方法/属性覆盖外键关系【英文标题】:is it possible to override a foreign key relation with a custom method/property 【发布时间】:2020-08-09 08:40:42 【问题描述】:上下文
我正在重构一个 Django 2.X 应用程序,尤其是核心模型CoreModel
。有一个包含所有相关表的数据库 (Postgres)。
CoreModel
的实例在此重构后将不再存在于 Postgres 中,它们将存在于 Django 项目范围之外的其他地方,比如一些 AWS No-SQL 数据库服务。
还有几个卫星模型 SateliteModel
到 CoreModel
将继续存在于 Postgres 上,但 CoreModel
目前被建模为外键字段。
class CordeModel(models.Model):
pass
class SatelliteModel(models.Model):
core = models.ForeignKey(CoreModel)
def some_instance_method(self):
return self.core.calculate_stuff() # <- override self.core!
问题
代码中提到了CoreModel
关系,我无法成功解决这个问题。
我的第一个天真的方法是实现 @property
getter 方法,这样我就有足够的灵活性来执行以下操作:
@property
def core(self):
try:
# ORM
return self.core
except CoreNotFound:
# External datastore
return aws_client.fetch_core()
有了这个 sn-p,我对 core
名称有一个循环依赖,所以这个想法就出来了。
我可以重命名外键:但我宁愿不触及数据库架构。毕竟我已经在重构应用程序的核心部分,这是一个非常容易出错的过程。如果没有其他选择,我会这样做。
我可以将@property
字段重命名为current_core
:这样可以避免无限递归部分,但这反过来意味着搜索整个代码库以查找提及关系,而且这是中心模型,这将花费大量时间。
经过几个小时的研究,我开始怀疑为外键字段覆盖 getter 的概念是否可行,我需要它。也许这不是我想要的,这是一个非常不寻常的用例,但需求也非常不寻常。
非常感谢您提供的任何见解。
更新
我忘记添加最重要的信息。
大部分CoreModel
将被 Postgres(历史上的)删除,但CoreModel
s 的一小部分将保留并在一段时间后移动。本质上,只有“活跃的”CoreModel
s 会留在 Postgres,但最终都会被移出,而新的CoreModel
会被创建。
这样就排除了将 ForeignKey 字段更改为整数的可能性。
【问题讨论】:
还需要外键字段吗?从那以后你不能用整数字段替换它吗? @IainShelvington 谢谢你的提问。我在 UPDATE 标题下添加了更多信息。 【参考方案1】:您可以保留但重命名外键,然后使用旧名称添加属性
class SatelliteModel(models.Model):
old_core = models.ForeignKey(CoreModel, null=True, blank=True, on_delete=models.SET_NULL)
@property
def core(self):
try:
return self.old_core
except CoreModel.DoesNotExist:
return aws_client.fetch_core()
这会更改架构中的列名,尽管您可以覆盖列名以防止这种情况发生
old_core = models.ForeignKey(CoreModel, db_column='core_id', null=True, blank=True, on_delete=models.SET_NULL)
也许可以创建一个ForeignKey
的子类,它会按照你的意愿执行,如果这个答案还不够,我可以分享一些想法
【讨论】:
这是否需要创建迁移? @Sebastialonso 几乎任何解决方案都需要您进行迁移,因为SatelliteModel.core
将不再是外键约束?对于 CoreModel
已迁移的实例,获取迁移数据所需的旧 id 以及旧列设置为什么?以上是关于是否可以使用自定义方法/属性覆盖外键关系的主要内容,如果未能解决你的问题,请参考以下文章
在实现自定义ValidationAttribute时,我应该覆盖哪种IsValid方法