4

我正在为大约 10 个模型构建一些抽象模型。我需要以某种方式使 1 字段未在抽象模型中声明,但必须在继承模型中声明。怎么做?有什么方法可以使用NotImplementedError吗?

4

2 回答 2

5

如果可能的话,恐怕没有一种简单的方法可以实现这一目标,而无需深入研究 Django。

主要原因是Django 中Field不允许名称“隐藏” 。这意味着如果你想在作为Field实例的基础抽象类中声明一个抽象属性,你将无法在子类中重写它,这与正常的 Python 类继承范式相反。引用文档:

在正常的 Python 类继承中,允许子类覆盖父类的任何属性。在 Django 中,这对于作为 Field 实例的属性是不允许的(至少目前不允许)。如果基类有一个名为 author 的字段,则不能在从该基类继承的任何类中创建另一个名为 author 的模型字段。

覆盖父模型中的字段会导致在初始化新实例(指定在 Model.init 中初始化哪个字段)和序列化等领域出现困难。这些是普通 Python 类继承不必以完全相同的方式处理的特性,因此 Django 模型继承和 Python 类继承之间的区别不是任意的。

此限制仅适用于作为 Field 实例的属性。如果您愿意,可以覆盖普通的 Python 属性。它也仅适用于 Python 看到的属性名称:如果您手动指定数据库列名,则可以在子模型和祖先模型中出现相同的列名以进行多表继承(它们是列在两个不同的数据库表中)。

如果您覆盖任何祖先模型中的任何模型字段,Django 将引发 FieldError。

但是,如果属性不是实例(尽管可能性很小),您将能够通过使用装饰器Field来实现您想要的。@property像这样的东西应该工作:

class Person(models.Model):
    def __init__(self, *args, **kwargs):
        super(Person, self).__init__(*args, **kwargs)
        self.last_name

    first_name = models.CharField(max_length=30)

    @property
    def last_name(self):
        raise NotImplementedError

    class Meta:
        abstract = True

class Student(Person):
    home_group = models.CharField(max_length=5)
    last_name = "Doe"  # "models.CharField()" will not work!

class BadStudent(Person):
    home_group = models.CharField(max_length=5)
    # "NotImplmentedError" will be raised when instantiating BadStudent()

您可能还想看看abc.abstractproperty. 我不确定它如何与 Django 的模型继承一起工作。

于 2012-10-20T23:54:07.847 回答
-2

你为什么要这么做??哪些是无法在 AbstractModel 中声明公共字段的原因?

如果您真的想这样做,请使用此处的说明: 在超类构造函数中的子类中添加方法

于 2012-10-21T01:07:23.097 回答