2017-01-04 6 views
2

でクエリセット・カウント()メソッドをオーバーライドする方法を、私はそうのようなDjangoのadminクラス内count()メソッドをオーバーライドしたいと思います:、時間とコストのかかる正確なデータベース・カウントクエリを避けるために、Djangoの管理者リスト

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クラスの元のクエリーセットにアクセスする方法を知らない。何か案が?私はget_changelistを通して全体をchangelistで上書きできることを知っています。しかし、これにはDjangoのリポジトリからコードを複製することがたくさんあります。

答えて

1

私が間違っている可能性がCountProxyのインスタンス属性としてqsを渡すことはできますか?

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 
+0

魅力のように動作します、ありがとう! –

2

私は以前も同様のことをしました。

私はカスタムクエリセットのクラスを定義した:

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() 
+0

良い解決策ですが、モデルのオブジェクトマネージャをオーバーライドすることはできません。この特別なカウント方法は、Djangoの管理インターフェース内でのみ適用する必要があります。 –

+0

あなたはここに行きます。http://stackoverflow.com/a/10446271/1587534 – Saksow

+0

この回答のコードはそれほど意味をなさない。 'return qs._clone(klass = ApproxCountQuerySet)'とは何ですか? 'klass'属性は、おそらく外部の目に見えないコードからのものです...しかし、この質問/回答は実際に私自身のコード/問題の元です。 –