是否可以用自定义 method/property 覆盖外键关系
is it possible to override a foreign key relation with a custom method/property
上下文
我正在重构 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()
有了这个代码片段,我对 core
名称产生了循环依赖,所以这个想法已经过时了。
我可以重命名外键:但我宁愿不触及数据库架构。毕竟我已经重构了应用程序的核心部分,这是一个非常容易出错的过程。如果没有其他选择,我会这样做。
我可以将 @property
字段重命名为 current_core
之类的名称:这样我就避免了无限递归部分,但这反过来又意味着一项非常艰巨的任务在整个代码库中搜索关系的提及,这是中心模型,这将花费大量时间。
经过几个小时的研究,我开始怀疑是否可以为外键字段覆盖 getter 的概念,因为我需要它。也许这不是我要找的,这是一个非常不寻常的用例,但要求也很不寻常。
非常感谢您提供的任何见解。
更新
我忘了添加最重要的信息。
大多数 CoreModel
将被删除用于 Postgres(历史的),但 CoreModel
的一小部分将保留并在一段时间后移动。本质上,只有 "active" CoreModel
会保留在 Postgres 中,但最终会全部移出,同时会创建新的 CoreModel
。
这样就排除了将 ForeignKey 字段更改为整数的可能性。
您可以保留但重命名外键,然后使用旧名称添加 属性
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
的子类,它会按照您的意愿执行,如果这个答案还不够,我可以分享一些想法
上下文
我正在重构 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()
有了这个代码片段,我对 core
名称产生了循环依赖,所以这个想法已经过时了。
我可以重命名外键:但我宁愿不触及数据库架构。毕竟我已经重构了应用程序的核心部分,这是一个非常容易出错的过程。如果没有其他选择,我会这样做。
我可以将
@property
字段重命名为current_core
之类的名称:这样我就避免了无限递归部分,但这反过来又意味着一项非常艰巨的任务在整个代码库中搜索关系的提及,这是中心模型,这将花费大量时间。
经过几个小时的研究,我开始怀疑是否可以为外键字段覆盖 getter 的概念,因为我需要它。也许这不是我要找的,这是一个非常不寻常的用例,但要求也很不寻常。
非常感谢您提供的任何见解。
更新
我忘了添加最重要的信息。
大多数 CoreModel
将被删除用于 Postgres(历史的),但 CoreModel
的一小部分将保留并在一段时间后移动。本质上,只有 "active" CoreModel
会保留在 Postgres 中,但最终会全部移出,同时会创建新的 CoreModel
。
这样就排除了将 ForeignKey 字段更改为整数的可能性。
您可以保留但重命名外键,然后使用旧名称添加 属性
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
的子类,它会按照您的意愿执行,如果这个答案还不够,我可以分享一些想法