object
book =Book.objects.get()
在经常写 orm 的时候总是会用到 objects,那 objects 是一个什么东西呢? objects 为我们提供了一系列的对数据库操作的查询方法,objects 是 django 中的管理器对象,管理器中提供了很多对数据库查询的方法,像平常我们经常用的 get、filter、all 等。 objects 是 model.Manager 类的对象,它赋予了 django 模型操作数据库的能力, Django 每个模型都至少有一个 Manager ,我们平常使用的都是默认的, 但是在有些时候可能需要添加额外的 Manager 方法, 或者修改 Manager 返回的原始 Queryset 的时候我们需要自定义一些管理器来帮我们实现。
为什么自定义管理器
- 添加额外的 Manager 方法
- 修改 Manager 返回的原始 Queryset
- 组织可重用查询逻辑,便于查询的组合
添加额外的 Manager 方法
添加额外的Manager方法一般是为模型添加“表级”功能的更好方法(对于“行级”功能——即,只操作简单模型对象——通过模型方法,而不是自定义Manager的方法。) 模型方法: 某个对象实例上生效,在 model 中定义一些相关逻辑代码的处理。 如:处理一个对象的 baby_boomer_status 方法, 使每个对象都能使用。
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"
例如,这个自定义Manager添加了一个方法 add_dense_cities() 方法,查询每个国家的城市总数:
class StateQuerySet(models.Manager):
def add_dense_cities(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
class State(models.Model):
objects = StateQuerySet()
name = models.CharField(verbose_name="名称", max_length=64)
views.py:
q = State.objects.add_dense_cities()
print(q.values('has_dense_cities'))
另外一件要注意的事情是 Manager 方法可以访问 self.model 以获取它们所附加的模型类。
print(self.model)
自定义 Manager 方法的问题
在有些时候我们可能需要先过滤一遍数据再去调用管理器方法,这个时候就会有问题,Manager 管理器不支持链式调用, 如下面的例子, 我想先过滤是活跃的城市, 再去计算总数:
class StateQuerySet(models.Manager):
def add_dense_cities(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_filter_status(self):
return self.filter(cities__status=True)
class State(models.Model):
objects = StateQuerySet()
name = models.CharField(verbose_name="名称", max_length=64)
views.py:
q = State.objects.with_filter_status().add_dense_cities()
print(q.values('has_dense_cities'))
报错如下: 出现的原因: Manager 返回的结果是链式的,也就是queryset , 依然拥有 queryset 的一些操作方法,如:get、all、 filter等,但是你试图在自定义的一些方法后面使用 queryset 或者是 Manager 中定义的方法, 那么 链式将会中止,要解决上面问题, 就要自定义 Queryset 方法, 也就是上述提到的 修改 Manager 返回的原始 Queryset。
修改 Manager 返回的原始 Queryset
class StateQuerySet(models.QuerySet):
def add_dense_cities(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_filter_status(self):
return self.filter(cities__status=True)
class State(models.Model):
objects = StateQuerySet.as_manager()
name = models.CharField(verbose_name="名称", max_length=64)
views.py:
q = State.objects.with_filter_status().add_dense_cities()
print(q.values('has_dense_cities'))
return HttpResponse('ok')
现在可以像任何的 QuerySet 方法一样使用他。 并且是链式的! **自定义的 QuerySet :**自定义的 QuerySet 和 自定义的 Manager 方法使用起来则是不同,QuerySet 是调用 as_manager() 方法, 该方法返回一个 Manager 实例,其中包含 QuerySet 的方法的副本,简单明了的说就是 Manager 就是提供数据库查询的接口, QuerySet 提供了查询数据库的方法,你扩展了 QuerySet 中的方法,那么在使用的时候怎么办呢, 就是需要使用 as_manager() 这个方法拷贝你自己定义的 QuerySet 方法。 自定义的 Manager: 自定义的 Manager 只是修改了默认的 Manager
另外一种情况: 如下会返回数据库中所有的国家。
q = State.objects.all()
print(q.values('has_dense_cities'))
但是如果我想返回包含我自己需要的属性, 例如城市数量在 200 以上的国家:
class StateQuerySet(models.QuerySet):
def add_dense_cities(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_filter_status(self):
return self.filter(cities__status=True)
class StateCountQuerySet(models.QuerySet):
def with_count_city(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_order_by_city(self):
return self.with_count_city().filter(has_dense_cities__gt=200)
class State(models.Model):
objects = StateQuerySet.as_manager()
count_objects = StateCountQuerySet.as_manager()
name = models.CharField(verbose_name="名称", max_length=64)
views.py: 模型有 两个 Manager —— 一个返回所有对象,另一个仅城市数大于200的国家:
q = State.objects.all()
print(q)
q_count = State.count_objects.with_count_city().with_order_by_city()
print(q_count.values('name'))
return HttpResponse('ok')
管理器调用自定义 QuerySet 方法
class StateCountQuerySet(models.QuerySet):
def with_count_city(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_order_by_city(self):
return self.with_count_city().filter(has_dense_cities__gt=200)
class DefaultManager(models.Manager):
def get_queryset(self):
return StateCountQuerySet(self.model)
def with_order_by_city(self):
return self.get_queryset().with_order_by_city()
class State(models.Model):
objects = StateQuerySet.as_manager()
count_objects = StateCountQuerySet.as_manager()
manager_object = DefaultManager()
name = models.CharField(verbose_name="名称", max_length=64)
views.py: 管理器 State.manager_object 直接调用 with_order_by_city。
q = State.manager_object.with_order_by_city()
print(q.values('name'))
return HttpResponse('ok')
进阶用法 from_queryset()
对于进阶用法,你可能同时要一个自定义 Manager 和一个自定义 QuerySet。你可以通过调用 Manager.from_queryset() 达成目的,这将会返回一个自定义基础 Manager 的子类,带有一份自定义 QuerySet 方法的拷贝:
class StateCountQuerySet(models.QuerySet):
def with_count_city(self):
return self.annotate(
has_dense_cities=Count('cities__state_id')
)
def with_order_by_city(self):
return self.with_count_city().filter(has_dense_cities__gt=200)
class FormManager(models.Manager):
def with_filter_city(self):
return self.filter(cities__status=False)
class State(models.Model):
manager_object = FormManager.from_queryset(StateCountQuerySet)()
name = models.CharField(verbose_name="名称", max_length=64)
views.py:
q = State.manager_object.with_order_by_city()
print(q.values('name'))
return HttpResponse('ok')
总结
- 自定义 Manager 将获得一个 queryset 实例,当您想再次过滤它时,会报错。
- as_manager()方法,该方法将其转变为 Manager
您可以在查询集上定义所有自定义方法,并将其转变为管理器,然后附加到模型,根据需要进行多次链接 queryset方法 - 自定义的 Manager 代码, 你可以写在models.py, 但随着代码库的增长, 我更加推荐你将定义的 QuerySets 和
Managers - 建议总是想编写QuerySet方法,并也通过as_manager()在管理器中使用它们
参考文献:
官网: https://docs.djangoproject.com/zh-hans/3.2/topics/db/managers/#create-manager-with-queryset-methods 什么时候应该在 Django 中使用自定义 Manager 和自定义 QuerySet?:https://stackoverflow.com/questions/29798125/when-should-i-use-a-custom-manager-versus-a-custom-queryset-in-django
|