Django ModelAdmin中的“list_display”可以显示ForeignKey字段的属性吗?
我有一个与Book有外键关系的Person模型。 书有很多字段,但是我最关心的是“作者”(一个标准的CharField)。
据说,在我的PersonAdmin模型中,我想使用“list_display”显示“book.author”。 我已经尝试了所有明显的方法(见下文),但似乎没有任何工作。 有什么build议么?
class PersonAdmin(admin.ModelAdmin): list_display = ['book.author',]
作为另一种select,你可以看起来像:
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'
尽pipe上面有很多好的答案,并且由于我是Django的新手,但我还是陷入了困境。 这是我从一个非常新的angular度的解释。
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模型链接
和其余的一样,我也带着可卡因。 但他们有一个缺点:默认情况下,你不能在他们的订单。 幸运的是,有一个解决scheme:
def author(self): return self.book.author author.admin_order_field = 'book__author'
根据文档,您只能显示ForeignKey的__unicode__
表示forms:
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-display
奇怪的是,它不支持在DB API中使用的'book__author'
风格的格式。
原来有这个function的票证 ,标记为不会修复。
请注意,添加get_author
函数会减慢pipe理中的list_display,因为显示每个人都会进行SQL查询。
为了避免这种情况,您需要修改get_queryset
方法,例如:
def get_queryset(self, request): return super(PersonAdmin,self).get_queryset(request).select_related('book')
之前:在36.02ms内查询73次(在pipe理员中重复查询67次)
之后:10.81ms内的6个查询
您可以通过使用可调用的函数来显示列表显示中的任何内容。 它看起来像这样:
def book_author(object): 返回object.book.author class PersonAdmin(admin.ModelAdmin): list_display = [book_author,]
我刚刚发布了一个使admin.ModelAdmin支持'__'语法的代码片段:
http://djangosnippets.org/snippets/2887/
所以你可以这样做:
class PersonAdmin(RelatedFieldAdmin): list_display = ['book__author',]
这基本上只是做与其他答案中描述的相同的事情,但它会自动处理(1)设置admin_order_field(2)设置short_description和(3)修改查询集,以避免每行的数据库命中。
这个已经被接受了,但是如果还有其他的傻子(像我一样)没有立即从目前接受的答案中得到它,这里有一些细节。
由ForeignKey
引用的模型类需要在其中有一个__unicode__
方法,如下所示:
class Category(models.Model): name = models.CharField(max_length=50) def __unicode__(self): return self.name
这对我有所帮助,应该适用于上述情况。 这适用于Django 1.0.2。
PyPI中有一个非常易于使用的软件包,可以完全处理: django-related-admin 。 你也可以在GitHub中看到代码 。
使用这个,你想要达到的是如此简单:
class PersonAdmin(RelatedFieldAdmin): list_display = ['book__author',]
这两个链接都包含完整的安装和使用的细节,所以我不会在这里粘贴他们的情况下,他们改变。
正如一个侧面说明,如果你已经使用的东西比model.Admin
(例如我使用SimpleHistoryAdmin
代替),你可以这样做: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)
。
如果你在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
如果在list_display
使用了很多关系属性字段,并且不想为每个属性创build一个函数(以及它的属性),那么一个简单而又简单的解决scheme将会覆盖ModelAdmin
实例__getattr__
方法,从而快速创build可调用对象:
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
作为这里的主旨
像boolean
和short_description
这样可调用的ModelAdmin
属性必须被定义为ModelAdmin
属性,例如book__author_verbose_name = 'Author name'
和category__is_new_boolean = True
。
可调用的admin_order_field
属性是自动定义的。
不要忘记在你的ModelAdmin
使用list_select_related属性来使Django避免附加查询。
AlexRobbins的答案对我很有帮助,只是前两行需要在模型中(也许这是假定的),并且应该引用self:
def book_author(self): return self.book.author
然后pipe理部分很好地工作。
我更喜欢这个:
class CoolAdmin(admin.ModelAdmin): list_display = ('pk', 'submodel__field') @staticmethod def submodel__field(obj): return obj.submodel.field