我正在为大约 10 个模型构建一些抽象模型。我需要以某种方式使 1 字段未在抽象模型中声明,但必须在继承模型中声明。怎么做?有什么方法可以使用NotImplementedError
吗?
2 回答
如果可能的话,恐怕没有一种简单的方法可以实现这一目标,而无需深入研究 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 的模型继承一起工作。
你为什么要这么做??哪些是无法在 AbstractModel 中声明公共字段的原因?
如果您真的想这样做,请使用此处的说明: 在超类构造函数中的子类中添加方法