Django模板如何使用变量查找字典值
- 2024-12-06 08:40:00
- admin 原创
- 129
问题描述:
mydict = {"key1":"value1", "key2":"value2"}
在 Django 模板中查找字典值的常规方法是{{ mydict.key1 }}
, {{ mydict.key2 }}
。如果键是循环变量怎么办?即:
{% for item in list %} # where item has an attribute NAME
{{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}
mydict.item.NAME
失败。如何修复?
解决方案 1:
编写自定义模板过滤器:
from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
(我使用.get
这样的方式来实现,如果键不存在,它就返回 none。如果你这样做,dictionary[key]
它就会引发一个KeyError
then。)
用法:
{{ mydict|get_item:item.NAME }}
解决方案 2:
在循环中从字典中获取键和值:
{% for key, value in mydict.items %}
{{ value }}
{% endfor %}
我发现这更容易阅读,并且避免了特殊编码的需要。无论如何,我通常需要循环内的键和值。
解决方案 3:
默认情况下您不能这样做。点是属性查找/键查找/切片的分隔符/触发器。
点在模板渲染中具有特殊含义。变量名中的点表示查找。具体来说,当模板系统在变量名中遇到点时,它会按以下顺序尝试以下查找:
字典查找。示例:foo["bar"]
属性查找。示例:foo.bar
列表索引查找。示例:foo[bar]
但是你可以创建一个过滤器来传递一个参数:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters
@register.filter(name='lookup')
def lookup(value, arg):
return value[arg]
{{ mydict|lookup:item.name }}
解决方案 4:
对于我来说,创建一个名为“我的应用程序”的python文件template_filters.py
,其中包含以下内容
# coding=utf-8
from django.template.base import Library
register = Library()
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
用法就像 culebrón 所说的那样:
{{ mydict|get_item:item.NAME }}
解决方案 5:
环境:Django 2.2
示例代码:
from django.template.defaulttags import register
@register.filter(name='lookup')
def lookup(value, arg):
return value.get(arg)
我把这段代码放在项目文件夹 portfoliomgr 中名为 template_filters.py 的文件中。
无论你将过滤器代码放在哪里,请确保该文件夹中有__init__.py
将该文件添加到 projectfolder/settings.py 文件中的 templates 部分中的 libraries 部分。对我来说,它是 portfoliomgr/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries':{
'template_filters': 'portfoliomgr.template_filters',
}
},
},
]
在你的 html 代码中加载库
{% load template_filters %}
解决方案 6:
我遇到过类似的情况。但是我使用了不同的解决方案。
在我的模型中,我创建了一个执行字典查找的属性。然后在模板中我使用该属性。
在我的模型中:-
@property
def state_(self):
""" Return the text of the state rather than an integer """
return self.STATE[self.state]
在我的模板中:-
The state is: {{ item.state_ }}
解决方案 7:
由于我无法评论,让我以答案的形式来做这件事:
以culebrón 的答案或Yuji 'Tomita' Tomita 的答案为基础,传递给函数的字典是字符串的形式,因此也许首先使用ast.literal_eval将字符串转换为字典,就像在本例中一样。
经过此编辑,代码应如下所示:
# code for custom template tag
@register.filter(name='lookup')
def lookup(value, arg):
value_dict = ast.literal_eval(value)
return value_dict.get(arg)
<!--template tag (in the template)-->
{{ mydict|lookup:item.name }}
解决方案 8:
11年后。
您可以将此文档用于 4.2 https://docs.djangoproject.com/en/4.2/howto/custom-template-tags/
视图.py
from django.template.defaultfilters import register
@register.simple_tag
def example_tag(var_1, var_2, *args, **kwargs):
args_1 = kwargs["args_1"]
args_2 = kwargs["args_2"]
return args_1+" "+ args_2
例子.html
{% example_tag variable_1 variable_2 args_1="hi" args_2="hello" %}
输出
hi hello
解决方案 9:
接受的答案很好,但我只想添加如何使用过滤器链深入研究嵌套值
mydict = {"USD": { "amount": 30 }, "JPY": { "amount": 3000 }}
currency = "JPY"
{{ mydict|get_item:currency|get_item:"amount" }}
输出将是3000
解决方案 10:
请不要。Django 尚未实现任意字典查找,但有充分的理由。
不这样做的主要原因是模板中需要这种逻辑的逻辑通常是业务逻辑。这种逻辑不属于模板,而应该移至视图。
另一个问题是 Django 的模板引擎效率不高:它需要大量的上下文解析和渲染逻辑,这意味着这样的字典查找不是“免费的”,这些会减慢渲染速度,特别是在循环中完成时。
通常它还需要解析作为键的变量,这会使调试更加棘手,因为上下文解析的结果可能不是人们所期望的。例如,如果未找到变量,它将使用值string_if_invalid
[ Django-doc],这本身并不是人们想要的,因此该行为可能会产生结果,但却是错误的结果。
最后,如果发生错误,则会使调试变得更加困难,并且如果出现问题,则可能会将其默默传递,而如果出现故障,通常最好至少在某处记录它。
如果你需要执行任意下标或属性查找,这意味着你应该将逻辑从模板移到视图。实际上,在这种情况下,你可以在视图中准备数据,例如这里:
def my_view(request):
my_list = ['key2']
my_dict = {'key1': 'value1', 'key2': 'value2'}
result = [my_dict[k] for k in my_list]
return render(request, 'name-of-template.html', {'result': result})
然后在模板中处理,而不是带有和的result
逻辑。my_dict
my_list
解决方案 11:
如果您的字典有一组固定的键,那么 Python 相对较新的数据类提供了一种优雅的方法来做到这一点。
为你的字典创建一个数据类
@dataclass
class MyObject:
key_1: str
key_2: str
然后在将字典传递给模板之前对其进行变形。因此可能在 get_conetxt_data() 中。
context.update({"mydict" :MyObject(**mydict)})
然后您就可以在模板中使用点符号访问值。
{{ mydict.key_1 }}
解决方案 12:
环境:django 2.1.7
看法:
dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})
模板:
{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>