[英]How to override queryset count() method in Django's admin list
為了避免耗時且昂貴的精確數據庫計數查詢,我想覆蓋 Django 管理類中的count()
方法,如下所示:
from django.contrib import admin
from django.db import connection
class CountProxy:
def __call__(self):
# how to access the queryset `query` here?
query = ...
try:
if not query.where:
cursor = connection.cursor()
cursor.execute("SELECT reltuples FROM pg_class WHERE relname = %s", [query.model._meta.db_table])
n = int(cursor.fetchone()[0])
if n >= 1000: return n # exact count for small tables
return object_list.count()
except:
# exception for lists
return len(object_list)
return estimated_count
class MyAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
qs.count = CountProxy()
return qs
但我不知道如何在我的CountProxy
類中訪問原始CountProxy
。 任何的想法? 我知道我可以通過get_changelist
覆蓋整個get_changelist
changelist
視圖。 但這涉及來自 Django 存儲庫的大量重復代碼。
我可能是錯的,但是您可以將qs
作為CountProxy
的實例屬性CountProxy
嗎?
class CountProxy:
def __init__(self, query):
self.query = query
def __call__(self):
# you've already had the query here, do something with self.query
class MyAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
qs.count = CountProxy(qs)
return qs
我以前做過類似的事情,所以我可以提供幫助。
我定義了一個自定義查詢集類:
class MyQuerySet(QuerySet):
def count(self):
"""
Override count queries (performed by Django ORM) to display approximate value.
This will speed the admin interface.
"""
if self._result_cache is not None and not self._iter:
return len(self._result_cache)
query = self.query
if not (query.group_by or query.having or query.distinct):
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)
然后定義了一個自定義模型管理器:
class MyManager(models.Manager):
def get_query_set(self):
return MyQuerySet(self.model)
然后在我的模型中使用它:
class MyModel(models.Model):
objects = MyManager()
這就是對我有用的 postgres 和 Django 2.2.x
from django.db.models.query import QuerySet
from django.db import connection
class FastCountQuerySet(QuerySet):
"""
Fast count (estimate) queryset to speedup count
"""
def count(self):
"""
Override count queries (performed by Django ORM) to display approximate value.
This will speed up count i.e. in the admin interface.
"""
if self._result_cache is not None:
return len(self._result_cache)
query = self.query
if not (query.group_by or query.where or query.distinct):
# cursor = connections[self.db].cursor()
cursor = connection.cursor()
cursor.execute("SELECT reltuples FROM pg_class WHERE relname = %s", [self.query.model._meta.db_table])
n = int(cursor.fetchone()[0])
if n >= 1000:
return n # exact count for small tables
else:
return self.query.get_count(using=self.db)
else:
return self.query.get_count(using=self.db)
class CustomManager(models.Manager):
"""
Custom db manager
"""
def get_queryset(self):
return FastCountQuerySet(self.model)
最后覆蓋您的模型管理器:
class YourModel(models.Model):
objects = CustomManager()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.