简体   繁体   English

提高 Django 管理列表过滤器查询的性能

[英]Improving performance of Django admin list filter queries

I'm developing a Django admin wrapper around a PostgreSQL data-warehouse app, which has some tables with millions of records.我正在围绕 PostgreSQL 数据仓库应用程序开发 Django 管理包装器,该应用程序有一些包含数百万条记录的表。

The admin changelist page, without any list filters, loads in a second, but if I include certain columns in the admin's list_filters , the it loads very slowly, and can take between 30 seconds to a minute to load.没有任何列表过滤器的管理员list_filters列表页面会在一秒钟内加载,但是如果我在管理员的list_filters包含某些列,它的加载速度会非常缓慢,并且可能需要 30 秒到一分钟的时间来加载。

Inspecting the database, I saw several queries like:检查数据库,我看到几个查询,如:

SELECT DISTINCT "warehouse_data"."filter_field1" FROM "warehouse_data" ORDER BY "warehouse_data"."filter_field1" ASC;

each one only takes 3-5 seconds, but there's as there's a dozen of them, these add up.每一个只需要 3-5 秒,但是有十几个,这些加起来。 All the fields are indexed, so I'm not sure how else I can speed them up.所有字段都被编入索引,所以我不知道我还能如何加快它们的速度。 How can I improve admin performance?如何提高管理性能? How would I plug in Django's caching mechanism to cache the actual queries of these list filters?我将如何插入 Django 的缓存机制来缓存这些列表过滤器的实际查询?

As you observed;正如你所观察到的; the slowness comes from django compiling the list of unique values so it can display them in the sidebar.缓慢来自 django 编译唯一值列表,以便它可以在侧边栏中显示它们。

Under the hood this requires a full table scan against the database, which is costly when your table is very large.在幕后,这需要对数据库进行全表扫描,当您的表非常大时,这会很昂贵。 If you're using this field as a list_filter;如果您将此字段用作 list_filter; there's a good chance that the number of unique values is small, and that you can generate a list of unique values more efficiently yourself (assuming you know where the values are coming from).很有可能唯一值的数量很少,并且您可以自己更有效地生成唯一值列表(假设您知道这些值的来源)。 To do that, you can define a custom list_filter.为此,您可以定义自定义 list_filter。

From the docs (condensed for berevity):来自文档(为简洁起见而浓缩):

list_filter should be a list or tuple of elements, where each element should be of one of the following types: list_filter 应该是元素的列表或元组,其中每个元素应该是以下类型之一:

  • a field name字段名称
  • a class inheriting from django.contrib.admin.SimpleListFilter从 django.contrib.admin.SimpleListFilter 继承的类
from datetime import date
from django.contrib import admin
from django.utils.translation import gettext_lazy as _

class DecadeBornListFilter(admin.SimpleListFilter):
    title = _('decade born')
    parameter_name = 'decade'

    def lookups(self, request, model_admin):
        return (
            ('80s', _('in the eighties')),
            ('90s', _('in the nineties')),
        )

    def queryset(self, request, queryset):
        # Compare the requested value (either '80s' or '90s')
        # to decide how to filter the queryset.
        if self.value() == '80s':
            return queryset.filter(birthday__gte=date(1980, 1, 1),
                                    birthday__lte=date(1989, 12, 31))
        if self.value() == '90s':
            return queryset.filter(birthday__gte=date(1990, 1, 1),
                                    birthday__lte=date(1999, 12, 31))

class PersonAdmin(admin.ModelAdmin):
    list_filter = (DecadeBornListFilter,)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM