49 votes

Comment ajouter une colonne de décompte triable à l'administrateur Django d'un modèle avec une relation plusieurs-à-un?

Supposons que j'ai un modèle Book contenant une clé étrangère vers un modèle Publisher.

Comment afficher dans l'admin Django une colonne avec le nombre de livres publiés par chaque éditeur, de manière à pouvoir utiliser le tri intégré?

79voto

Lincoln B Points 1214

J'ai eu le même problème (je ne peux pas changer le gestionnaire de mon modèle pour ajouter des annotations ou des jointures lentes). Une combinaison de deux des réponses ici fonctionne. @Andre est vraiment proche, l'administrateur Django prend en charge la modification de l'ensemble de requêtes pour uniquement l'administrateur, alors appliquez la même logique ici, puis utilisez l'attribut admin_order_field. Vous devez toujours ajouter le nouveau champ admin à list_display, bien sûr.

 from django.db.models import Count

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

    def queryset(self, request):
        return Event.objects.annotate(artist_count=Count('artists'))

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

8voto

Andre Bossard Points 4655

Essaye ça:

faire un nouveau gestionnaire (et agréger avec compter sur le champ de relation livre):

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

trier sur pubcount :

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

    class Meta:
        ordering = ('pubcount',)
 

1voto

GJ. Points 1149

Vous devriez en effet commencer par ajouter:

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

Mais la bonne façon de l'ajouter en tant que champ triable est:

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

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

Et puis vous pouvez simplement ajouter 'count' à l'attribut list_display du modèle admin dans admin.py

0voto

gruszczy Points 14097

Essayez quelque chose comme ceci:

 class PublisherAdminWithCount(Admin):

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

    list_display = ('user_count',)

admin.site.register(Group, PublisherAdminWithCount)
 

0voto

Tomasz Gandor Points 426

Lincoln B réponse était la bonne façon de faire pour moi.

Au début, je voulais juste un commentaire sur sa solution, mais en fait je me suis retrouvé à la résolution d'un problème légèrement différent. J'avais un administrateur de classe, ce que je voulais "personnaliser" à mes besoins, à savoir l' django-taggit admin. Dans l'une de mes application de l' admin.py, j'ai ajouté:

# 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]

L'observation intéressant pour moi était que je ne pouvais pas juste d'annoter l' queryset, et ajouter "item_count" de list_display - parce qu'il n'y avait pas d' item_count méthode de TagAdmin,, ni une méthode ou le champ de l' Tag de la classe du modèle (seulement dans l' queryset).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X