【问题标题】:django: how to make query be not lazy executed?django:如何使查询不被懒惰地执行?
【发布时间】:2026-01-09 07:15:01
【问题描述】:

我的自定义管理器方法中的查询延迟执行有问题。在其中我想通过模型 CharField 选择来分离查询并返回 dict[choice, QuerySet]。

model.py 部分:

...

PRODUCT_STATUS = [
    ('pn', 'Запланировано'),
    ('ga', 'В процессе (Ознакомляюсь)'),
    ('rv', 'Повтор'),
    ('ac', 'Завершено'),
    ('ab', 'Брошено'),
    ('pp', 'Отложено'),
]


class ExtendedManager(models.Manager):
    def separated_by_status(self, product_type):
        query = super().get_queryset().all()
        dict_ = {}
        for status in PRODUCT_STATUS:
            dict_.update({status[1]: query.filter(status=status[0]).all()})
        return dict_

...

views.py 部分与经理使用:

...

class ProductListView(ContextMixin, View):
    template_name = 'myList/myList.html'

    def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
        product = kwargs.get('product')
        if product not in {'film', 'game', 'series', 'book'}:
            raise Http404
        context = self.get_context_data()
        context['title'] = f'Список {product}'
        context['dict_queryset'] = Product.objects.separated_by_status(product)
        
        return render(request, self.template_name, context)

...

django 调试工具栏结果: here

问题是查询在管理器中是惰性执行的,但在模板中它已经分别为每个 PRODUCT_STATUS 元素完全执行。 cat 如何优化执行 1 次?

如果我错误地使用了“懒惰”这个词,我深表歉意。

【问题讨论】:

    标签: python sql django orm query-optimization


    【解决方案1】:

    问题不在于懒惰,问题在于你做了一个QuerySet per PRODUCT_STATUS

    您可以使用groupby function [Python-doc]itertools module [Python-doc] 单遍制作这样的字典:

    from itertools import groupby
    from operator import attrgetter
    
    class ExtendedManager(models.Manager):
        def separated_by_status(self, product_type):
            query = super().get_queryset().order_by('status')
            dict_ = {
                k: list(vs)
                for k, vs in groupby(query, attrgetter('status'))
            }
            return {
                status1: dict_.get(status0, [])
                for status0, status1 in PRODUCT_STATUS
            }

    【讨论】:

    • 谢谢,这是解决方案。据我了解,每次我使用.all().filter() 等时,都会生成新的QuerySet?那么,为避免这种情况,我应该使用 Python 本身的内部工具过滤查询?
    • @ALittleMoron:它确实会创建一个新的查询集,并在必要时对其进行评估。如果您需要对数据进行分组,因此最好使用单个查询检索所有数据,并在 Django/Python 层进行分组。但过滤应该尽可能由数据库来完成。