Django中在views.py外部无法检测当前语言的问题解决求助
解决方案:动态在表单实例化时生成翻译后的国家选项
你的问题核心在于模块级别的代码在Django启动阶段就执行了,比如countries_handler.py里的arr_country = get_country(),这时候还没有任何请求,get_language()只能拿到默认的en,自然无法加载对应语言的翻译文件。我们需要把国家选项的生成逻辑移到请求处理阶段,也就是表单实例化的时候,这样才能获取当前请求的语言。
步骤1:重构countries_handler.py,让它支持传入语言参数
把原来模块级别的语言获取逻辑改成可传入参数的函数,这样调用者可以主动传入当前请求的语言:
from django.utils.translation import gettext_lazy as _ import importlib import json def readJson(filename): with open(filename, 'r', encoding="utf8") as fp: return json.load(fp) # 修改为接受language参数的函数,不再依赖模块加载时的语言 def get_country(language): filepath = 'myproj/static/data/countries_states_cities.json' all_data = readJson(filepath) all_countries = [('----', _("--- Select a Country ---"))] # 根据传入的语言导入对应的翻译文件 imp = importlib.import_module(f"countries.translations.countries_{language}") for x in all_data: y = (x['name'], imp.t_countries(x['name'])) all_countries.append(y) return all_countries
删除原来模块末尾的arr_country = get_country(),因为我们不再需要提前生成这个列表。
步骤2:修改forms.py,在表单初始化时动态生成选项
在表单的__init__方法中,获取当前请求的语言,然后调用重构后的get_country()生成翻译后的选项。注意要把request传递给表单,这样能拿到最准确的当前语言(LocaleMiddleware会把语言存在request.LANGUAGE_CODE中):
from django import forms from .models import Address from django.utils.translation import gettext_lazy as _, get_language from .countries_handler import get_country class AddressForm(forms.ModelForm): # 先设置一个默认的空选项,后面会动态覆盖 country = forms.ChoiceField( choices = [('----', _("--- Select a Country ---"))], required = False, label=_('Company Country Location'), widget=forms.Select(attrs={'class':'form-control', 'id': 'id_country'}), ) def __init__(self, *args, **kwargs): # 从参数中取出request(如果有的话),不要传给父类 self.request = kwargs.pop('request', None) # 先调用父类的初始化方法 super().__init__(*args, **kwargs) # 获取当前语言:优先用request里的LANGUAGE_CODE,备用get_language() current_lang = self.request.LANGUAGE_CODE if self.request else get_language() # 动态生成翻译后的国家选项并更新字段 self.fields['country'].choices = get_country(current_lang) def get_state_by_country(self, country): return return_state_by_country(country) def get_city_by_state(self, state): return return_city_by_state(state) class Meta: model = Address fields = ['country']
步骤3:修改视图,将request传递给表单
在创建表单实例时,把当前请求对象传进去,这样表单才能拿到正确的语言信息:
from django.shortcuts import render from .forms import AddressForm from django.utils.translation import get_language def load_form(request): # 把request作为参数传给表单 form = AddressForm(request=request) return render(request, 'countries/country_form.html', {'form':form, 'lang':get_language()})
为什么之前的方案无效?
你之前尝试在视图里传递arr_country给表单,但问题在于:
- 如果你还是在模块级别生成
arr_country,它依然是启动时的默认语言版本,不会随请求变化; - 表单的字段定义应该在类级别,或者在
__init__里正确修改字段属性,你之前的__init__写法没有正确覆盖字段的choices,反而可能破坏了表单的正常初始化流程。
验证一下
现在切换URL语言(比如/fr/countries/),表单会在每个请求到来时:
- 获取当前请求的语言(
fr); - 加载对应的
countries_fr.py翻译文件; - 动态生成法语的国家选项列表;
- 渲染到页面上。
这样就能实现语言切换时国家列表自动对应翻译的效果了。
内容的提问来源于stack exchange,提问作者ionecum
相关产品推荐
相关产品推荐

