Django抽象模型与常规inheritance

除了语法之外,使用django抽象模型和使用纯Pythoninheritance与django模型之间有什么区别? 优点和缺点?

更新:我想我的问题被误解,我收到了一个抽象模型和从django.db.models.Modelinheritance的类之间的差异的反应。 实际上,我想知道inheritance自django抽象类(Meta:abstract = True)的模型类和从“object”(而不是models.Model)inheritance的纯Python类之间的区别。

这里是一个例子:

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(... 

实际上,我想知道inheritance自django抽象类(Meta:abstract = True)的模型类和从“object”(而不是models.Model)inheritance的普通Python类之间的区别。

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) 

…将导致生成一个单一的表,沿着…的线

 CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); 

…而后者…

 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) 

…不会产生任何表格。

你可以使用多重inheritance来做这样的事情…

 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) 

…这将创build一个表,但它将忽略User类中定义的字段,所以你最终会得到这样一个表…

 CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); 

抽象模型创build一个包含每个子集的整个列集合的表,而使用“普通”Pythoninheritance创build一组链接表(又称“多表inheritance”)。 考虑你有两种模式的情况:

 class Vehicle(models.Model): num_wheels = models.PositiveIntegerField() class Car(Vehicle): make = models.CharField(…) year = models.PositiveIntegerField() 

如果Vehicle是一个抽象模型,您将拥有一个表:

 app_car: | id | num_wheels | make | year 

但是,如果使用普通的Pythoninheritance,则会有两个表:

 app_vehicle: | id | num_wheels app_car: | id | vehicle_id | make | model 

其中, vehicle_idapp_vehicle中的行的链接,该行也具有该车的车轮数量。

现在,Django会很好地把它放在对象forms中,所以你可以在Car上访问num_wheels作为一个属性,但是数据库中的底层表示将会不同。


更新

为了解决更新后的问题,从Django抽象类inheritance并从Python objectinheritance的区别在于前者被视为一个数据库对象(因此它的表被同步到数据库),它具有一个Model的行为。 从普通的Python objectinheritance给这个类(及其子类)没有这些质量。

只是想添加一些我在其他答案中没有看到的东西。

与python类不同, 字段名称隐藏不被模型inheritance所赋予

例如,我用一个用例来试验问题如下:

我有一个从django的auth PermissionMixininheritance的模型:

 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 # ... 

然后我有我的混入,其中我希望它覆盖groups字段的related_name 。 所以这或多或less是这样的:

 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.')) 

我正在使用这2 mixins如下:

 class Member(PermissionMixin, WithManagedGroupMixin): pass 

所以是的,我希望这个工作,但没有。 但问题更严重,因为我得到的错误并不是指向模型,我不知道发生了什么问题。

试图解决这个问题时,我随机决定改变我的mixin并将其转换为抽象模型mixin。 错误更改为:

 django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin' 

正如你所看到的,这个错误确实解释了正在发生的事情。

这是一个巨大的差异,在我看来:)

主要区别是如何创build模型的数据库表。 如果使用没有abstract = Trueinheritance,Django将为父模型和子模型创build一个单独的表,这些表包含每个模型中定义的字段。

如果对基类使用abstract = True Django只会为从基类inheritance的类创build一个表 – 无论这些字段是在基类还是inheritance类中定义的。

优点和缺点取决于您的应用程序的体系结构。 给定以下示例模型:

 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(...) 

如果Publishable类不是抽象类,Django将为列titledate创buildpublishables表,并为BlogEntryImage分别创build表。 这个解决scheme的优点是,你可以在所有的 publishables中查询基本模型中定义的字段,而不pipe它们是博客条目还是图像。 但是,因此,Django将不得不进行连接,如果你做图像查询…如果使可Publishable abstract = True Django不会创build一个发布表的表,但只为博客条目和图像,包含所有字段(也是inheritance的) 。 这将是方便的,因为没有连接将需要一个操作,如得到。

另请参阅Django关于模型inheritance的文档 。

主要的区别是当你inheritanceUser类。 一个版本的行为就像一个简单的类,另一个版本的行为就像一个Django modeel。

如果您inheritance基础“对象”版本,则您的Employee类将只是一个标准类,并且first_name不会成为数据库表的一部分。 您无法创build表单或使用其他任何Djangofunction。

如果您inheritance了models.Model版本,那么您的Employee类将拥有Django Model的所有方法,并且它将inheritancefirst_name字段作为可以在表单中使用的数据库字段。

根据文档,“ 抽象模型 ”提供了一种在Python级别分解常见信息的方法,但仍然只在数据库级别为每个子模型创build一个数据库表。