Django模板标签测试中自定义设置无法生效问题排查
嘿,这个问题我之前也踩过坑!核心原因是模块级变量只会在Django启动/模块加载时初始化一次,后续修改settings根本不会更新它。
你看,你的DPS_TEMPLATE_TRUE_DEFAULT是定义在模板标签模块的顶级作用域里的,当Django加载这个模板标签模块时,getattr(settings, ...)就执行了,把值固定成了默认的"True"。之后不管你怎么修改settings(哪怕用override_settings或者pytest的settings fixture),这个变量都不会重新读取settings的值——因为它早就初始化完了。
更坑的是,你之前尝试把getattr移到函数默认参数里也没用,因为Python的函数默认参数是在函数定义时计算的,而不是每次调用函数时。所以哪怕你写成def get_var(name, rit=getattr(settings, ...), ...):,这个默认值还是只会计算一次,后续settings变化也不会生效。
要解决这个问题,你需要把settings的读取逻辑移到函数体内部,每次调用模板标签时都去读取最新的settings值。这里有个优雅的写法,用哨兵值(比如None)作为默认参数,然后在函数里判断并动态获取:
# other imports from django.conf import settings from django import template register = template.Library() @register.simple_tag(name="var") def get_var(name, rit=None, rif="False", rin=""): """ A template tag to render value of a variable. """ _LOGGER.debug("Rendering value for `%s`...", name) # 动态读取settings,每次调用都获取最新值 if rit is None: rit = getattr(settings, "DPS_TEMPLATE_TRUE_DEFAULT", "True") variable = models.Variable.objects.get(name=name) value = variable.value if value is None: return rin if isinstance(value, bool): if value: return rit else: return rif return variable.value
这样修改后,每次调用{% var %}模板标签时,都会实时读取当前的settings.DPS_TEMPLATE_TRUE_DEFAULT值,你的测试里修改的settings就能生效了。
你的测试代码不需要大改,只要确保settings修改在模板渲染之前就行——pytest-django的settings fixture已经帮你做了这件事。运行测试后,应该能正确断言到"this is true by settings"的渲染结果。
另外,如果你之前硬编码settings.py没生效,也是因为模板标签模块早就加载了,改完settings后需要重启Django(或者测试进程)才能让模块重新加载。但用上面的动态读取方法,就再也不需要担心这个问题了。
内容的提问来源于stack exchange,提问作者Eray Erdin

