queryset list_display foreign filter_horizontal custom changelist_view python django django-admin modeladmin

python - filter_horizontal - ¿Puede "list_display" en un Django ModelAdmin mostrar los atributos de los campos ForeignKey?



django changelist_view (13)

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.

modelos.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 (Modo incorrecto) : cree que funcionaría utilizando ''model__field'' como referencia, pero no funciona

class BookAdmin(admin.ModelAdmin): model = Book list_display = [''title'', ''author__name'', ] admin.site.register(Book, BookAdmin)

admin.py (Modo correcto) : así es como usted hace referencia a un nombre de clave externa al estilo 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 referencia adicional, vea el enlace del modelo Django here

Tengo un modelo de persona que tiene una relación de clave externa con el libro. El libro tiene una serie de campos, pero me preocupa más el "autor" (un CharField estándar).

Dicho esto, en mi modelo PersonAdmin, me gustaría mostrar "book.author" usando "list_display". He intentado 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'',]


Acabo de publicar un fragmento que hace que admin.ModelAdmin soporte la sintaxis ''__'':

http://djangosnippets.org/snippets/2887/

Así que puedes hacer:

class PersonAdmin(RelatedFieldAdmin): list_display = [''book__author'',]

Básicamente, se trata de hacer lo mismo que se describe en las otras respuestas, pero se ocupa automáticamente de (1) configurar admin_order_field (2) configurar short_description y (3) modificar el queryset para evitar un golpe de base de datos para cada fila.


Como el resto, fui con callables también. Pero tienen un inconveniente: de forma predeterminada, no puede ordenarlos. Afortunadamente, hay una solución para eso:

def author(self): return self.book.author author.admin_order_field = ''book__author''


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''



Este ya está aceptado, pero si hay otros tontos por ahí (como yo) que no obtuvieron de inmediato la respuesta actualmente aceptada , aquí hay un poco más de detalles.

La clase modelo a la que hace referencia ForeignKey debe tener un método __unicode__ , 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.


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 todos los detalles de instalación y uso, por lo que no los pegaré aquí en caso de que cambien.

Solo como nota al margen, si ya está utilizando algo que no sea model.Admin (por ejemplo, yo estaba usando SimpleHistoryAdmin en SimpleHistoryAdmin lugar), puede hacer esto: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin) .


La respuesta de AlexRobbins funcionó para mí, excepto que las dos primeras líneas deben estar en el modelo (¿tal vez esto fue asumido?), Y deberían referirse a sí mismo:

def book_author(self): return self.book.author

Entonces la parte de administrador funciona muy bien.


Prefiero esto:

class CoolAdmin(admin.ModelAdmin): list_display = (''pk'', ''submodel__field'') @staticmethod def submodel__field(obj): return obj.submodel.field


Puede mostrar lo que quiera en la visualización de lista utilizando un llamador. Se vería así:

def book_author(object): return object.book.author class PersonAdmin(admin.ModelAdmin): list_display = [book_author,]


Si lo intentas en línea, no lo lograrás a menos que:

en tu 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


Si tiene una gran cantidad de 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 gist aquí

Los atributos especiales recuperables como boolean y short_description deben definirse como atributos ModelAdmin , por ejemplo, book__author_verbose_name = ''Author name'' y category__is_new_boolean = True .

El atributo admin_order_field se define automáticamente.

No olvide usar el atributo list_select_related en su ModelAdmin para hacer que Django evite consultas adicionales.


Tenga en cuenta que agregar la función get_author ralentizaría el list_display en el administrador, ya que 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.02ms (67 consultas duplicadas en admin)

Después: 6 consultas en 10.81ms.