【问题标题】:Django - how to make required to implement field?Django - 如何使需要实现字段?
【发布时间】:2012-10-20 23:30:56
【问题描述】:

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

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    如果可能的话,恐怕没有一种简单的方法可以在不深入研究 Django 的情况下实现这一目标。

    主要原因是 Django 中的Field name "hiding" is not permitted。这意味着如果您想在作为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 的模型继承一起工作。

    【讨论】:

      【解决方案2】:

      你为什么要这样做?什么是公共字段不能在 AbstractModel 中声明的原因?

      如果您真的想这样做,请使用此处的说明: add methods in subclasses within the super class constructor

      【讨论】:

      • 我想为 cmets 做一个抽象类。我希望每个模型在自己的模型上都有自己的 cmets。所以这就是为什么我要创建 1 个抽象类,并要求在每个子模型中创建 ForeignKey 字段。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 2019-10-26
      • 2019-06-11
      • 2018-09-08
      • 2019-08-30
      相关资源
      最近更新 更多