Puede "list display" en un Django ModelAdmin mostrar atributos de campos ForeignKey?
Tengo un modelo de Persona que tiene una relación de clave foránea con Book. Libro tiene una serie de campos, pero estoy más preocupado por "autor" (un CharField estándar).
Dicho esto, en mi modelo PersonAdmin, me gustaría mostrar "libro.autor "usando " list_display". He probado todos los métodos obvios para hacerlo (ver más abajo), pero nada parece funcionar. Alguna sugerencia?
class PersonAdmin(admin.ModelAdmin):
list_display = ['book.author',]
13 answers
Como otra opción, puedes hacer búsquedas como:
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'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-25 16:10:06
A pesar de todas las grandes respuestas anteriores y debido a que soy nuevo en Django, todavía estaba atascado. Aquí está mi explicación desde una perspectiva muy novata.
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 (Incorrect Way) - crees que funcionaría usando 'model _ _ field' para hacer referencia, pero no
class BookAdmin(admin.ModelAdmin):
model = Book
list_display = ['title', 'author__name', ]
admin.site.register(Book, BookAdmin)
Admin.py (Correct Way) - así es como se hace referencia a un nombre de clave foránea de la manera Django
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)
Para obtener más información, consulte el enlace del modelo Django aquí
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-04 12:02:50
Al igual que el resto, fui con callables también. Pero tienen un inconveniente: por defecto, no se puede ordenar en ellos. Afortunadamente, hay una solución para eso:
def author(self):
return self.book.author
author.admin_order_field = 'book__author'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-03 07:41:01
Tenga en cuenta que agregar la función get_author
ralentizaría list_display en el administrador, porque mostrar a cada persona haría una consulta SQL.
Para evitar esto, necesita modificar el método get_queryset
en PersonAdmin, por ejemplo:
def get_queryset(self, request):
return super(PersonAdmin,self).get_queryset(request).select_related('book')
Antes: 73 consultas en 36.02 ms (67 consultas duplicadas en admin)
Después de: 6 consultas en 10.81 ms
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-30 08:05:15
De acuerdo con la documentación, solo se puede mostrar la representación __unicode__
de una ForeignKey:
Http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-display
Parece extraño que no soporte el formato de estilo 'book__author'
que se usa en todas partes en la API de la base de datos.
Resulta que hay un ticket para esta característica, que está marcado como No solucionado.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-12 02:45:02
Puede mostrar lo que desee en la visualización de la lista utilizando un llamable. Se vería así:
def book_author(object): return object.book.author class PersonAdmin(admin.ModelAdmin): list_display = [book_author,]
Acabo de publicar un fragmento que hace admin.Sintaxis de ModelAdmin support'__':
Http://djangosnippets.org/snippets/2887 /
Así que puedes hacer:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
Esto es básicamente hacer lo mismo que se describe en las otras respuestas, pero automáticamente se encarga de (1) establecer admin_order_field (2) establecer short_description y (3) modificar el conjunto de consultas para evitar un golpe en la base de datos para cada fila.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-03 21:21:58
Este ya está aceptado, pero si hay otros maniquíes por ahí (como yo) que no lo obtuvieron inmediatamente de la respuesta actualmente aceptada, aquí hay un poco más de detalle.
La clase modelo referenciada por el ForeignKey
necesita tener un método __unicode__
dentro de ella, como aquí:
class Category(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
Eso hizo la diferencia para mí, y debería aplicarse al escenario anterior. Esto funciona en Django 1.0.2.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:14
Si lo intentas en línea, no tendrás éxito a menos que:
En su línea:
class AddInline(admin.TabularInline):
readonly_fields = ['localname',]
model = MyModel
fields = ('localname',)
En tu modelo (MyModel):
class MyModel(models.Model):
localization = models.ForeignKey(Localizations)
def localname(self):
return self.localization.name
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-30 12:30:33
Si tiene muchos campos de atributos de relación para usar en list_display
y no desea crear una función (y sus atributos) para cada uno, una solución sucia pero simple sería anular el método ModelAdmin
instace __getattr__
, creando los callables sobre la marcha:
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
Como lo esencial aquí
Los atributos especiales llamables como boolean
y short_description
deben definirse como ModelAdmin
atributos, por ejemplo book__author_verbose_name = 'Author name'
y category__is_new_boolean = True
.
El atributo callable admin_order_field
está definido automática.
No olvide usar el atributo list_select_related en su ModelAdmin
para hacer que Django evite consultas adicionales.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-12 03:42:30
Hay un paquete muy fácil de usar disponible en PyPI que maneja exactamente eso: django-related-admin. También puedes ver el código en GitHub.
Usando esto, lo que quieres lograr es tan simple como:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
Ambos enlaces contienen detalles completos de la instalación y el uso, por lo que no los pegaré aquí en caso de que cambien.
Como nota al margen, si ya estás usando algo que no sea model.Admin
(por ejemplo, estaba usando SimpleHistoryAdmin
en su lugar), puedes hacer esto: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-28 10:30:55
La respuesta de AlexRobbins funcionó para mí, excepto que las dos primeras líneas deben estar en el modelo (¿quizás se asumió esto?), y debe hacer referencia a sí mismo:
def book_author(self):
return self.book.author
Entonces la parte de administración funciona muy bien.
Prefiero esto:
class CoolAdmin(admin.ModelAdmin):
list_display = ('pk', 'submodel__field')
@staticmethod
def submodel__field(obj):
return obj.submodel.field
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 14:48:41