Django自定义过滤器处理嵌套字典与对象属性
本文介绍在Django中,当视图传递包含嵌套字典及模型对象的复杂数据结构至模板时,如何通过自定义过滤器解决直接访问问题。通过定义get_key和get_attr两个过滤器,实现从字典中提取对象并获取其属性值,适用于处理深层嵌套数据场景。
问题背景与解决方案概述
在Django开发中,视图层(views)常需将包含字典结构的数据传递给模板(template)。若字典的值仍为字典,且内部键对应的值为模型对象,则无法直接在模板中通过键名取值或通过点号(.)访问对象属性。经过调研,采用自定义过滤器(filter)是解决此类复杂变量处理的有效方案。
视图层数据准备
首先,需在视图函数中准备需传递给模板的数据。以views.py中的index函数为例,该函数负责构建上下文数据。
其中,latest_article_list为Article对象的列表,存储了文章的ID、作者、发布时间及分类等详细信息。
dic['tag_list']被赋值为一个列表,用于存储文章的标签信息。
articles_info是一个列表,其元素为字典。值得注意的是,该字典中键'Article'对应的值并非普通变量,而是具体的Article对象实例。
以下是views.py中index函数的具体实现代码。
def index(request):
latest_article_list = Article.objects.query_by_time()
articles_info = []
dic = {}
for article in latest_article_list:
taginfo = Article.objects.get(id=article.id)
dic['tag_list'] = taginfo.tags.all()
dic['article'] = article;
articles_info.append(dic)
dic = {}
loginform = LoginForm()
context = {'articles_info':articles_info, 'loginform':loginform}
return render(request, 'index.html', context)
模板层数据引用挑战
接下来探讨在模板中如何正确引用视图传递过来的变量值。
在index.html模板中,首先通过循环遍历列表,从而获取每一个字典变量。
{% for article_info in articles_info %}
遍历articles_info后得到的article_info为一个字典。根据前述视图逻辑,该字典包含一个article对象和一个tag_list列表。
对于article_info这一字典变量,在标准模板语法中无法直接通过键名获取对应值,更无法直接访问Article对象中的ID、作者或发布时间等属性。为解决此限制,必须引入自定义过滤器。
自定义过滤器的创建与实现
第三步,创建自定义过滤器。
具体操作如下:在app目录下创建templagetags文件夹,并在该目录下新建__init__.py空文件以及过滤器文件articleinfo.py。
编辑articleinfo.py文件,添加两个自定义过滤器:get_key用于获取字典中指定键对应的值,get_attr用于获取Article对象中指定字段的值。
以下是articleinfo.py文件的代码实现。
from django import template
register = template.Library()
@register.filter
def get_key(d, key_name):
return d.get(key_name)
@register.filter
def get_attr(d, m):
if hasattr(d, m):
return getattr(d, m)
模板中过滤器的调用与使用
第四步,在模板中调用自定义过滤器以获取所需变量值。
在index.html中,首先需使用标签加载前述定义的过滤器文件articleinfo.py,随后在模板中调用这些过滤器。具体用法参考下方的index.html代码。
{% load articleinfo %}
以下index.html代码片段展示了变量使用部分,其中通过双重过滤器提取了所需变量。
例如在第4行代码中。
{{ article_info|get_key:"article"|get_attr:"id" }}
首先通过article_info|get_key:"article"获取字典中的article对象。由于模板语法不支持直接链式访问如{{ article_info|get_key:"article".id }},因此需通过双重过滤器链式调用来实现ID值的获取。
以下是index.html模板的完整代码示例。
{% for article_info in articles_info %}
<div class="row">
<article class="col-xs-12">
<h3><a id="article_title", href="/focus/{{ article_info|get_key:" rel="external nofollow" article"|get_attr:"id" }}">{{ article_info|get_key:"article"|get_attr:"title" }}</a></h3>
<div class="article_info">
<span class="">{{ article_info|get_key:"article"|get_attr:"author" }}</span>
<span class="">{{ article_info|get_key:"article"|get_attr:"create_time"|date:"Y-m-d H:i" }}</span>
</div>
<div class="category">
分类:
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class>{{ article_info|get_key:"article"|get_attr:"category" }}</a>
</div>
<div class="category">
标签:
{% for tag in article_info|get_key:"tag_list" %}
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{{ tag }}</a>
{% endfor %}
</div>
<p>{{ article_info|get_key:"article"|get_attr:"content"|truncatechars_html:80 | safe }}</p>
<p><button class="btn btn-default" onclick="window.location.href='/focus/{{ article_info|get_key:"article"|get_attr:"id" }}' ">Read More</button></p>
<ul class="list-inline">
<li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><span class="glyphicon glyphicon-comment"></span>{{ article_info|get_key:"article"|get_attr:"comment_num" }} Comments</a></li>
<li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><span class="glyphicon glyphicon-thumbs-up"></span>{{ article_info|get_key:"article"|get_attr:"like_num" }} Likes</a></li>
</ul>
</article>
</div>
<hr>
{% endfor %}
以上即为Django中利用自定义过滤器处理复杂嵌套变量数据的完整方法,供开发者参考与实践。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









