2008-10-02 6 views
189

У меня есть модель Person, которая имеет отношение внешних ключей к книге. Книга имеет несколько полей, но меня больше всего беспокоит «автор» (стандартный CharField).Может ли «list_display» в атрибутах отображения Django ModelAdmin полей ForeignKey?

С учетом сказанного, в моей модели PersonAdmin, я хотел бы отобразить «book.author», используя «list_display». Я пробовал все очевидные методы для этого (см. Ниже), но ничего не работает. Какие-либо предложения?

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

ответ

319

В качестве другого варианта, вы можете сделать внешний вид окна, как:

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

Должен ли get_author быть 'get_reviews'? – Huuuze 2008-10-04 20:50:06

+1

whoops, nice catch! – imjoevasquez 2008-10-05 10:47:07

+0

Не должны оба быть `get_author`, так как это то, возвращаемое (и краткое описание) на самом деле ссылается? Или изменить аргумент форматирования строки на `obj.book.reviews`? – 2012-06-20 19:12:33

19

Согласно документации, вы можете отобразить только __unicode__ представление ForeignKey:

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

кажется странным, что он не поддерживает формат 'book__author' стиль, который используется везде в API БД.

Оказывается, есть a ticket for this feature, который отмечен как «Не исправить».

+2

`book__author`works действительно. (Django 1.2) – Mermoz 2010-11-01 16:45:20

+11

@Mermoz действительно? Кажется, билет остается установленным как wontfix. Он, похоже, не работает (Django 1.3) – 2012-06-04 23:16:31

+0

@Mermoz Even в 1.10.x он не работает. – 2016-11-18 13:36:26

5

Это один уже принято, но если есть какие-либо другие манекены там (как я), что не сразу получить его от presently accepted answer , вот немного более подробно.

Класс модели ссылается на ForeignKey потребности иметь метод __unicode__ в нем, как здесь:

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

    def __unicode__(self): 
     return self.name 

Это сделал разницу для меня, и должно применяться к вышеуказанному сценарию. Это работает на Django 1.0.2.

9

Вы можете показать все, что хотите, в отображении списка с помощью вызываемого. Это будет выглядеть следующим образом:

 

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

class PersonAdmin(admin.ModelAdmin): 
    list_display = [book_author,]
ответ
-1

AlexRobbins' работал для меня, за исключением того, что первые две строки должны быть в модели (возможно, это предполагалось?), И должны ссылаться на себя:

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

Затем часть администратора работает красиво.

56

Как и все остальное, я тоже пошел с вызывающими. Но у них есть один недостаток: по умолчанию вы не можете заказать их. К счастью, есть решение для этого:

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

Я просто разместил сниппет, что делает поддержку admin.ModelAdmin '__' синтаксис:

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

Так что вы можете сделать:

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

Это в основном просто то же самое, что описано в других ответах, но оно автоматически заботится о настройке (1) admin_order_field (2) установки short_descriptio n и (3) изменение набора запросов, чтобы избежать попадания базы данных для каждой строки.

2

, если вы попробуете его в Inline, вы не получится, если только:

в вашем инлайн:

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

в модели (MyModel):

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

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

Несмотря на все большие ответы выше и из-за того, что я новичок в Django, я все еще застрял. Вот мое объяснение с точки зрения новичка.

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 (неверный способ) - Вы думаете, что это будет работать, используя 'model__field' для справки, но это не

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

admin.site.register(Book, BookAdmin) 

admin.py (правильный путь) - так вы ссылаетесь на имя внешнего ключа, способ 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) 

Для получения дополнительной справки см модели ссылка Джанго here

18

Пожалуйста, обратите внимание, что добавление функции get_author замедлит list_display в админке, потому что показ каждого человека будет сделать запрос SQL.

Чтобы избежать этого, необходимо изменить get_queryset метод в PersonAdmin, например:

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

Before: 73 queries in 36.02ms (67 duplicated queries in admin)

After: 6 queries in 10.81ms

1

Если у вас есть много относительно атрибутов полей для использования в list_display и не хотите создать функцию (и это атрибуты) для каждого из них, грязей, но простое решение будет переопределить ModelAdmin instace __getattr__ метода, создавая на вызываемые объекты лета:

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 

Как gist here

Вызываемые особенные атрибуты, такие как boolean и short_description должны быть определены как ModelAdmin атрибутов, например book__author_verbose_name = 'Author name' и category__is_new_boolean = True.

Атрибут вызываемого admin_order_field определяется автоматически.

Не забудьте использовать атрибут list_select_related в своем ModelAdmin, чтобы Django избегал дополнительных запросов.

4

В PyPI есть очень простой в использовании пакет, который обрабатывает именно это: django-related-admin. Вы также можете see the code in GitHub.

Используя это, что вы хотите достичь, это так просто, как:

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

Обе ссылки содержат полную информацию об установке и использовании, так что я не буду вставлять их здесь в случае, если они изменяются.

Как примечание, если вы уже используете что-то отличное от model.Admin (например, я использовал SimpleHistoryAdmin), вы можете сделать это: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin).

-3

Я предпочитаю это:

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

    @staticmethod 
    def submodel__field(obj): 
     return obj.submodel.field 

 Смежные вопросы

  • Нет связанных вопросов^_^