Pode "list_display" em um Django ModelAdmin atributos de campos ForeignKey de exibição?

votos
198

Eu tenho um modelo Pessoa que tem uma relação de chave estrangeira para reservar. Livro tem um número de campos, mas eu estou mais preocupado com o autor (a CharField standard).

Com isso dito, no meu modelo PersonAdmin, eu gostaria de exibir book.author usando list_display. Eu tentei todos os métodos óbvios para fazê-lo (veja abaixo), mas nada parece funcionar. Alguma sugestão?

class PersonAdmin(admin.ModelAdmin):
  list_display = ['book.author',]
Publicado 02/10/2008 em 19:26
fonte usuário
Em outras línguas...                            


13 respostas

votos
341

Como outra opção, você pode fazer ups olhar 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'
Respondeu 02/10/2008 em 22:11
fonte usuário

votos
84

Apesar de todas as grandes respostas acima e devido a eu ser novo para Django, eu ainda estava preso. Aqui está a minha explicação de uma perspectiva muito novato.

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 (Caminho incorreto) - Você acha que ele iria trabalhar usando 'model__field' para referência, mas isso não acontece

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

admin.site.register(Book, BookAdmin)

admin.py (maneira correta) - esta é a forma como você faz referência a um nome de chave estrangeira a maneira 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 referência adicionais, consulte o link modelo Django aqui

Respondeu 19/05/2014 em 22:55
fonte usuário

votos
57

Como o resto, eu fui com chamáveis ​​também. Mas eles têm uma desvantagem: por padrão, você não pode ordenar sobre eles. Felizmente, há uma solução para isso:

def author(self):
    return self.book.author
author.admin_order_field  = 'book__author'
Respondeu 28/07/2010 em 10:13
fonte usuário

votos
19

Por favor, note que a adição da get_authorfunção seria retardar o list_display na administração, porque mostrando cada pessoa iria fazer uma consulta SQL.

Para evitar isso, é necessário modificar get_querysetmétodo em PersonAdmin, por exemplo:

def get_queryset(self, request):
    return super(PersonAdmin,self).get_queryset(request).select_related('book')

Antes: 73 consultas em 36.02ms (67 consultas duplicadas em admin)

Depois: 6 consultas em 10.81ms

Respondeu 28/01/2015 em 11:20
fonte usuário

votos
19

De acordo com a documentação, você só pode exibir a __unicode__representação de um ForeignKey:

http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-display

Parece estranho que ele não suporta o 'book__author'formato de estilo que é usado no resto do API DB.

Acontece que há um bilhete para este recurso , que é marcada como não fixará.

Respondeu 02/10/2008 em 19:53
fonte usuário

votos
10

Você pode mostrar o que quiser na visualização da lista usando um exigível. Ele ficaria assim:


BOOK_AUTHOR def (objecto):
  voltar object.book.author

classe PersonAdmin (admin.ModelAdmin):
  list_display = [BOOK_AUTHOR,]
Respondeu 30/01/2009 em 18:41
fonte usuário

votos
9

Acabei de publicar um trecho que faz suporte admin.ModelAdmin '__' sintaxe:

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

Então você pode fazer:

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

Isto é, basicamente, apenas fazendo a mesma coisa descrito em outras respostas, mas ele automaticamente cuida de (1) definindo admin_order_field (2) definindo short_description e (3) modificar o queryset para evitar um golpe de banco de dados para cada linha.

Respondeu 03/02/2013 em 22:21
fonte usuário

votos
5

Este já é aceito, mas se houver quaisquer outros manequins lá fora (como eu) que não obtê-lo imediatamente a partir da resposta atualmente aceita , aqui está um pouco mais detalhadamente.

A classe modelo referenciado pelas ForeignKeynecessidades de ter um __unicode__método dentro dela, como aqui:

class Category(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

Que fez a diferença para mim, e deve aplicar-se o cenário acima. Isso funciona em Django 1.0.2.

Respondeu 24/01/2009 em 00:40
fonte usuário

votos
4

Há um muito fácil de usar pacote disponível no PyPI que trata exatamente isso: -admin relacionados com o Django . Você também pode ver o código no GitHub .

Usando isso, o que você quer alcançar é tão simples como:

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

Ambos os links incluir informações completas sobre a instalação e uso por isso não vou colá-los aqui no caso de eles mudam.

Assim como uma nota lateral, se você já estiver usando algo diferente model.Admin(por exemplo, eu estava usando SimpleHistoryAdminem seu lugar), você pode fazer isso: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin).

Respondeu 28/05/2016 em 10:30
fonte usuário

votos
3

se você tentar isso em inline, você não vai ter sucesso a menos que:

em sua linha:

class AddInline(admin.TabularInline):
    readonly_fields = ['localname',]
    model = MyModel
    fields = ('localname',)

no seu modelo (MyModel):

class MyModel(models.Model):
    localization = models.ForeignKey(Localizations)

    def localname(self):
        return self.localization.name
Respondeu 30/01/2014 em 13:30
fonte usuário

votos
2

Se você tem um monte de relação campos de atributo para usar em list_displaye não quero criar uma função (e é atributos) para cada um, a sujeira, mas solução simples seria substituir o ModelAdmininstace __getattr__método, criando as funções chamáveis na mosca:

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 essência aqui

Atributos especiais que pode ser chamado gosto booleane short_descriptiondeve ser definida como ModelAdminatributos, por exemplo, book__author_verbose_name = 'Author name'e category__is_new_boolean = True.

O que pode ser chamado admin_order_fieldatributo é definido automaticamente.

Não se esqueça de usar o list_select_related atributo no seu ModelAdminfazer Django evitar consultas adicionais.

Respondeu 12/01/2016 em 03:42
fonte usuário

votos
-1

resposta AlexRobbins' trabalhou para mim, exceto que as duas primeiras linhas precisam estar no modelo (talvez isso foi assumido?), e deve fazer referência a si mesmo:

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

Em seguida, a parte de administração funciona muito bem.

Respondeu 25/03/2009 em 01:27
fonte usuário

votos
-3

Eu prefiro isso:

class CoolAdmin(admin.ModelAdmin):
    list_display = ('pk', 'submodel__field')

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
Respondeu 22/09/2016 em 14:48
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more