django abstract models versus regular inheritance
除了语法之外,使用django抽象模型和对django模型使用纯Python继承有什么区别?利弊?
更新:我认为我的问题被误解了,我收到了对抽象模型和继承自django.db.models.model的类之间差异的响应。实际上,我想知道继承自Django抽象类(meta:abstract=true)的模型类与继承自say"object"(而不是models.model)的纯Python类之间的区别。
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class User(object): first_name = models.CharField(.. def get_username(self): return self.username class User(models.Model): first_name = models.CharField(... def get_username(self): return self.username class Meta: abstract = True class Employee(User): title = models.CharField(... |
I actually want to know the difference between a model class that
inherits from a django abstract class (Meta: abstract = True) and a
plain Python class that inherits from say, 'object' (and not
models.Model).
号
Django只为
1 2 3 4 5 6 7 8 9 10 11 | class User(models.Model): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Meta: abstract = True class Employee(User): title = models.CharField(max_length=255) |
…将导致沿着以下行生成单个表…
1 2 3 4 5 6 7 | CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); |
。
…而后者……
1 2 3 4 5 6 7 8 | class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User): title = models.CharField(max_length=255) |
。
…不会导致生成任何表。
您可以使用多个继承来执行这样的操作…
1 2 3 4 5 6 7 8 | class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User, models.Model): title = models.CharField(max_length=255) |
…这将创建一个表,但它将忽略
1 2 3 4 5 6 | CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); |
。
一个抽象模型为每个子类创建一个具有完整列集的表,而使用"纯"python继承创建一组链接表(又称"多表继承")。考虑您有两个模型的情况:
1 2 3 4 5 6 7 | class Vehicle(models.Model): num_wheels = models.PositiveIntegerField() class Car(Vehicle): make = models.CharField(…) year = models.PositiveIntegerField() |
如果
1 2 | app_car: | id | num_wheels | make | year |
号
但是,如果使用纯python继承,则会有两个表:
1 2 3 4 5 | app_vehicle: | id | num_wheels app_car: | id | vehicle_id | make | model |
其中
现在,Django将以对象形式将其很好地组合在一起,这样您就可以访问
为了解决更新后的问题,从django抽象类继承和从python的
只是想添加一些我在其他答案中没有看到的内容。
与Python类不同的是,模型继承不允许字段名隐藏。
例如,我对一个用例的问题进行了如下的实验:
我从Django的auth permissionMixin继承了一个模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class PermissionsMixin(models.Model): """ A mixin class that adds the fields and methods necessary to support Django's Group and Permission model using the ModelBackend. """ is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_('Designates that this user has all permissions without ' 'explicitly assigning them.')) groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.')) user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, help_text='Specific permissions for this user.') class Meta: abstract = True # ... |
然后我有了我的混音器,除其他外,我想要它覆盖
1 2 3 4 5 6 | class WithManagedGroupMixin(object): groups = models.ManyToManyField(Group, verbose_name=_('groups'), related_name="%(app_label)s_%(class)s", blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.')) |
号
我使用的这两种混音器如下:
1 2 | class Member(PermissionMixin, WithManagedGroupMixin): pass |
所以,是的,我希望这能奏效,但没有。但问题更严重,因为我得到的错误根本没有指向模型,我不知道出了什么问题。
在尝试解决这个问题时,我随机决定更改我的mixin并将其转换为抽象模型mixin。错误更改为:
1 | django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin' |
。
正如您所看到的,这个错误确实解释了正在发生的事情。
在我看来,这是一个巨大的差异:)
主要区别在于如何创建模型的数据库表。如果使用不带
如果将
优缺点取决于应用程序的体系结构。给出以下示例模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Publishable(models.Model): title = models.CharField(...) date = models.DateField(....) class Meta: # abstract = True class BlogEntry(Publishable): text = models.TextField() class Image(Publishable): image = models.ImageField(...) |
。
如果
另请参见Django关于模型继承的文档。
主要区别在于继承用户类的时间。一个版本表现得像一个简单的类,另一个版本表现得像一个django model。
如果继承基本的"对象"版本,那么Employee类将只是一个标准类,而first_name不会成为数据库表的一部分。您不能创建表单,也不能在其中使用任何其他Django功能。
如果继承models.model版本,则Employee类将具有django模型的所有方法,并且它将继承First_Name字段作为可以在表单中使用的数据库字段。
根据文档,抽象模型"提供了一种在Python级别分解公共信息的方法,同时在数据库级别为每个子模型只创建一个数据库表。"