假设您必须对多个类建模,这些类应该具有复合属性,例如尺寸(宽度 和高度)或电话号码(前缀、编号 和扩展名)。
在 Java 中(使用 JPA 2)我会创建一个 Dimensions 类并用 @Embeddable
注释它。这会导致 Dimension 的 字段(例如 width 和 height)被嵌入到声明类型为 Dimensions.
如何在避免代码重复的同时使用 Django 对这些进行建模?创建单独的 Dimensions 模型并使用 ForeignKey
字段引用它没有意义。而且这些类没有足够的共同点来证明模型继承的合理性。
最佳答案
我认为您可能过度考虑了继承。继承是并且实际上是复合模型的推荐方法。以下是如何在 Django 中正确使用模型继承的示例:
class PhoneModelBase(model.Model):
phone = models.CharField(max_length=16)
...
class Meta:
abstract = True
class PhoneModel(PhoneModelBase):
# phone is here without typing it
# the only restriction is that you cannot redefine phone here
# its a Django restriction, not Python restriction
# phone = models.CharField(max_length=12) # <= This will raise exception
pass
所以它所做的是创建一个模型 PhoneModelBase
,但是这里的关键是它使用 class Meta
和 abstract=True
。
这里有更多关于正在发生的事情的幕后故事以及对一些 Python 概念的一些解释。我假设您不知道它们,因为您在问题中提到了 Java。这些 Python 概念实际上是比较困惑的概念,所以我的解释可能不完整,甚至令人困惑,所以如果你不会遵循,请不要介意。您只需要知道使用 abstact = True
。这是官方文档:https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes .
PhoneModelBase
中的 Meta
属性就是一个属性。它与类中的任何其他属性相同,除了它是一个类实例(请记住,在 Python 中,类和函数是一阶成员)。此外,Python 有一个名为 __metaclass__
的东西,您可以将其添加到您的类中。 __metaclass__
定义了一种构建类实例的方式。更多相关信息 here . Django 在创建模型类实例的过程中使用了这些。
所以要创建PhoneModelBase
类,下面是一个大概的轮廓:
- 当
PhoneModelBase
类的实例(类本身,而不是类的实例 -PhoneModelBase()
)被创建时,__metaclass__
由于继承而来自model.Model
接管创建过程 - 在
__metaclass__
中,Python 调用创建实际类实例的函数,并将您尝试创建的类的所有字段传递给它 - PhoneModelBase。这将包括phone
、Meta
和您定义的任何其他字段 - 它看到
Meta
属性,然后开始分析它的属性。根据这些属性的值,Django 会改变模型的行为 - 它看到
abstract
属性,然后更改它试图创建的类的逻辑 -PhoneModelBase
不将它存储在 db 中
然后是 PhoneModelBase
,尽管它的定义看起来与常规模型非常相似,但它不是常规模型。它只是一个抽象类,旨在用作其他模型中的组合。
当其他模型继承自 PhoneModelBase
时,它们的 __metaclass__
将从基础模型中复制属性,就像您手动键入这些属性一样。它不会是任何类似的外键。所有继承的属性都将成为模型的一部分,并将在同一个表中。
希望所有这些都有意义。如果不是,您只需记住将 Meta
类与 abstract = True
一起使用即可。
编辑
如评论中所建议的,您还可以从多个基类继承。因此,您可以拥有 PhoneModelBase
、DimensionsModelBase
,然后您可以从这两个(或更多)继承,所有基类的所有属性都将出现在您的模型。
关于python - Django:复合字段或嵌入式类(如 JPA)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12493568/