如何在Django Admin的list_display中引用反向外键关联?
问题
我的应用需随时支持新增语言或方言,不同语言/方言的文本需互译,因此将不同语言文本关联为“文本组”(即多语言翻译集合),模型定义如下:
class StringFamily(models.Model): id = models.AutoField(primary_key=True) # plus some other fields class String(models.Model): id = models.AutoField(primary_key=True) # the reference to StringFamily family = models.ForeignKey(StringFamily, null=False, on_delete=models.CASCADE) # other important stuff language = models.ForeignKey(Language, on_delete=models.DO_NOTHING) dialect = models.ForeignKey(Dialect, null=True, on_delete=models.SET_NULL) text = models.TextField(null=False)
现有Element模型关联StringFamily:
class Element(models.Model): id = models.AutoField(primary_key=True) element_role = models.ForeignKey(ElementRole, null=False, on_delete=models.RESTRICT) string_family = models.ForeignKey(StringFamily, null=True, on_delete=models.SET_NULL) # plus more fields
希望在ElementAdmin的list_display中添加display_english_string字段展示英文文本,尝试代码如下:
class Element(models.Model): # first above code, then... def display_english_string(self) -> str: strings = self.string_family.strings # this is the reference I would like to work but doesn't english_string = strings.filter(language="eng").values("text")[0] return english_string display_english_string.short_description = 'English Text'
运行报错:AttributeError: 'StringFamily' object has no attribute 'string',请问如何实现该需求?
解决方案
1. 修正反向关联名称
Django外键的默认反向关联名称为模型名小写_set,String模型的外键指向StringFamily,所以正确的反向关联属性是string_set,而非自定义的strings。
2. 处理空值与异常
需考虑string_family为空、找不到对应英文文本的情况,避免抛出异常:
class Element(models.Model): # 原有模型代码... def display_english_string(self) -> str: if not self.string_family: return "-" # 使用正确的反向关联获取String集合 english_entry = self.string_family.string_set.filter(language__code="eng").first() return english_entry.text if english_entry else "-" display_english_string.short_description = 'English Text'
注:假设Language模型用
code字段存储语言标识(如"eng"),若使用名称字段匹配,改为language__name="English"即可。
3. 优化Admin查询性能(可选)
当Element列表数据量较大时,每次调用方法会触发额外数据库查询,可通过prefetch_related预加载关联数据提升性能:
from django.contrib import admin class ElementAdmin(admin.ModelAdmin): list_display = ['id', 'element_role', 'display_english_string'] def get_queryset(self, request): qs = super().get_queryset(request) # 预加载关联的StringFamily和对应的String对象 qs = qs.prefetch_related('string_family', 'string_family__string_set') return qs
内容的提问来源于stack exchange,提问作者stasp
相关产品推荐
相关产品推荐

