可以“list_display” 在 Django ModelAdmin 中显示外键字段的属性?

发布于 2024-07-07 07:45:50 字数 381 浏览 10 评论 0原文

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

话虽这么说,在我的 PersonAdmin 模型中,我想使用 list_display 显示 book.author

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

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

有什么建议么?

I have a Person model that has a foreign key relationship to Book, which has a number of fields, but I'm most concerned about author (a standard CharField).

With that being said, in my PersonAdmin model, I'd like to display book.author using list_display:

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

I've tried all of the obvious methods for doing so, but nothing seems to work.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

猫九 2024-07-14 07:45:50

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

#models.py
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'

对于 Django 3.2 或更高版本,请参阅此答案

As another option, you can do lookups like:

#models.py
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'

For Django 3.2 or higher, please refer to this answer

枕花眠 2024-07-14 07:45:50

尽管上面有很多很好的答案,并且由于我是 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)

有关其他参考,请参阅 Django 模型链接 此处

Despite all the great answers above and due to me being new to Django, I was still stuck. Here's my explanation from a very newbie perspective.

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 (Incorrect Way) - you think it would work by using 'model__field' to reference, but it doesn't

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

admin.site.register(Book, BookAdmin)

admin.py (Correct Way) - this is how you reference a foreign key name the Django way

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)

For additional reference, see the Django model link here

离线来电— 2024-07-14 07:45:50

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

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

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

之前:36.02 毫秒内 73 个查询(管理中 67 个重复查询)

之后:10.81 毫秒内 6 次查询

Please note that adding the get_author function would slow the list_display in the admin, because showing each person would make a SQL query.

To avoid this, you need to modify get_queryset method in PersonAdmin, for example:

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

蓝礼 2024-07-14 07:45:50

和其他人一样,我也选择了可调用的。 但它们有一个缺点:默认情况下,您无法订购它们。 幸运的是,有一个解决方案:

Django >= 1.8

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

Django < 1.8

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

Like the rest, I went with callables too. But they have one downside: by default, you can't order on them. Fortunately, there is a solution for that:

Django >= 1.8

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

Django < 1.8

def author(self):
    return self.book.author
author.admin_order_field  = 'book__author'
枉心 2024-07-14 07:45:50

对于 Django >= 3.2

使用 Django 3.2 或更高版本执行此操作的正确方法是使用 显示装饰器

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

    @admin.display(description='Author Name', ordering='author__name')
    def get_author_name(self, obj):
        return obj.author.name

For Django >= 3.2

The proper way to do it with Django 3.2 or higher is by using the display decorator

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

    @admin.display(description='Author Name', ordering='author__name')
    def get_author_name(self, obj):
        return obj.author.name
孤独陪着我 2024-07-14 07:45:50

根据文档,您只能显示外键的 __unicode__ 表示形式:

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

看起来很奇怪,它不支持 ' book__author' 样式格式在 DB API 中的其他任何地方都使用。

结果是此功能的票证,被标记为“无法修复”。

According to the documentation, you can only display the __unicode__ representation of a ForeignKey:

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

Seems odd that it doesn't support the 'book__author' style format which is used everywhere else in the DB API.

Turns out there's a ticket for this feature, which is marked as Won't Fix.

海之角 2024-07-14 07:45:50

我刚刚发布了一个片段,使 admin.ModelAdmin 支持 '__' 语法:

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

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

2887每行的数据库命中。

I just posted a snippet that makes admin.ModelAdmin support '__' syntax:

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

So you can do:

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

This is basically just doing the same thing described in the other answers, but it automatically takes care of (1) setting admin_order_field (2) setting short_description and (3) modifying the queryset to avoid a database hit for each row.

似梦非梦 2024-07-14 07:45:50

PyPI 中有一个非常易于使用的包可以完全处理这个问题: 。 您还可以查看 GitHub 中的代码

使用此功能,您想要实现的目标非常简单:

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

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

顺便说一句,如果您已经使用了 model.Admin 以外的其他内容(例如我使用的是 SimpleHistoryAdmin),您可以执行以下操作:class MyAdmin(SimpleHistoryAdmin,RelatedFieldAdmin)

