是否可以使用自定义方法/属性覆盖外键关系

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 数据库服务。

还有几个卫星模型 SateliteModelCoreModel 将继续存在于 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(历史上的)删除,但CoreModels 的一小部分将保留并在一段时间后移动。本质上,只有“活跃的”CoreModels 会留在 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 以及旧列设置为什么?

以上是关于是否可以使用自定义方法/属性覆盖外键关系的主要内容,如果未能解决你的问题,请参考以下文章

Django覆盖模型get()方法不适用于外键

无法使用自定义类返回类型覆盖方法

在实现自定义ValidationAttribute时,我应该覆盖哪种IsValid方法

是否有办法在春季为自定义依赖项找出application.properties文件的属性名?

MyBatis注解开发---实现自定义映射关系和关联查询

七,Kotlin常见高阶函数用法