我每次使用管理列出模型的项目,管理数在表中的行。 更糟糕的是,它似乎是这样做,即使你过滤查询。
举例来说,如果我想只显示id为123,型号456,789,我可以这样做:
/admin/myapp/mymodel/?id__in=123,456,789
但查询跑(等等)是:
SELECT COUNT(*) FROM `myapp_mymodel` WHERE `myapp_mymodel`.`id` IN (123, 456, 789) # okay
SELECT COUNT(*) FROM `myapp_mymodel` # why???
这是杀人的MySQL + InnoDB的。 看来,这个问题部分承认这一票 ,但因为它计数,即使它是不应该的所有行我的问题似乎更加具体。
有没有一种方法来禁用全球行算不算?
注:我使用Django 1.2.7。
Django的1.8使您可以通过设置禁用此show_full_result_count = False
。
https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.show_full_result_count
好吧,我想我找到了解决办法。 正如彼得建议,最好的办法是对工作的count
财产,它可以通过自定义查询设置(如图覆盖它做这个职位 ),专门用一个近似等价计数:
from django.db import connections, models
from django.db.models.query import QuerySet
class ApproxCountQuerySet(QuerySet):
"""Counting all rows is very expensive on large Innodb tables. This
is a replacement for QuerySet that returns an approximation if count()
is called with no additional constraints. In all other cases it should
behave exactly as QuerySet.
Only works with MySQL. Behaves normally for all other engines.
"""
def count(self):
# Code from django/db/models/query.py
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
is_mysql = 'mysql' in connections[self.db].client.executable_name.lower()
query = self.query
if (is_mysql and not query.where and
query.high_mark is None and
query.low_mark == 0 and
not query.select and
not query.group_by and
not query.having and
not query.distinct):
# If query has no constraints, we would be simply doing
# "SELECT COUNT(*) FROM foo". Monkey patch so the we
# get an approximation instead.
cursor = connections[self.db].cursor()
cursor.execute("SHOW TABLE STATUS LIKE %s",
(self.model._meta.db_table,))
return cursor.fetchall()[0][4]
else:
return self.query.get_count(using=self.db)
然后在admin:
class MyAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(MyAdmin, self).queryset(request)
return qs._clone(klass=ApproxCountQuerySet)
近似的功能,可以把事情搞得一团糟上页码100000,但它是我的情况不够好。
我发现新星的回答非常有帮助,但我使用Postgres的。 我修改了它稍微进行一些轻微的改动Postgres的工作来处理表的命名空间,并略有不同的“检测Postgres的”逻辑。
这里是皮克版本。
class ApproxCountPgQuerySet(models.query.QuerySet):
"""approximate unconstrained count(*) with reltuples from pg_class"""
def count(self):
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
if hasattr(connections[self.db].client.connection, 'pg_version'):
query = self.query
if (not query.where and query.high_mark is None and query.low_mark == 0 and
not query.select and not query.group_by and not query.having and not query.distinct):
# If query has no constraints, we would be simply doing
# "SELECT COUNT(*) FROM foo". Monkey patch so the we get an approximation instead.
parts = [p.strip('"') for p in self.model._meta.db_table.split('.')]
cursor = connections[self.db].cursor()
if len(parts) == 1:
cursor.execute("select reltuples::bigint FROM pg_class WHERE relname = %s", parts)
else:
cursor.execute("select reltuples::bigint FROM pg_class c JOIN pg_namespace n on (c.relnamespace = n.oid) WHERE n.nspname = %s AND c.relname = %s", parts)
return cursor.fetchall()[0][0]
return self.query.get_count(using=self.db)
新星的解决方案(ApproxCountQuerySet)的伟大工程,但在Django的查询集法的新版本与get_queryset得到了更换,所以现在应该是:
class MyAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
return qs._clone(klass=ApproxCountQuerySet)
如果这是一个严重的问题,你可能不得不采取激烈行动™。
看着一个1.3.1代码安装,我看到管理员密码是使用返回的分页程序get_paginator()
。 默认的分页程序类似乎是django/core/paginator.py
。 这个类有一个私有值称为_count
这是在设置Paginator._get_count()
在我的副本线120)。 这又是用来设置称为分页程序类的属性 count
。 我认为_get_count()
是你的目标。 现在,舞台设置。
你有两个选择:
直接修改源。 我不建议这样做,但因为你似乎在1.2.7被卡住你会发现它是最适宜的。 记住要记录这种变化! 将来的维护(可能包括你自己)会感谢你的头了。
猴补丁类。 这比直接修改更好,因为一),如果你不喜欢你就是注释掉猴补丁的变化,和b)它更可能使用Django的未来版本的工作。 我有一个猴补丁追溯到4年多,因为他们还没有固定的模板变量中的错误_resolve_lookup()
不会在评估的顶层承认可调用,只有在较低级别的代码。 虽然修补程序(它包装一个类的方法)写对0.97前,它仍然工作在1.3.1。
我没有花时间去弄清楚到底什么样的变化,你将不得不作出你的问题,但它可能是一起添加的行_approx_count
成员适当的类class META
,然后再测试,看看是否存在ATTR。 如果它确实是None
那么做sql.count()
并设置它。 您可能还需要重置,如果你是对的(或接近)列表的最后一页。 联系我,如果你需要在这一点更多的帮助; 我的电子邮件是我的个人资料。
它可以更改默认的分页程序由管理类使用。 这里有一个缓存结果的时间短时期: https://gist.github.com/e4c5/6852723