There is a very easy to use package available in PyPI that handles exactly that: django-related-admin. You can also see the code in GitHub.

Using this, what you want to achieve is as simple as:

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

Both links contain full details of installation and usage so I won't paste them here in case they change.

Just as a side note, if you're already using something other than model.Admin (e.g. I was using SimpleHistoryAdmin instead), you can do this: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin).

苄①跕圉湢 2024-07-14 07:45:50

您可以使用可调用函数在列表显示中显示您想要的任何内容。 它看起来像这样:

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

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

You can show whatever you want in list display by using a callable. It would look like this:

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

class PersonAdmin(admin.ModelAdmin):
  list_display = [book_author,]
可遇━不可求 2024-07-14 07:45:50

如果您有很多关系属性字段要在 list_display 中使用,并且不想为每个字段创建一个函数(及其属性),那么一个肮脏但简单的解决方案将覆盖 ModelAdmin< /code> 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

要点< /a>

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

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

不要忘记使用 ModelAdmin 中的“list_select_lated”>list_select_lated 属性使 Django 避免额外的查询。

If you have a lot of relation attribute fields to use in list_display and do not want create a function (and it's attributes) for each one, a dirt but simple solution would be override the ModelAdmin instace __getattr__ method, creating the callables on the fly:

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

As gist here

Callable especial attributes like boolean and short_description must be defined as ModelAdmin attributes, eg book__author_verbose_name = 'Author name' and category__is_new_boolean = True.

The callable admin_order_field attribute is defined automatically.

Don't forget to use the list_select_related attribute in your ModelAdmin to make Django avoid aditional queries.

靖瑶 2024-07-14 07:45:50

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

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

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

    def __unicode__(self):
        return self.name

这对我来说很重要,并且应该适用于上述场景。 这适用于 Django 1.0.2。

This one's already accepted, but if there are any other dummies out there (like me) that didn't immediately get it from the presently accepted answer, here's a bit more detail.

The model class referenced by the ForeignKey needs to have a __unicode__ method within it, like here:

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

    def __unicode__(self):
        return self.name

That made the difference for me, and should apply to the above scenario. This works on Django 1.0.2.

污味仙女 2024-07-14 07:45:50

我可能会迟到,但这是另一种方法。 您可以简单地在模型中定义一个方法并通过 list_display 访问它,如下所示:

models.py

class Person(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)

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

admin.py

class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_book_author',)

但是这个和另一个上面提到的方法在列表视图页面的每行添加两个额外的查询。 为了优化这一点,我们可以重写 get_queryset 来注释必填字段,然后在 ModelAdmin 方法

admin.py中使用带注释的字段

from django.db.models.expressions import F

@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_author',)
    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(
            _author = F('book__author')
        )
        return queryset

    @admin.display(ordering='_author', description='Author')
    def get_author(self, obj):
        return obj._author

I may be late, but this is another way to do it. You can simply define a method in your model and access it via the list_display as below:

models.py

class Person(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)

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

admin.py

class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_book_author',)

But this and the other approaches mentioned above add two extra queries per row in your listview page. To optimize this, we can override the get_queryset to annotate the required field, then use the annotated field in our ModelAdmin method

admin.py

from django.db.models.expressions import F

@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ('get_author',)
    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(
            _author = F('book__author')
        )
        return queryset

    @admin.display(ordering='_author', description='Author')
    def get_author(self, obj):
        return obj._author
丢了幸福的猪 2024-07-14 07:45:50

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

在您的内联中:

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

if you try it in Inline, you wont succeed unless:

in your inline:

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

in your model (MyModel):

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

    def localname(self):
        return self.localization.name
相守太难 2024-07-14 07:45:50

AlexRobbins 的答案对我有用,除了前两行需要位于模型中(也许这是假设的?),并且应该引用 self:

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

然后管理部分就可以很好地工作。

AlexRobbins' answer worked for me, except that the first two lines need to be in the model (perhaps this was assumed?), and should reference self:

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

Then the admin part works nicely.

幻梦 2024-07-14 07:45:50

我更喜欢这个:

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

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

I prefer this:

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

    @staticmethod
    def submodel__field(obj):
        return obj.submodel.field
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文