Django自定义模型管理器(Manager)及方法详解

不晚
不晚
发布时间:2026-10-13| 4人浏览过
原创

本文详解Django中自定义模型管理器(Manager)的两种核心方式:添加额外管理器以封装表级查询,以及通过重写get_queryset()修改初始查询集。同时介绍如何自定义模型方法实现行级逻辑,以及重写save()、delete()和clean()等内置方法以控制数据库交互与数据验证流程。

Django自定义模型管理器(Manager)及方法详解

1. 自定义管理器 (Manager)

在代码 `Book.objects.all()` 中,`objects` 是一个特殊属性,用于执行数据库查询,它实际上是模型关联的一个 Manager 实例。

每个 Django 模型默认至少包含一个 Manager。开发者可以创建自定义 Manager,从而定制数据库访问的行为和逻辑。

创建自定义 Manager 主要有两种途径:一是添加额外的 Manager 实例,二是修改默认 Manager 返回的初始 QuerySet。

添加额外的 Manager

添加额外的 Manager

向模型添加额外 Manager 是实现表级功能(Table-wide functionality)的首选方案。对于仅作用于特定模型实例的行级功能,则应通过自定义模型方法来实现。

例如,为 `Book` 模型添加一个名为 `title_count()` 的 Manager 方法,该方法接收一个关键词参数,并返回标题中包含该关键词的书籍数量。


from django.db import models
# 自定义模型管理器类
class BookManager(models.Manager):
  #自定义模型管理器中的方法
  def title_count(self, keyword):
    return self.filter(title_icountains=keyword).count()
class Book(models.Model):
  title = models.CharField(max_length=100)
  authors = models.ManyToManyField(Author)
  ...
  objects = BookManager()
  def __str__(self):
    return self.title

首先,创建一个继承自 django.db.models.Manager 的 `BookManager` 类。该类包含一个 `title_count()` 方法用于统计。注意,此方法内部调用了 `self.filter()`,这里的 `self` 指向 Manager 本身。

接着,将 `BookManager()` 的实例赋值给模型的 `objects` 属性。这将覆盖模型默认的 Manager(通常也命名为 `objects`),以保持命名一致性。

完成上述配置后,可以执行以下操作:


>>> Books.objects.title_count('django')  #这是我们自定义的manager中的查询方法

>>> Books.objects.filter(title__icontains='django').count()  # 默认的查询方法依然可用

通过这种方式,可以将常用的查询逻辑封装在 Manager 中,避免在代码中重复编写相同的查询语句。

修改初始 Manager QuerySet

修改初始 Manager QuerySet

Manager 的基础 QuerySet 默认返回系统中的所有对象。例如,Book.objects.all() 会返回数据库中的所有书籍记录。你可以通过覆盖 Manager.get_queryset() 方法来重写 Manager 的基础 Queryset. get_queryset() ,使其根据需求返回特定的 QuerySet。

以下示例模型定义了两个 Manager:一个返回所有对象,另一个仅返回作者是 Roald Dahl 的书籍。


from django.db import models

#首先,定义一个Manager的子类
class DahlBookManager(models.Manager):
  def get_queryset(self):
    return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl')


# 然后,将它显式地插入到Book模型中
class Book(models.Model):
  title = models.CharField(max_length=100)
  author = models.CharField(max_length=50)
  ...
  objects = models.Manager()  # 默认Manager
  dahl_objects = DahlBookManager()  # 自定义的特殊Manager

在该示例中, Book.objects.all() 将返回数据库中的所有书籍,而 `Book.dahl_objects.all()` 仅返回作者是 Roald Dahl 的书籍。注意,我们显式地将 `objects` 设置为默认 Manager 的实例。如果不这样做,`dahl_objects` 将成为唯一的可用 Manager。

由于 `get_queryset()` 返回一个 QuerySet 对象,因此你可以继续使用 `filter()`、`exclude()` 以及其他所有 QuerySet 提供的方法。

若使用自定义 Manager,需注意:Django 会将模型中定义的第一个 Manager 视为默认 Manager。Django 的许多组件(Admin 应用除外)会明确使用该 Manager。因此,需谨慎选择默认 Manager。如果覆盖了 `get_queryset()` 导致返回无用的结果,应予以避免。

自定义模型方法

2. 自定义模型方法

若需为对象添加行级功能,应定义自定义模型方法。鉴于 Manager 通常用于整表操作,模型方法应仅针对特定的模型实例起作用。


from django.db import models

class Person(models.Model):
  first_name = models.CharField(max_length=50)
  last_name = models.CharField(max_length=50)
  birth_date = models.DateField()

  def baby_boomer_status(self):
    # Returns the person's baby_boomer status
    import datetime
    if self.birth_date < datetime.date(1945, 8, 1):
      return 'Pre-boomer'
    elif self.birth_date < datetime.date(1965, 1, 1):
      return 'Baby boomer'
    else:
      return 'Post-boomer'

  def _get_full_name(self):
    # Return the person's full name
    return f'{self.first_name} {self.last_name}'
  full_name = property(_get_full_name)  # 将类方法包装为属性

这些方法的使用示例如下:


>>> p = Person.objects.get(first_name='Barack', last_name='Obama')
>>> p.birth_date
datetime.date(1961, 8, 4)
>>> p.baby_boomer_status()
'Baby boomer'
>>> p.full_name # 注意这不是一个方法 -- 它被视为一个属性
'Barack Obama'

重写预定义的模型方法

3. 重写预定义的模型方法

Django 提供了一组封装数据库行为的模型方法,你可能需要自定义其行为,特别是 `save()` 和 `delete()`。你可以自由重写这些方法(及其他模型方法)以改变其行为。重写内置方法的经典用例是在保存对象时执行其他操作,例如:


from django.db import models

class Blog(models.Model):
  name = models.CharField(max_length=100)
  tagline = models.TextField()

  def save(self, *args, **kwargs):
    do_something()
    super(Blog, self).save(*args, **kwargs)  #Call the "real" save() method.
    do_something_else()

你也可以通过重写方法来阻止保存行为:


from django.db import models
class Blog(models.Model):
  name = models.CharField(max_length=100)
  tagline = models.TextField()
  def save(self, *args, **kwargs):
    if self.name == 'Yoko Ono's Blog':
      return  # Yoko shall never have her own blog!
    else:
      super(Blog, self).save(*args, **kwargs)  #Call the "real" save() method

务必注意,继承超类的方法至关重要,即调用  super(Blog, self).save(*args, **kwargs) ,这确保对象仍被保存到数据库中。如果忘记调用超类方法,默认行为将不会发生,数据也不会写入数据库。

同样重要的是,需传递可传递给模型方法的参数——这正是 `*args` 和 `**kwargs` 的作用。Django 可能会扩展内置模型方法的功能并添加新参数。如果在方法定义中使用 `*args` 和 `**kwargs`,可确保代码在 Django 更新时自动支持新参数。

Model.clean()

应用此方法可提供自定义的模型验证,并修改模型属性。例如,可用于为字段自动赋值,或处理多个字段联合验证的情形:


import detetime
from django.core.exceptions import ValidationError
from django.db import models

class Article(models.Model):
  ...
  def clean(self):
    # Don't allow draft entries to have a pub_date
    if self.status == 'draft' and self.pub_date is not done:
      raise ValidationEroor('Draft entries may not have a publication date')
    #Set the pub_date for published items if it hasn't been set already
    if self.status == 'published' and self.pub_date is None:
      self.pub_date = datetime.date.today()

注意,调用模型的 `save()` 方法时,不会自动调用 `clean()` 方法,需在 View 中手动调用。

在上述示例中,`clean()` 引发的 `ValidationError` 异常通过字符串实例化,因此它将被保存在一个特殊的错误字典中,键为 `NON_FIELD_ERRORS`。该键用于标识整个模型层面的错误,而非特定字段的错误:


from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
try:
  article.full_clean()
except ValidationError as e:
  non_field_errors = e.message_dict[NON_FIELD_ERRORS]

若要引发特定字段的异常,可使用字典实例化 `ValidationError`,其中字典的键为字段名。我们可以更新前面的示例,仅针对 `pub_date` 字段引发异常:


class Article(models.Model):
  ...
  def clean(self):
    # Don't allow draft entries to have a pub_date.
    if self.status == 'draft' and self.pub_date is not None:
      raise ValidationError({'pub_date': 'Draft entries may not have a publication date.'})
    ...

总结

以上所述是小编给大家介绍的Django中自定义模型管理器(Manager)及方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。