Django:复合字段或嵌入式类(例如JPA)?

rlu*_*uba 3 python django django-models

假设您必须对几个类进行建模,这些类应该具有复合属性,例如尺寸widthheight)或电话号码prefixnumberextension)。

在Java中(使用JPA 2),我将创建一个Dimensions类并使用对其进行注释@Embeddable。这导致Dimension的字段(例如widthheight)被嵌入到每个声明了Dimensions类型的属性的类中。

在避免代码重复的同时,如何使用Django建模?创建一个单独的Dimensions模型并用一个ForeignKey字段引用它是没有意义的。而且这些类没有足够的共同点来证明模型继承的合理性。

mik*_*725 5

我认为您可能对继承问题考虑过多。实际上,继承是组合模型的推荐方法。以下是在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
Run Code Online (Sandbox Code Playgroud)

因此,它要做的就是创建一个模型PhoneModelBase,但是这里的关键是它class Meta与with一起使用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__定义了如何构建类实例的方法。更多关于这里。Django在创建模型类实例的过程中使用了它们。

因此,要创建PhoneModelBase该类,下面是一个粗略的概述:

  • 在创建PhoneModelBase类的实例(类本身,而不是class的实例PhoneModelBase())时,由于继承__metaclass__而来的model.Model继承了创建过程
  • 在内__metaclass__,Python调用该函数,该函数创建实际的类实例,并将您尝试创建的类的所有字段(PhoneModelBase)传递给它。这将包括phoneMeta和您定义的任何其他领域
  • 它看到该Meta属性,然后开始分析其属性。根据这些属性的值,Django将更改模型的行为
  • 它看到该abstract属性,然后更改其尝试创建的类的逻辑- PhoneModelBase通过不将其存储在db中

因此PhoneModelBase,尽管的定义看起来与常规模型非常相似,但它不是常规模型。它只是一个抽象类,可以在其他模型中用作组合。

当其他模型继承自时PhoneModelBase,它们__metaclass__将复制基本模型中的属性,就像您手动键入这些属性一样。那样的话它不是外键。所有继承的属性都将成为模型的一部分,并将位于同一表中。

希望所有这些都有意义。如果不是这样,您只需要记住将Metaclass与一起使用即可abstract = True

编辑

如注释中所建议,您还可以从多个基类继承。因此,您可以具有PhoneModelBase,,DimensionsModelBase然后可以从这两个(或多个)中继承,并且所有基类的所有属性都将出现在模型中。