Django - 如何使字段成为必填项?

6

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

2个回答

6
我很抱歉,如果可能的话,没有简单的方法可以实现这一点,需要深入了解Django。
主要原因是在Django中不允许Field name "hiding" is not permitted。这意味着,如果您想在基本抽象类中声明一个抽象属性,它是一个Field实例,您将无法像正常的Python类继承范例那样在子类中重写它。引用文档:
在常规的Python类继承中,允许子类覆盖父类的任何属性。但在Django中,对于字段实例(至少目前是这样),不允许这样做。如果一个基类有一个名为“author”的字段,那么您不能在从该基类继承的任何类中创建另一个模型字段名为“author”的字段。
在父模型中覆盖字段会导致一些困难,例如初始化新实例(指定在Model.init中初始化哪个字段)和序列化等领域。这些是正常的Python类继承不必以相同方式处理的特性,因此Django模型继承与Python类继承之间的区别并非是任意的。
此限制仅适用于字段实例属性。如果您希望,可以覆盖普通的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的模型继承中如何工作。

自Django 1.10以来,允许对抽象模型上定义的字段进行“隐藏”。 - Supra621

-2

2
我想为评论制作一个抽象类。我希望每个模型都有自己的评论,对应其自身的模型。因此,我想制作一个抽象类,并要求在每个子模型中制作ForeignKey字段。 - tunarob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接