Django管理器

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'))
# <QuerySet [{'has_dense_cities': 9535}, {'has_dense_cities': 209}, {'has_dense_cities': 259}, 
# {'has_dense_cities': 0}, {'has_dense_cities': 0}, {'has_dense_cities': 0}]>

另外一件要注意的事情是 Manager 方法可以访问 self.model 以获取它们所附加的模型类。

print(self.model) # <class 'manytable.models.State'>

自定义 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')

# <StateQuerySet [{'has_dense_cities': 3}]>

现在可以像任何的 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')
# <StateCountQuerySet [{'name': 'Illinois'}, {'name': '中国'}, {'name': '美国'}]>

管理器调用自定义 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)  # 一定要加 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

猜你喜欢

转载自blog.csdn.net/qq_39253370/article/details/119899255