假设您必须为几个应具有复合属性的类建模,例如维度(宽度和高度)或电话号码< / em>(前缀,数字和扩展名)。
在Java中(使用JPA 2)我将创建一个 Dimensions 类,并使用@Embeddable
对其进行注释。这会导致 Dimension的字段(例如 width 和 height )嵌入到声明属性为 Dimensions
如何使用Django对这些进行建模,同时避免代码重复?创建单独的维度模型并使用ForeignKey
字段引用它是没有意义的。并且这些类没有足够的共同点来证明模型继承的合理性。
答案 0 :(得分:4)
我认为你可能会过度思考继承。继承是并且实际上是复合模型的推荐方法。以下是如何在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。
Meta
中的 PhoneModelBase
属性就是属性。它与类中的任何其他属性相同,除了它是一个类实例(请记住,在Python类和函数中是一阶成员)。另外,Python有一个名为__metaclass__
的东西,你可以添加到你的类中。 __metaclass__
定义了如何构建类实例的方法。更多关于here的信息。 Django在创建模型类实例的过程中使用了这些。
因此,要创建PhoneModelBase
类,以下是粗略概述:
PhoneModelBase
类的实例(类本身,而不是类的实例 - PhoneModelBase()
)时,来自__metaclass__
的{{1}}由于继承接管创建过程model.Model
中,Python调用创建实际类实例的函数,并将您尝试创建的类中的所有字段传递给它 - PhoneModelBase。这将包括__metaclass__
,phone
以及您定义的任何其他字段Meta
属性,然后开始分析其属性。根据这些属性的值,Django将改变模型的行为Meta
属性,然后通过不将其存储在db abstract
那么PhoneModelBase
,即使它的定义看起来非常类似于常规模型,它也不是常规模型。它只是一个抽象类,可以在其他模型中用作复合类。
当其他模型继承自PhoneModelBase
时,他们的PhoneModelBase
将复制基本模型中的属性,就像您手动键入这些属性一样。对于这样的事情,它不会是外键。所有继承的属性都将成为模型的一部分,并且将位于同一个表中。
希望所有这一切都有道理。如果没有,您只需将__metaclass__
类与Meta
一起使用即可。
修改强>
正如评论中所建议的那样,您也可以从多个基类继承。因此,您可以拥有abstract = True
,PhoneModelBase
,然后您可以继承这两个(或更多),并且所有基类的所有属性都将出现在您的模型中。