从 ABC 和 django.db.models.Model 继承会引发元类异常



我正在尝试使用Python 3实现一个Django数据模型类,这也是一个接口类。 我这样做的原因是,我正在为我的同事编写一个基类,并且需要他在从我的类派生的所有类中实现三种方法。 我试图给他一种简化的方式来使用我设计的系统的功能。但是,他必须重写一些方法,以便为系统提供足够的信息来执行继承类中的代码。

我知道这是错误的,因为它会抛出异常,但我希望有一个类似于以下示例的类:

from django.db import models
from abc import ABC, abstractmethod
class AlgorithmTemplate(ABC, models.Model):
    name = models.CharField(max_length=32)
    @abstractmethod
    def data_subscriptions(self):
        """
        This method returns a list of topics this class will subscribe to using websockets
        NOTE: This method MUST be overriden!
        
        :rtype: list
        """

我知道我可以避免从ABC类继承,但我想使用它的原因我不会在这里让你感到厌烦。

问题所在


将一个类(如上面的类(包含在我的项目中并运行python manage.py makemigrations后,我收到错误:TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases . 我已经搜索了堆栈溢出,但只找到了如下解决方案:

class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass

我读过以下帖子:

使用ABC,PolymorphicModel,django-models给出了元类冲突

解决元类冲突

我已经尝试了这些解决方案的许多变体,但我仍然得到了可怕的metaclass例外。 帮助我欧比旺克诺比,你是我唯一的希望。 :-)

我有同样的需求并找到了这个。为了清晰和完整,我更改了代码。基本上,您需要一个额外的类,可用于所有模型接口。

import abc
from django.db import models

class AbstractModelMeta(abc.ABCMeta, type(models.Model)):
    pass

class AbstractModel(models.Model, metaclass=AbstractModelMeta):    
    # You may have common fields here.
    class Meta:
        abstract = True
    @abc.abstractmethod
    def must_implement(self):
        pass

class MyModel(AbstractModel):
    code = models.CharField("code", max_length=10, unique=True)
    class Meta:
        app_label = 'my_app'

test = MyModel(code='test')
> TypeError: Can't instantiate abstract class MyModel with abstract methods must_implement

现在,您拥有两全其美的优势。

我找到了一个适合我的解决方案,所以我想我会在这里发布它,以防它帮助其他人。 我决定不从 ABC 类继承,而只是在"抽象"方法(派生类必须实现的方法(中引发异常。 我确实在 Django 文档中找到了有用的信息,描述了使用 Django 数据模型作为抽象基类和多表继承。

Django 数据模型作为抽象基类


引自文档:

当您想要将一些公共信息放入许多其他模型中时,抽象基类非常有用。你编写基类并将 abstract=True 放在 Meta 类中。然后,此模型将不用于创建任何数据库表。相反,当它用作其他模型的基类时,其字段将添加到子类的字段中。

举个例子:

from django.db import models
class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()
    class Meta:
        abstract = True
class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

学生模型将包含三个字段:姓名、年龄和home_group。 CommonInfo 模型不能用作普通的 Django 模型,因为它 是一个抽象基类。它不生成数据库表或 有一个管理器,不能直接实例化或保存。

从抽象基类继承的字段可以使用 另一个字段或值,或使用"无"删除。


使用 Django 数据模型的多表继承


我对"多表继承"的理解是,您可以定义一个数据模型,然后将其用作第二个数据模型的基类。第二个数据模型将继承第一个模型的所有字段,以及它自己的字段。

引自文档:

Django 支持的第二种模型继承类型是当每个 层次结构中的模型本身就是一个模型。每个型号 对应自己的数据库表,可以查询和创建 单独。继承关系引入了 子模型及其每个父模型(通过自动创建的 一对一字段(。例如:

from django.db import models
class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

Place的所有字段也将在餐厅提供, 尽管数据将驻留在不同的数据库表中。所以这些 两者都可能:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

最新更新