Stel dat ik een boekmodel heb met een refererende sleutel naar een uitgeversmodel.
Hoe kan ik in de Django-beheerder een kolom weergeven met het aantal boeken dat door elke uitgever is gepubliceerd, zodat ik de ingebouwde sortering kan gebruiken?
Antwoord 1, autoriteit 100%
Ik had hetzelfde probleem (ik kan de manager van mijn model niet wijzigen om langzame annotaties of joins toe te voegen). Een combinatie van twee van de antwoorden hier werkt. @Andre is heel dichtbij, de Django-beheerder ondersteunt het wijzigen van de queryset voor alleen de beheerder, dus pas hier dezelfde logica toe en gebruik vervolgens het attribuut admin_order_field. Je moet natuurlijk nog steeds het nieuwe beheerdersveld toevoegen aan 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'
Antwoord 2, autoriteit 10%
Probeer dit:
maak een nieuwe Manager(en aggregerenmet telling in het veld boekrelatie):
class PublisherManager(models.Manager):
def get_query_set(self):
return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))
sorteer het op pubcount
:
class Publisher(models.Model):
......
objects = PublisherManager()
class Meta:
ordering = ('pubcount',)
Antwoord 3
Je zou inderdaad moeten beginnen met het toevoegen van:
class PublisherManager(models.Manager):
def get_query_set(self):
return super(PublisherManager,self).get_query_set().annotate(pubcount=Count('book'))
Maar de juiste manier om het toe te voegen als een sorteerbaar veld is:
class Publisher(models.Model):
......
objects = PublisherManager()
def count(self):
return self.pubcount
count.admin_order_field = 'pubcount'
En dan kun je gewoon ‘count’ toevoegen aan het list_display attribuut van model admin in admin.py
Antwoord 4
Lincoln B’s antwoord was de juiste manier voor mij.
Eerst wilde ik alleen commentaar geven op zijn oplossing, maar ik merkte dat ik een iets ander probleem aan het oplossen was. Ik had een beheerdersklas, die ik wilde “aanpassen” aan mijn behoeften – namelijk de django-taggit
admin. In een van de admin.py
van mijn toepassing heb ik toegevoegd:
# 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]
De interessante observatie voor mij was dat ik niet alleen de queryset
kon annoteren en "item_count"
kon toevoegen aan list_display
– omdat er was geen item_count
methode in TagAdmin
, noch een methode of veld in de Tag
modelklasse (alleen in de queryset
).
Antwoord 5
Probeer zoiets als dit:
class PublisherAdminWithCount(Admin):
def book_count(self, obj):
return obj.book_set.count()
list_display = ('user_count',)
admin.site.register(Group, PublisherAdminWithCount)