Can „list_display“ in einem Django Modeladmin Anzeigeattribute von ForeignKey Felder?
-
03-07-2019 - |
Frage
Ich habe ein Person
Modell, das eine Fremdschlüsselbeziehung Book
hat, die eine Anzahl von Feldern hat, aber ich bin sehr besorgt über author
(ein Standard CharField).
Mit diesem wird gesagt, in meinem PersonAdmin
Modell, ich möchte book.author
anzuzeigen list_display
mit:
class PersonAdmin(admin.ModelAdmin):
list_display = ['book.author',]
Ich habe alle offensichtlichen Methoden versucht, so zu tun, aber nichts scheint zu funktionieren.
Irgendwelche Vorschläge?
Lösung
Als weitere Option können Sie aussehen ups tun:
class UserAdmin(admin.ModelAdmin):
list_display = (..., 'get_author')
def get_author(self, obj):
return obj.book.author
get_author.short_description = 'Author'
get_author.admin_order_field = 'book__author'
Andere Tipps
Trotz aller großen Antworten oben und wegen mir Django neu zu sein, war ich immer noch fest. Hier ist meine Erklärung von einer sehr newbie Perspektive.
models.py
class Author(models.Model):
name = models.CharField(max_length=255)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=255)
admin.py (falscher Weg) - denken Sie es mithilfe von 'model__field' zu Referenz funktionieren würde, aber es funktioniert nicht
class BookAdmin(admin.ModelAdmin):
model = Book
list_display = ['title', 'author__name', ]
admin.site.register(Book, BookAdmin)
admin.py (richtiger Weg) - das ist, wie Sie einen Fremdschlüssel Namen des Django Weges Referenz
class BookAdmin(admin.ModelAdmin):
model = Book
list_display = ['title', 'get_name', ]
def get_name(self, obj):
return obj.author.name
get_name.admin_order_field = 'author' #Allows column order sorting
get_name.short_description = 'Author Name' #Renames column head
#Filtering on side - for some reason, this works
#list_filter = ['title', 'author__name']
admin.site.register(Book, BookAdmin)
Wie der Rest ging ich mit Callables auch. Aber sie haben einen Nachteil: Standardmäßig können Sie nicht auf sie bestellen. Glücklicherweise gibt es eine Lösung dafür:
def author(self):
return self.book.author
author.admin_order_field = 'book__author'
Bitte beachten Sie, dass die get_author
Funktion Zugabe würde die list_display im Admin verlangsamen, weil jede Person zeigen würde eine SQL-Abfrage machen.
Um dies zu vermeiden, müssen Sie get_queryset
Methode in PersonAdmin, zum Beispiel ändern:
def get_queryset(self, request):
return super(PersonAdmin,self).get_queryset(request).select_related('book')
Vor 73 Abfragen in 36.02ms (67 duplizierte Anfragen in admin)
Nach 6 Abfragen in 10.81ms
Nach der Dokumentation, können Sie nur die __unicode__
Darstellung eines ForeignKey angezeigt werden:
http://docs.djangoproject.com/en / dev / ref / contrib / admin / # list-Anzeige
Es scheint seltsam, dass es nicht das 'book__author'
Stil Format nicht unterstützt, die überall in dem DB-API verwendet wird.
Es stellt sich heraus gibt es ein Ticket für diese Funktion , die gekennzeichnet ist als würde nicht beheben.
Sie können zeigen, was Sie in Listendarstellung wollen durch eine aufrufbare verwenden. Es würde wie folgt aussehen:
def book_author(object): return object.book.author class PersonAdmin(admin.ModelAdmin): list_display = [book_author,]
Ich habe gerade gebucht einen Schnipsel, die admin.ModelAdmin Unterstützung '__' Syntax macht:
http://djangosnippets.org/snippets/2887/
So können Sie tun:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
Dies ist im Grunde nur tun, die gleiche Sache in den anderen Antworten beschrieben, aber es kümmert sich automatisch um (1) Einstellung admin_order_field (2) Einstellung short_description und (3) Modifizieren der queryset eine Datenbank Hit für jede Zeile zu vermeiden.
ist das man schon akzeptiert, aber wenn es keine andere Dummies gibt (wie ich), die nicht sofort von der bekommen hat derzeit Antwort akzeptiert, ist hier ein bisschen mehr Detail.
Die Modellklasse durch die ForeignKey
verwiesen braucht eine __unicode__
Methode darin zu haben, wie hier:
class Category(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
Das machte den Unterschied für mich, und soll auf das oben beschriebene Szenario anzuwenden. Dies funktioniert auf Django 1.0.2.
, wenn Sie es in Inline versuchen, Sie werden nicht erfolgreich sein, wenn:
in Ihrem inline:
class AddInline(admin.TabularInline):
readonly_fields = ['localname',]
model = MyModel
fields = ('localname',)
in Ihrem Modell (MyModel):
class MyModel(models.Model):
localization = models.ForeignKey(Localizations)
def localname(self):
return self.localization.name
Wenn Sie eine Menge Beziehung Attributfeldern in list_display
verwenden und nicht möchten, dass eine Funktion erstellen (und es ist Attribute) für jeden, eine unbefestigte, aber einfache Lösung, um die ModelAdmin
instace __getattr__
Methode außer Kraft setzen würde, die Callables Schaffung auf die Fliege:
class DynamicLookupMixin(object):
'''
a mixin to add dynamic callable attributes like 'book__author' which
return a function that return the instance.book.author value
'''
def __getattr__(self, attr):
if ('__' in attr
and not attr.startswith('_')
and not attr.endswith('_boolean')
and not attr.endswith('_short_description')):
def dyn_lookup(instance):
# traverse all __ lookups
return reduce(lambda parent, child: getattr(parent, child),
attr.split('__'),
instance)
# get admin_order_field, boolean and short_description
dyn_lookup.admin_order_field = attr
dyn_lookup.boolean = getattr(self, '{}_boolean'.format(attr), False)
dyn_lookup.short_description = getattr(
self, '{}_short_description'.format(attr),
attr.replace('_', ' ').capitalize())
return dyn_lookup
# not dynamic lookup, default behaviour
return self.__getattribute__(attr)
# use examples
@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin, DynamicLookupMixin):
list_display = ['book__author', 'book__publisher__name',
'book__publisher__country']
# custom short description
book__publisher__country_short_description = 'Publisher Country'
@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin, DynamicLookupMixin):
list_display = ('name', 'category__is_new')
# to show as boolean field
category__is_new_boolean = True
Wie Kern hier
aufrufbare besondere Attribute wie boolean
und short_description
müssen definiert werden als ModelAdmin
Attribute, zB book__author_verbose_name = 'Author name'
und category__is_new_boolean = True
.
Das aufrufbar admin_order_field
Attribut wird automatisch definiert.
Vergessen Sie nicht, die list_select_related Attribut in Ihrem ModelAdmin
zu machen Django aditional Abfragen zu vermeiden.
Es ist ein sehr einfaches Paket in PyPI zur Verfügung zu verwenden, die Griffe genau das: django- verwandte-admin . Sie können auch den Code in GitHub .
Mit diesem, was Sie erreichen wollen, ist so einfach wie:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
Die beiden Links enthalten Ausführliche Informationen zur Installation und Nutzung, so will ich sie hier nicht einfügen, falls sie sich ändern.
So wie eine Randnotiz, wenn Sie bereits etwas anderes als model.Admin
verwenden sind (zum Beispiel war ich mit SimpleHistoryAdmin
statt), können Sie dies tun: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)
AlexRobbins' Antwort war für mich, mit der Ausnahme, dass die ersten beiden Linien im Modell sein müssen (vielleicht ist dies angenommen wurde?), Und soll selbst verweisen:
def book_author(self):
return self.book.author
Dann wird der Admin-Teil funktioniert gut.
Ich ziehe es so aus:
class CoolAdmin(admin.ModelAdmin):
list_display = ('pk', 'submodel__field')
@staticmethod
def submodel__field(obj):
return obj.submodel.field