我正在尝试使用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
。我搜索过Stack Overflow,但只找到类似下面的解决方案:
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
我已阅读以下帖子:
Using ABC, PolymorphicModel, django-models gives metaclass conflict
我已尝试过这些解决方案的许多变体,但我仍然遇到可怕的metaclass
异常。帮助我欧比旺克诺比,你是我唯一的希望。 : - )
答案 0 :(得分:3)
我有同样的需求并找到了 this。为了清晰和完整,我修改了代码。基本上,您需要一个额外的类,您可以将其用于所有模型接口。
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
现在您拥有两全其美的优势。
答案 1 :(得分:1)
我找到了一个适合我的解决方案,所以我想在这里发布它以防万一。我决定不继承ABC
类,而只是在" abstract"中引发异常。方法(派生类必须实现的方法)。我确实在Django文档中找到了有用的信息,描述了将Django数据模型用作抽象基类以及多表继承。
引自the docs:
当您想要将一些公共信息放入许多其他模型时,抽象基类非常有用。编写基类并在Meta类中放置abstract = True。然后,此模型不会用于创建任何数据库表。相反,当它被用作其他模型的基类时,它的字段将被添加到子类的字段中。
一个例子:
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模型,因为它 是一个抽象的基类。它不会生成数据库表或 有经理,无法直接实例化或保存。
从抽象基类继承的字段可以被覆盖 另一个字段或值,或者使用None删除。
我对"多表继承的理解"是,您可以定义数据模型,然后将其用作第二个数据模型的基类。第二个数据模型将继承第一个模型中的所有字段以及它自己的字段。
引自the docs:
Django支持的第二种模型继承是每种类型 层次结构中的模型本身就是一个模型。每个型号 对应于自己的数据库表,可以查询和创建 个别。继承关系引入了之间的联系 儿童模型及其每个父母(通过自动创建 OneToOneField)。例如:
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")