Python Django 抽象模型与常规继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16655097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
django abstract models versus regular inheritance
提问by rpq
Besides the syntax, what's the difference between using a django abstract model and using plain Python inheritance with django models? Pros and cons?
除了语法之外,使用 django 抽象模型和使用带有 django 模型的纯 Python 继承有什么区别?利弊?
UPDATE: I think my question was misunderstood and I received responses for the difference between an abstract model and a class that inherits from django.db.models.Model. 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.db.models.Model 继承的类之间差异的答复。 我实际上想知道从 django 抽象类 (Meta: abstract = True) 继承的模型类和从“object”(而不是 models.Model)继承的普通 Python 类之间的区别。
Here is an example:
下面是一个例子:
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(...
采纳答案by Aya
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 抽象类 (Meta: abstract = True) 继承的模型类和从“object”(而不是 models.Model)继承的普通 Python 类之间的区别。
Django will only generate tables for subclasses of models.Model, so the former...
Django 只会为 的子类生成表models.Model,所以前者...
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)
...will cause a single table to be generated, along the lines of...
...将导致生成一个表,沿着...
CREATE TABLE myapp_employee
(
id INT NOT NULL AUTO_INCREMENT,
first_name VARCHAR(255) NOT NULL,
title VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
...whereas the latter...
……而后者……
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)
...won't cause any tables to be generated.
...不会导致生成任何表。
You could use multiple inheritance to do something like this...
你可以使用多重继承来做这样的事情......
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)
...which would create a table, but it will ignore the fields defined in the Userclass, so you'll end up with a table like this...
...这将创建一个表,但它会忽略User类中定义的字段,所以你最终会得到一个这样的表......
CREATE TABLE myapp_employee
(
id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
回答by mipadi
An abstract model creates a table with the entire set of columns for each subchild, whereas using "plain" Python inheritance creates a set of linked tables (aka "multi-table inheritance"). Consider the case in which you have two models:
抽象模型为每个子子项创建一个包含整个列集的表,而使用“普通”Python 继承创建一组链接表(又名“多表继承”)。考虑您有两个模型的情况:
class Vehicle(models.Model):
num_wheels = models.PositiveIntegerField()
class Car(Vehicle):
make = models.CharField(…)
year = models.PositiveIntegerField()
If Vehicleis an abstract model, you'll have a single table:
如果Vehicle是抽象模型,您将拥有一个表:
app_car:
| id | num_wheels | make | year
However, if you use plain Python inheritance, you'll have two tables:
但是,如果您使用纯 Python 继承,您将有两个表:
app_vehicle:
| id | num_wheels
app_car:
| id | vehicle_id | make | model
Where vehicle_idis a link to a row in app_vehiclethat would also have the number of wheels for the car.
到哪vehicle_id一行的链接app_vehicle也将包含汽车的轮子数量。
Now, Django will put this together nicely in object form so you can access num_wheelsas an attribute on Car, but the underlying representation in the database will be different.
现在,Django 将把它很好地以对象形式组合在一起,以便您可以num_wheels作为属性访问Car,但数据库中的底层表示将有所不同。
Update
更新
To address your updated question, the difference between inheriting from a Django abstract class and inheriting from Python's objectis that the former is treated as a database object (so tables for it are synced to the database) and it has the behavior of a Model. Inheriting from a plain Python objectgives the class (and its subclasses) none of those qualities.
为了解决您更新的问题,从 Django 抽象类继承和从 Python 继承之间的区别在于object前者被视为数据库对象(因此它的表同步到数据库)并且它具有Model. 从一个普通的 Python 继承而来object,类(及其子类)没有这些品质。
回答by Bernhard Vallant
The main difference is how the databases tables for the models are created.
If you use inheritance without abstract = TrueDjango will create a separate table for both the parent and the child model which hold the fields defined in each model.
主要区别在于模型的数据库表是如何创建的。如果您在没有abstract = TrueDjango 的情况下使用继承,将为父模型和子模型创建一个单独的表,其中包含每个模型中定义的字段。
If you use abstract = Truefor the base class Django will only create a table for the classes that inherit from the base class - no matter if the fields are defined in the base class or the inheriting class.
如果你使用abstract = True基类,Django 只会为从基类继承的类创建一个表——无论字段是在基类还是继承类中定义的。
Pros and cons depend on the architecture of your application. Given the following example models:
优缺点取决于应用程序的架构。给出以下示例模型:
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(...)
If the Publishableclass is not abstract Django will create a table for publishables with the columns titleand dateand separate tables for BlogEntryand Image. The advantage of this solution would be that you are able to query across allpublishables for fields defined in the base model, no matter if they are blog entries or images. But therefore Django will have to do joins if you e.g. do queries for images...
If making Publishableabstract = TrueDjango will not create a table for Publishable, but only for blog entries and images, containing all fields (also the inherited ones). This would be handy because no joins would be needed to an operation such as get.
如果Publishable该类不是抽象的Django会创建一个表与列publishablestitle与date和单独的表BlogEntry和Image。此解决方案的优点是您可以在所有可发布内容中查询基本模型中定义的字段,无论它们是博客条目还是图像。但是因此,如果您例如对图像进行查询,Django 将不得不进行连接...如果使Publishableabstract = TrueDjango 不会为Publishable,而是仅为博客条目和图像创建一个表,包含所有字段(也是继承的字段)。这会很方便,因为不需要连接到诸如 get 之类的操作。
Also see Django's documentation on model inheritance.
另请参阅Django 关于模型继承的文档。
回答by Brent Washburne
The main difference is when you inherit the User class. One version will behave like a simple class, and the other will behave like a Django modeel.
主要区别在于您何时继承 User 类。一个版本的行为就像一个简单的类,另一个版本的行为就像一个 Django 模型。
If you inherit the base "object" version, your Employee class will just be a standard class, and first_name won't become part of a database table. You can't create a form or use any other Django features with it.
如果您继承基本的“对象”版本,您的 Employee 类将只是一个标准类,而 first_name 不会成为数据库表的一部分。您不能创建表单或使用任何其他 Django 功能。
If you inherit the models.Model version, your Employee class will have all the methods of a Django Model, and it will inherit the first_name field as a database field that can be used in a form.
如果您继承 models.Model 版本,您的 Employee 类将拥有 Django Model 的所有方法,并且它将继承 first_name 字段作为可以在表单中使用的数据库字段。
According to the documentation, an Abstract Model"provides a way to factor out common information at the Python level, whilst still only creating one database table per child model at the database level."
根据文档,抽象模型“提供了一种在 Python 级别提取公共信息的方法,同时仍然只在数据库级别为每个子模型创建一个数据库表。”
回答by Adrián
Just wanted to add something which I haven't seen in other answers.
只是想添加一些我在其他答案中没有看到的东西。
Unlike with python classes, field name hiding is not permitedwith model inheritance.
与 python 类不同,模型继承不允许隐藏字段名称。
For example, I have experimented issues with an use case as follows:
例如,我在一个用例中试验了如下问题:
I had a model inheriting from django's auth PermissionMixin:
我有一个从 django 的 auth PermissionMixin继承的模型:
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
# ...
Then I had my mixin which among other things I wanted it to override the related_nameof the groupsfield. So it was more or less like this:
然后,我有我的混入其中除其他事项外,我想它覆盖related_name了的groups领域。所以它或多或少是这样的:
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.'))
I was using this 2 mixins as follows:
我使用了这 2 个 mixin,如下所示:
class Member(PermissionMixin, WithManagedGroupMixin):
pass
So yeah, I expected this to work but it didn't. But the issue was more serious because the error I was getting wasn't pointing to the models at all, I had no idea of what was going wrong.
所以是的,我希望这会起作用,但没有。但问题更严重,因为我得到的错误根本没有指向模型,我不知道出了什么问题。
While trying to solve this I randomly decided to change my mixin and convert it to an abstract model mixin. The error changed to this:
在尝试解决这个问题时,我随机决定更改我的 mixin 并将其转换为抽象模型 mixin。错误改为:
django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'
As you can see, this error does explain what is going on.
如您所见,此错误确实解释了发生了什么。
This was a huge difference, in my opinion :)
在我看来,这是一个巨大的差异:)

