Django中如何在values()中获取当前语言的翻译字段?
解决Django TranslatableModel.values()获取当前语言翻译的问题
问题原因
直接在values()中使用certificate_name会报错,因为该字段并非存储在Certificate主表中,而是在关联的翻译表内;使用translations__certificate_name会返回所有语言的翻译记录,导致同一证书实例重复出现。
解决方案
方法1:使用Subquery获取优先语言翻译
通过子查询优先匹配当前语言的翻译,无对应翻译时回退到指定语言,确保每个证书仅返回一条记录:
from django.db.models import OuterRef, Subquery from django.utils.translation import get_language # 获取当前语言和回退语言 current_lang = get_language() fallback_lang = "en" # 替换为你的实际回退语言 # 构造子查询:优先取当前语言,再取回退语言 translation_subquery = ( CertificateTranslation.objects.filter( master=OuterRef("pk"), language_code__in=[current_lang, fallback_lang] ) .order_by("-language_code") # 让当前语言结果排在前面,优先匹配 .values("certificate_name")[:1] ) # 主查询:通过annotate注入翻译字段,再用values提取所需字段 certificates_values_list = ( Certificate.objects.filter(enabled=True) .annotate(certificate_name=Subquery(translation_subquery)) .values("id", "type", "certificate_name") )
方法2:使用Case-When条件判断
通过条件注解实现语言优先级匹配,配合distinct去重:
from django.db.models import Case, When, F, Value from django.utils.translation import get_language from django.db import models current_lang = get_language() fallback_lang = "en" certificates_values_list = ( Certificate.objects.filter(enabled=True) .annotate( certificate_name=Case( # 优先匹配当前语言的翻译 When(translations__language_code=current_lang, then=F("translations__certificate_name")), # 无当前语言时使用回退语言 When(translations__language_code=fallback_lang, then=F("translations__certificate_name")), # 都无匹配时使用默认空值 default=Value(""), output_field=models.CharField(), ) ) .values("id", "type", "certificate_name") .distinct("id", "type", "certificate_name") )
说明
- 两种方法都能保证返回结果中每个证书仅出现一次,且优先使用当前语言翻译,无对应翻译时自动回退。
- 注意替换代码中的
fallback_lang为你项目实际配置的回退语言。
内容的提问来源于stack exchange,提问作者Hat hout
相关产品推荐
相关产品推荐

