Domanda

Ho un modello Person che ha una relazione di chiave esterna con Book , che ha un numero di campi, ma sono molto preoccupato per autore (un CharField standard).

Detto questo, nel mio modello PersonAdmin , vorrei visualizzare book.author utilizzando list_display :

class PersonAdmin(admin.ModelAdmin):
    list_display = ['book.author',]

Ho provato tutti i metodi ovvi per farlo, ma nulla sembra funzionare.

Qualche suggerimento?

È stato utile?

Soluzione

Come altra opzione, puoi fare delle ricerche come:

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'

Altri suggerimenti

Nonostante tutte le grandi risposte di cui sopra e perché ero nuovo di Django, ero ancora bloccato. Ecco la mia spiegazione da una prospettiva molto nuova.

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 (Modo errato) - pensi che funzionerebbe usando 'model__field' come riferimento, ma non

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

admin.site.register(Book, BookAdmin)

admin.py (Modo corretto) : ecco come fai riferimento a un nome di chiave esterna nel modo 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)

Per ulteriori riferimenti, consultare il collegamento al modello Django qui

Come il resto, sono andato anche con i callable. Ma hanno un aspetto negativo: per impostazione predefinita, non puoi ordinarli. Fortunatamente, esiste una soluzione per questo:

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

Si noti che l'aggiunta della funzione get_author rallenterebbe la visualizzazione di listino nell'amministratore, perché mostrare ad ogni persona farebbe una query SQL.

Per evitare ciò, è necessario modificare il metodo get_queryset in PersonAdmin, ad esempio:

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

Prima: 73 query in 36.02ms (67 query duplicate in admin)

     

Dopo: 6 query in 10,81 ms

Secondo la documentazione, è possibile visualizzare solo la rappresentazione __unicode__ di un ForeignKey:

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

Sembra strano che non supporti il ??formato di stile 'book__author' che viene usato ovunque nell'API DB.

Si scopre che un biglietto per questa funzione , contrassegnato come Non risolto.

Puoi mostrare quello che vuoi nella visualizzazione elenco usando un callable. Sembrerebbe così:

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

class PersonAdmin(admin.ModelAdmin):
  list_display = [book_author,]

Ho appena pubblicato uno snippet che rende admin.ModelAdmin che supporta la sintassi '__':

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

Quindi puoi fare:

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

Questo in pratica sta facendo la stessa cosa descritta nelle altre risposte, ma si occupa automaticamente di (1) impostazione admin_order_field (2) impostazione short_description e (3) modifica del queryset per evitare un hit del database per ogni riga.

/ p>

Questo è già accettato, ma se ci sono altri manichini là fuori (come me) che non lo hanno immediatamente ricevuto dal risposta attualmente accettata , ecco qualche dettaglio in più.

La classe del modello a cui fa riferimento il ForeignKey deve contenere un metodo __unicode__ , come qui:

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

    def __unicode__(self):
        return self.name

Ciò ha fatto la differenza per me e dovrebbe applicarsi allo scenario sopra. Funziona su Django 1.0.2.

se lo provi in ??Inline, non riuscirai a meno che:

nel tuo inline:

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

nel tuo modello (MyModel):

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

    def localname(self):
        return self.localization.name

Se hai molti campi degli attributi di relazione da usare in list_display e non vuoi creare una funzione (ed i suoi attributi) per ognuno, una soluzione sporca ma semplice avrebbe la precedenza sul ModelAdmin installa il metodo __getattr__ , creando al volo i callable:

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

Come gist qui

Gli attributi speciali richiamabili come booleano e short_description devono essere definiti come attributi ModelAdmin , ad es. book__author_verbose_name = 'Nome autore' e category__is_new_boolean = True .

L'attributo admin_order_field richiamabile viene definito automaticamente.

Non dimenticare di usare list_select_related nell'attributo ModelAdmin per evitare che Django eviti le query adizionali.

Esiste un pacchetto molto facile da usare disponibile in PyPI che gestisce esattamente questo: django- correlate amministratore . Puoi anche vedere il codice in GitHub .

Usando questo, ciò che vuoi ottenere è semplice come:

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

Entrambi i collegamenti contengono tutti i dettagli dell'installazione e dell'utilizzo, quindi non li incollerò qui in caso di modifiche.

Proprio come una nota a margine, se stai già utilizzando qualcosa di diverso da model.Admin (ad es. stavo usando invece SimpleHistoryAdmin ), puoi farlo: < code> class MyAdmin (SimpleHistoryAdmin, RelatedFieldAdmin) .

La risposta di AlexRobbins ha funzionato per me, tranne per il fatto che le prime due righe devono essere nel modello (forse è stato ipotizzato?), e dovrebbe fare riferimento a sé:

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

Quindi la parte admin funziona bene.

Preferisco questo:

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

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top