Django抽象模型与常规继承

2025-04-16 08:56:00
admin
原创
22
摘要:问题描述:除了语法之外,使用 Django 抽象模型和使用带有 Django 模型的纯 Python 继承之间有什么区别?优点和缺点是什么?更新:我觉得我的问题被误解了,我收到的回复都是关于抽象模型和继承自 django.db.models.Model 的类之间的区别。 我实际上想知道继承自 Django 抽...

问题描述:

除了语法之外,使用 Django 抽象模型和使用带有 Django 模型的纯 Python 继承之间有什么区别?优点和缺点是什么?

更新:我觉得我的问题被误解了,我收到的回复都是关于抽象模型和继承自 django.db.models.Model 的类之间的区别。 我实际上想知道继承自 Django 抽象类(Meta: abstract = True)的模型类和继承自“object”(而不是 models.Model)的普通 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(...

解决方案 1:

我实际上想知道从 django 抽象类(Meta:abstract = True)继承的模型类和从“对象”(而不是 models.Model)继承的普通 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)

...不会导致生成任何表。

您可以使用多重继承来做这样的事情......

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)

...这将创建一个表,但它将忽略类中定义的字段User,因此您最终会得到这样的表...

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

解决方案 2:

抽象模型会为每个子模型创建一个包含所有列的表,而使用“普通”Python 继承则会创建一组相互关联的表(也称为“多表继承”)。考虑一下有两个模型的情况:

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

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

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

哪里vehicle_id有一个链接指向某一行,其中app_vehicle还包含汽车的车轮数量。

现在,Django 会将其以对象形式很好地组合在一起,以便您可以将其num_wheels作为属性进行访问Car,但数据库中的底层表示会有所不同。


更新

为了解决您更新的问题,从Django抽象类继承和从Python继承之间的区别object在于,前者被视为数据库对象(因此它的表将同步到数据库),并且具有的行为Model。从普通的Python继承object不会赋予该类(及其子类)任何这些特性。

解决方案 3:

主要区别在于模型数据库表的创建方式。如果使用继承,abstract = TrueDjango 将为父模型和子模型分别创建一个单独的表,用于保存每个模型中定义的字段。

如果您使用abstract = True基类,Django 将仅为从基类继承的类创建一个表 - 无论字段是在基类还是继承类中定义。

其优缺点取决于应用程序的架构。以下是示例模型:

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并为 和 分别创建表BlogEntryImage此解决方案的优势在于,您可以查询所有可发布项中定义在基础模型中的字段,无论它们是博客文章还是图片。但因此,如果您查询图片,Django 将不得不进行连接操作……如果使Publishable abstract = TrueDjango 不会为 创建一个表Publishable,而只会为博客文章和图片创建一个表,其中包含所有字段(包括继承的字段)。这将非常方便,因为像 get 这样的操作不需要连接操作。

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

解决方案 4:

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

与 Python 类不同,模型继承不允许隐藏字段名称。

例如,我已经试验过如下用例的问题:

我有一个从 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

    # ...

然后我创建了一个 mixin,除了其他功能之外,我还想让它覆盖related_namegroups字段。所以它大致是这样的:

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

我使用这两个 mixin 如下:

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'

正如您所见,这个错误确实解释了发生了什么。

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

解决方案 5:

主要区别在于继承 User 类时。一个版本的行为类似于简单类,而另一个版本的行为类似于 Django 模型。

如果你继承了基础的“对象”版本,你的 Employee 类将只是一个标准类,first_name 不会成为数据库表的一部分。你无法用它创建表单或使用任何其他 Django 功能。

如果您继承了 models.Model 版本,您的 Employee 类将具有 Django Model的所有方法,并且它将继承 first_name 字段作为可在表单中使用的数据库字段。

根据文档,抽象模型“提供了一种在 Python 级别提取公共信息的方法,同时在数据库级别每个子模型仍只创建一个数据库表”。

解决方案 6:

在大多数情况下,我更喜欢使用抽象类,因为它不会创建单独的表,ORM 也不需要创建数据库连接。而且在 Django 中使用抽象类非常简单。

class Vehicle(models.Model):
    title = models.CharField(...)
    Name = models.CharField(....)

    class Meta:
         abstract = True

class Car(Vehicle):
    color = models.CharField()

class Bike(Vehicle):
    feul_average = models.IntegerField(...)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用