【问题标题】:How to dynamically make an existing non-abstract django model, abstract?如何动态地使现有的非抽象 django 模型抽象化?
【发布时间】:2017-03-15 12:39:45
【问题描述】:

我想我有一个或多或少的非正统和骇人听闻的问题要问你。我目前拥有的是具有多个应用程序的 django 项目。 我想使用一个应用程序的non-abstract model (ModelA) (app1) 并通过子类化它在另一个应用程序 (app2) 中使用它。 App1的模型 不应该迁移到数据库,我只想通过扩展其功能和逻辑来使用 app1 及其模型类的功能。 我通过将这两个应用程序添加到 settings.INSTALLED_APPS 并阻止将 app1 的模型迁移到数据库来实现这一点。

INSTALLED_APPS += (
    'App1',
    'App2',
)

# This is needed to just use App1's models
# without creating it's database tables
# See: http://stackoverflow.com/a/35921487/1230358
MIGRATION_MODULES = {
    'App1': None,
}

到目前为止,一切都很好,丑陋和骇人听闻,我知道...剩下的问题是现在 app1 的大多数模型都是非抽象的 (ModelA),如果我尝试 为了对它们进行子类化,ModelA 的所有字段都不会填充到数据库中名为app2_modelb 的表中。这对我来说很清楚,因为我排除了 App1 迁移到数据库,因此数据库中完全缺少表 app1_modela。

我现在的想法是克隆 ModelA,保留其所有功能,并将其元信息从非抽象更改为抽象 (ModelB.Meta.abstract = True)。 我希望通过这种方式,ModelA的所有原始字段都将继承给ModelB,并且可以在其各自的DB表和列中找到(app1_modelb)。

我现在拥有的是:

# In app1 -> models.py
class ModelA(models.Model):
    title = models.CharField(_('title'), max_length=255)
    subtitle =  models.CharField(_('subtitle'), max_length=255)

    class Meta:
        abstract = False # just explicitly for demonstration


# In app2 -> models.py
from app1.models import ModelA

class ModelB(ModelA):
    pass
    # Just extending ModelAdoes not create the fields title and subtitle fields in app2_modelb
    # because ModelA.meta.abstract = False

我目前使现有非抽象模型抽象的方式(伪代码)如下所示:

# In app2 -> models.py
from app1.models import ModelA

def get_abstract_class(cls):
    o = dict(cls.__dict__)
    o['_meta'].abstract = True
    o['_meta'].app_label = 'app2'
    o['__module__'] = 'app2.models'

    #return type('Abstract{}'.format(cls.__name__), cls.__bases__, o)
    return type('Abstract{}'.format(cls.__name__), (cls,), o)

ModelB = get_abstract_class(ModelA)

class ModelC(ModelB):
    # title and subtitle are inherited from ModelA
    description = models.CharField(_('description'), max_length=255)

这不起作用,经过冗长的描述,我的(简单)问题是,是否以及如何克隆保留其所有功能的非抽象模型类以及如何将其更改为抽象?

只是为了清楚。所有上面的模糊都是关于,我无法更改 app1 中的任何代码。可能app1是通过pip安装的django应用。

【问题讨论】:

  • 您是否打算禁止某人创建 ModelA 的实例?由于无论如何您都在走 hacky 路线,因此如果模型保存方法是调用它的 ModelA 类,您总是会在模型保存方法中引发错误...
  • 您会添加任何新字段吗?
  • 意图如下。假设我想重用 django-blog 应用程序的一些模型(app1 和 ModelA),我发现它们对我的物品(app2)非常有用。遗憾的是 app1.model.ModelA 不是抽象的,因为在 django-blog 应用程序中,它不需要是抽象的,因为在 app1 内部它是一个最终模型类。如果我想在我的应用程序 (app2) 中使用它,它必须是抽象的,以便我可以对它进行子类化,并且在表 (app2_modelb) 中生成所有字段(也是 ModelA 的字段)。总而言之,它是关于重用原本不打算重用的非抽象模型。
  • @SardorbekImomaliev,没有字段更改。模型应该保持不变,但要抽象。
  • @SardorbekImomaliev,很抱歉造成误解!我必须向子类添加字段。应该像最后一个代码块中的 ModelC。

标签: python django django-models


【解决方案1】:

为什么不呢,在 app1 中

AbstractBaseModelA(models.Model):
    # other stuff here
    class Meta:
        is_abstract=True


ModelA(AbstractBaseModelA):
    # stuff

在 app2 中:

MobelB(AbstractBaseModelA):
    # stuff

对不起,如果我误解了你的目标,但我认为上述应该达到相同的最终结果。

【讨论】:

  • 或者issubclass(ModelB, ModelA)重要吗?
  • 我无法更改app1中的任何代码,认为app1是通过pip安装的django应用程序。对不起,我把这个不清楚!
  • 我不确定这是哲学还是编程,但如果是后者:它是开源的,所以你可以改变它。可能有一个 git 或类似的源存储库,您可以从中分叉并创建一个补丁。另一个问题是这是否明智。对于像这样不太可能破坏 app1 的更改,它可能是可以接受的。如果你能说服“上游”开发人员模型应该是抽象的,那就更好了,因为你认为有用的东西,许多其他人也可能同样如此。在这种情况下,他们可能会将您的想法纳入下一个版本。
  • 真实的话@nigel。通常我不喜欢那种骇人听闻的方式,但我很好奇我是否错过了一个可能使之成为可能的简单技巧。
猜你喜欢
  • 2015-08-01
  • 1970-01-01
  • 2018-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-10
  • 2016-12-05
相关资源
最近更新 更多