【问题标题】:Inheritance model update to its parent model继承模型更新到其父模型
【发布时间】:2019-12-26 20:47:47
【问题描述】:

我需要从另一个模型扩展一个模型。

案例:

core/models.py

class Master(models.Model):
    code = models.CharField(max_length=30, unique=True)
    name = models.CharField(max_length=100, blank=False, null=False)

    class Meta:
        abstract = True

class City(Master):
        zipcode = models.IntegerField()

custom/models.py

from core.models import City
class City(City)
    newfield = models.CharField(max_length=20)

自定义是一个应用程序。

我尝试过代理模型,但这不是我需要的,因为代理模型添加了一个新表。 https://docs.djangoproject.com/en/2.2/topics/db/models/#proxy-models

我需要的是,当我迁移时,将新字段添加到 City。

更多信息。 在核心中创建表,在自定义中您可以添加客户需要的新字段。这个想法是核心仅作为标准维护。

【问题讨论】:

    标签: python django django-inheritance


    【解决方案1】:

    代理模型不添加新表。来自docs link you mentioned

    MyPerson 类与其父 Person 类在同一个数据库表上运行。

    如果您想要一个名为core_city 的表和另一个名为custom_city 的表,而第二个表有一个额外的字段,您只需将其子类化即可。也许使用别名会更容易:

    from core.models import City as CoreCity
    
    class City(CoreCity):
        newfield = models.CharField(max_length=20)
    

    custom_city 将包含来自core_city 的所有字段,外加一个newfield。文档部分Multi-table inheritance 中介绍了其工作原理(和示例)。

    如果您想要一个单个数据库表,那么您应该使用代理模型,但是它们确实不允许您创建新字段。该字段应该在父模型中创建,或者存在于数据库中并且根本不由 Django 迁移处理。

    【讨论】:

    • Master是代理模型,刚刚澄清了。它不能这样工作,因为它创建了一个带有 app 后缀的新表,现在我有两个表 core_City 和 custom_City
    • Master是一个抽象模型; master.City 是一个代理(代理什么?)。听起来 master.City 也应该是抽象的(参见@dani herrera 的回答)。
    • City 不能是抽象的,因为只有在客户端需要添加新行的时候才会被修改。目的是创建一个核心项目,其中包含具有标准化业务逻辑的标准表,并且只有在定制时客户才会添加他需要的内容。
    • 好的,所以坚持我的答案的第二部分,它说“如果你想要的是拥有一个单一的数据库表......”。 Django 无法进行迁移以在代理表中添加字段。您可以手动完成(例如使用migrations.RunSQL()),但您必须维护它。
    • 我已经阅读过它,但问题是如果它没有在模型中声明,我将无法与该字段进行交互。
    【解决方案2】:

    您正在寻找Abstract base classes 模特:

    当您想将一些通用信息放入许多其他模型中时,抽象基类很有用。您编写基类并将 abstract=True 放在 Meta 类中。

    这是基类:

    #core/models.py
    class City(Master):
        zipcode = models.IntegerField()
        class Meta:
            abstract = True   # <--- here the trick
    

    这里是你的模型:

    #custom/models.py
    from core.models import City as CoreCity
    class City(CoreCity):
        newfield = models.CharField(max_length=20)
    

    对于许多用途,这种类型的模型继承将正是您想要的。它提供了一种在 Python 级别分解常见信息的方法,同时仍然在数据库级别仅为每个子模型创建一个数据库表

    【讨论】:

    • 城市不能是抽象表。例如,客户需要一个新行 CityShortName,为此客户需要创建一个新应用并在那里进行自定义。
    • 可能在同一个应用程序中,abstract_models.pymodels.py。我在这里做:github.com/ctrl-alt-d/django-aula/tree/master/aula/apps/aules
    • Dani,在核心中创建了表格,在自定义中您可以添加客户需要的新字段。这个想法是核心仅作为标准维护。
    • 与我在示例中所做的相同,但有 2 个应用程序而不是一个。我所做的是以pass 作为模型主体编写自定义架构。
    • 城市不能是抽象的。
    【解决方案3】:

    您可以在这样定义之后更新或创建您的类常量

    from core.models import City    
    
    City.newfield = models.CharField(max_length=20)
    

    【讨论】:

    • 我试过了,但是 makemigrations 没有检测到变化
    【解决方案4】:

    您可能需要使用可交换模型,使用它们您可以定义一个 City 类并使用以后需要的任何模型对其进行更改, 但是这样您就不能直接导入和使用基础 City 模型,您可能需要为此提供一个类似 get_city_model 的方法,作为您的公共 API。

    class City(Master):
        zipcode = models.IntegerField()
    
        class Meta:
            swappable = 'CORE_CITY_MODEL'
    

    也许稍后用其他模型替换它,然后以“app_name.model_name”的形式将 CORE_CITY_MODEL 设置为该模型。

    django.contrib.auth 就是一个很好的例子,你可以考虑检查User 模型和get_user_model 方法。虽然我认为如果您在运行 migrate 后更改城市模型可能会遇到问题,但它可能不会将您的数据移动到新表中,但我不确定这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多