用Django做一个简单的记账网站(九)自定义模板过滤器
已经能提交表单数据并保存账单了,于是需要在打开页面时请求账单历史记录的数据,并显示在页面上。
期望的是把账单按每一天来整合,并能显示汇总的收支信息,于是返回的数据就会有每日账单和每日收支,类似如下:
# 每日账单
{'2021-01-20': [<HistoryRecord: HistoryRecord object (16)>], '2021-01-19': [<HistoryRecord: HistoryRecord object (15)>], '2021-01-18': [<HistoryRecord: HistoryRecord object (14)>, <HistoryRecord: HistoryRecord object (13)>]}
# 每日收支
{'2021-01-20': {'income': 0, 'expense': Decimal('30.00')}, '2021-01-19': {'income': Decimal('450.12'), 'expense': 0}, '2021-01-18': {'income': 0, 'expense': Decimal('3018.00')}}
对于账单来说,可以通过for循环来显示在页面上,但收支每天只有一个,需要在循环日期时使用,在循环账单时不使用。
html的template就可以是如下:
{% for day, records in current_month_records.items %}
<div class="card" style="margin: 0px 20px 10px 20px;">
<div class="card-header" style="font-size: 80%;">
<div style="float: left;">{{ day }}</div>
<div style="float: right;">
收入: | 支出:
</div>
</div>
<ul class="list-group list-group-flush">
{% for hr in records %}
<li class="list-group-item">
{% if hr.sub_category %}
<div style="float: left;">{{ hr.category }} - {{ hr.sub_category }}</div>
{% else %}
<div style="float: left;">{{ hr.category }}</div>
{% endif %}
{% if hr.category.category_type == 'Income' %}
<div style="float: right; color: green;">{{ hr.amount }}</div>
{% else %}
<div style="float: right; color: red;">{{ hr.amount }}</div>
{% endif %}
<br>
{% if hr.comment %}
<div style="float: left; font-size: 80%; color: gray;">{{ hr.comment }}</div>
{% endif %}
<div style="float: right; font-size: 80%; color: gray;">{{ hr.account }}</div>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{% for day, records in current_month_records.items %}这代表着循环每日账单的字典元素,并取回日期(key)和当日账单记录(value),当日账单记录会再做一次for循环。
于是问题来了,在收入支出那里就不能再做一次循环,而是需要通过dict[key]的方式来取对应的值,获得当日的收支状况。
很遗憾,django template并不默认支持这样的取值。(其实django template可以支持类似加法之类的操作,比如{{ income | add: expense }},但是没有直接可用的取字典值的方法。)
于是我们可以添加一个自定义的template tags,有的叫模板标签,有的也叫模板过滤器。
在accounting/views.py同级目录下创建一个python package,取名为templatetags,在其中默认生成了一个__init__.py,然后自己创建一个脚本,假设取名为filter_dict.py,在其中加入代码:
from django import template
register = template.Library()
@register.filter('get_dict_value')
def get_dict_value(d, key):
return d[key]
这段代码意味着我可以在template里调用get_dict_value这个方法来为字典取值了。
于是在刚才的html template片段中把收支的部分改为如下:
{% load filter_dict %}
<div style="float: right;">
收入:{{ day_income_expense|get_dict_value:day|get_dict_value:'income' }} | 支出:{{ day_income_expense|get_dict_value:day|get_dict_value:'expense' }}
</div>
这样便能完成自定义模板过滤器,并协助自己筛选字典值了。
然后页面就能完成为下面的图片的样子,能显示每日的账单整合信息,并显示每日的收支汇总信息。
共有6条评论
添加评论
KH
2024年12月18日 23:05博主您好,参照教程执行到这一步,前端页面无法获取category(name),是否有源码可以参考?十分感谢@ bobjiang4321@gmail.com
Khakikiddo
2024年3月7日 17:22请问博主,current_month_records该如何定义呢
Khakikiddo
2024年3月7日 17:22请问博主,current_month_records该如何定义呢
yp
2022年5月3日 23:55你好!我后台数据库有更新,但是为什么页面上无法显示账单的列表,会显示'NoneType' object has no attribute 'category_type'
Bo
2021年5月9日 19:47@hp2 bobjiang4321@gmail.com
hp2
2021年5月9日 19:15能留个联系方式吗