我正在尝试使用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")