Django Admin含多个同模型外键的模型无法显示关联属性如何解决
错误成因
Django Admin 的 list_display 配置项本身不支持直接使用双下划线__的跨模型关联查询语法,你之前在单个外键场景下的正常生效属于误记,大概率是之前的场景中额外定义了对应的属性/方法才支持了该写法。
Django 在校验list_display的取值时,只会检查三类目标:当前TypeAdmin类的属性/方法、Type模型的属性/方法、可调用对象,icon1__name不属于上述三类,因此直接抛出admin.E108错误。
修复方案
有两种常用的修复方式,都可以兼容外键为空的场景:
方案1:在ModelAdmin中自定义展示方法(推荐)
直接在TypeAdmin类中定义获取关联图标名称的方法,同时处理空值情况:
class TypeAdmin(admin.ModelAdmin): list_display = ( 'name', 'get_icon1_name', 'get_icon2_name', 'get_icon3_name', 'modified_date', 'creation_date', 'id' ) # 联表提前查询关联Icon,避免N+1查询问题 list_select_related = ('icon1', 'icon2', 'icon3') def get_icon1_name(self, obj): # 外键为空时返回横杠占位 return obj.icon1.name if obj.icon1 else '-' # 自定义列表页的列头显示名称 get_icon1_name.short_description = '图标1名称' def get_icon2_name(self, obj): return obj.icon2.name if obj.icon2 else '-' get_icon2_name.short_description = '图标2名称' def get_icon3_name(self, obj): return obj.icon3.name if obj.icon3 else '-' get_icon3_name.short_description = '图标3名称' admin.site.register(models.Type, TypeAdmin)
方案2:在Type模型中定义关联属性
如果需要在Admin之外的场景也能直接获取图标名称,可以把属性定义在Type模型中:
首先修改models.py的Type类:
class Type(models.Model): name = models.CharField(max_length=60) modified_date = models.DateTimeField(auto_now=True) creation_date = models.DateTimeField(auto_now_add=True) icon1 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon1") icon2 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon2") icon3 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon3") def __str__(self): return self.name @property def icon1_name(self): return self.icon1.name if self.icon1 else '-' @property def icon2_name(self): return self.icon2.name if self.icon2 else '-' @property def icon3_name(self): return self.icon3.name if self.icon3 else '-'
之后修改admin.py的list_display配置即可:
class TypeAdmin(admin.ModelAdmin): list_display = ( 'name', 'icon1_name', 'icon2_name', 'icon3_name', 'modified_date', 'creation_date', 'id' ) list_select_related = ('icon1', 'icon2', 'icon3')
内容的提问来源于stack exchange,提问作者DDCA567
相关产品推荐
相关产品推荐

