web-dev-qa-db-ja.com

多対1の関係を持つモデルのDjango adminにソート可能なカウント列を追加するにはどうすればよいですか?

Publisherモデルへの外部キーを含むBookモデルがあるとします。

組み込みの並べ替えを使用できるように、Django adminに各出版社が発行した書籍の数を示す列を表示するにはどうすればよいですか?

50
GJ.

同じ問題が発生しました(モデルのマネージャーを変更して、遅い注釈や結合を追加することはできません)。ここでの2つの答えの組み合わせが機能します。 @Andreは本当に近いです、Django管理者は管理者だけのクエリセットの変更をサポートしているので、ここで同じロジックを適用してから、admin_order_field属性を使用します。新しい管理フィールドをに追加する必要がありますもちろん、list_display。

from Django.db.models import Count

class EventAdmin(admin.ModelAdmin)
    list_display = (..., 'show_artist_count')

    def queryset(self, request):
    # def get_queryset(self, request):    for Django 1.6+
        qs = super(EventAdmin, self).queryset(request)
        return qs.annotate(artist_count=Count('artists'))

    def show_artist_count(self, inst):
        return inst.artist_count
    show_artist_count.admin_order_field = 'artist_count'
76
Lincoln B

これを試して:

新しい Manager (および aggregate をブックリレーションフィールドにカウントして):

class PublisherManager(models.Manager):
    def get_query_set(self):
        return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))

pubcountで並べ替えます:

class Publisher(models.Model):
    ......
    objects = PublisherManager()

    class Meta:
        ordering = ('pubcount',)
8
Andre Bossard

あなたは確かに追加することから始めるべきです:

class PublisherManager(models.Manager):
    def get_query_set(self):
        return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))

ただし、並べ替え可能なフィールドとして追加する正しい方法は次のとおりです。

class Publisher(models.Model):
    ......
    objects = PublisherManager()

    def count(self):
        return self.pubcount
    count.admin_order_field = 'pubcount'

そして、admin.pyのモデルadminのlist_display属性に「count」を追加するだけです。

1
GJ.

リンカーンBの答えは私にとって正しい方法でした。

最初は彼の解決策についてコメントしたかったのですが、実際には少し違う問題を解決していることに気づきました。自分のニーズに合わせて「カスタマイズ」したい管理者クラス、つまりDjango-taggit管理者がいました。私のアプリケーションのadmin.pyの1つに、次のものを追加しました。

# sort tags by name in admin (count items also possible)
from taggit.admin import TagAdmin
TagAdmin.ordering = ["name"]
#   make sortable on item_count:
# 1. function for lookup
def item_count(obj):
    """This takes the item_count from object: didn't work as model field."""
    return obj.item_count # not needed: obj.taggit_taggeditem_items.count()
# 2. property in function - admin field name
item_count.admin_order_field = 'item_count'
# 3. queryset override, with count annotation
from Django.db.models import Count
TagAdmin.queryset = lambda self, request: super(TagAdmin, self).queryset(request).annotate(item_count=Count('taggit_taggeditem_items'))
# 4. add to list display
TagAdmin.list_display = ["name", item_count]

私にとって興味深い観察は、querysetに注釈を付けて、"item_count"list_displayに追加することはできなかったということでした。これは、TagAdminitem_countメソッドがなく、Tagモデルクラス(querysetのみ)。

0
Tomasz Gandor

次のようなものを試してください。

class PublisherAdminWithCount(Admin):

    def book_count(self, obj):
        return obj.book_set.count()

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)
0
gruszczy