关于python:可以在django modeladmin中”list-display”显示foreignkey字段的属性吗?

Can “list_display” in a Django ModelAdmin display attributes of ForeignKey fields?

我有一个Person模型,它与Book有一个外键关系,它有许多字段,但我最关心的是author(标准字符字段)。

尽管如此,在我的PersonAdmin模型中,我想使用list_display显示book.author

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

我已经尝试过所有显而易见的方法,但似乎没有任何效果。

有什么建议吗?


作为另一种选择,您可以进行如下查找:

1
2
3
4
5
6
7
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'


尽管上面所有的答案都很好,而且由于我是刚到姜哥的人,我还是被困住了。这是我从一个新手的角度来解释的。

模特儿

1
2
3
4
5
6
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_uu field"来引用,但它不能

1
2
3
4
5
class BookAdmin(admin.ModelAdmin):
    model = Book
    list_display = ['title', 'author__name', ]

admin.site.register(Book, BookAdmin)

admin.py(正确的方式)-这是如何引用外键名django方式

1
2
3
4
5
6
7
8
9
10
11
12
13
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)

有关其他参考,请参见此处的django model链接


和其他人一样,我也带着可卡因去了。但它们有一个缺点:默认情况下,您不能订购它们。幸运的是,有一个解决方案:

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

请注意,添加get_author函数会减慢管理员中的列表显示速度,因为显示每个人都会进行SQL查询。

为了避免这种情况,您需要在Personadmin中修改get_queryset方法,例如:

1
2
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


根据文档,您只能显示foreignkey的__unicode__表示:

http://docs.djangoproject.com/en/dev/ref/contrib/admin/列表显示

奇怪的是,它不支持DBAPI中其他地方使用的'book__author'样式的格式。

结果发现有一张关于此功能的罚单,标记为"无法修复"。


我刚刚发布了一个代码片段,它使admin.modeladmin支持"uuuuu"语法:

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

所以你可以这样做:

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

这基本上是在做其他答案中描述的相同的事情,但它自动处理(1)设置管理顺序字段(2)设置简短描述和(3)修改查询集以避免每行的数据库命中。


您可以使用Callable在列表显示中显示您想要的任何内容。如下所示:

1
2
3
4
5
def book_author(object):
  return object.book.author

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


这一个已经被接受了,但是如果有其他的傻瓜(像我一样)没有立即从目前接受的答案中得到答案,这里有更多的细节。

ForeignKey引用的模型类需要在其中包含一个__unicode__方法,如下所示:

1
2
3
4
5
class Category(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

这对我来说是不同的,应该适用于上面的场景。这在Django 1.0.2上工作。


如果您在list_display中有许多关系属性字段要使用,并且不想为每个字段创建函数(及其属性),那么一个简单而肮脏的解决方案将覆盖ModelAdmin实例__getattr__方法,动态创建可调用文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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

这里是要点

可调用的特殊属性,如booleanshort_description必须定义为ModelAdmin属性,如book__author_verbose_name = 'Author name'category__is_new_boolean = True

可调用的admin_order_field属性是自动定义的。

不要忘记使用ModelAdmin中的list-select-relevant属性,使django避免其他查询。


如果您在内联中进行尝试,则不会成功,除非:

在你的内联:

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

在您的模型(MyModel)中:

1
2
3
4
5
class MyModel(models.Model):
    localization = models.ForeignKey(Localizations)

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

Pypi中有一个非常容易使用的包,它可以精确地处理这个问题:django相关的管理。您还可以在GitHub中看到代码。

使用此功能,您想要实现的简单方法如下:

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

这两个链接都包含安装和使用的完整详细信息,因此我不会将它们粘贴到此处以防更改。

作为旁注,如果你已经在使用除model.Admin以外的东西(例如我使用SimpleHistoryAdmin),你可以这样做:class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)


亚历克斯罗宾斯的回答对我很有效,只是前两行需要在模型中(也许这是假设的?),并应参考自身:

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

然后管理部分工作得很好。


我更喜欢这个:

1
2
3
4
5
6
class CoolAdmin(admin.ModelAdmin):
    list_display = ('pk', 'submodel__field')

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