一、 Template概述
1.1 模板作用
- 呈现给用户界面; 实现MTV中TV的解耦;
- VT 有着N:M的关系; 一个View可以调用任意Template, 一个Template可以被任意View使用
1.2 模板内容
- HTML静态代码
- 动态插入的代码段(变量、运算、转换和逻辑)
二、 模板加载处理流程
- 加载: 读取指定的html文件
- from django.template import loader
- template = loader.get_template('index.html')
- 渲染: 以context设置的数据,处理html文件中模板的语句和变量,生成html网页内容
- html = template.render(context) # context是一个dict类型对象
- 加载+渲染:
- html = loader.render_to_string("index.html", context)
1 2 3 4 5 6 7 8 9 | def user_list3(request: HttpRequest): users = UserEntity.objects. all () msg = '最佳创业团队' # 加载模板 template = loader.get_template( 'user/list2.html' ) # 渲染模板 html = template.render(context = { 'msg' : msg, 'users' : users}) return HttpResponse(html, status = 200 ) |
1 2 3 4 5 6 | def user_list3(request: HttpRequest): users = UserEntity.objects. all () msg = '最佳创业团队' html = loader.render_to_string( 'user/list2.html' , locals (), request) return HttpResponse(html, status = 200 ) |
三、 模板语法
3.1 变量 {{ var }}
变量: 遵循命名规范
点语法(.): 获取属性 car.name ; 调用方法: 不能传递参数 / 索引 cars.0.name / 字典 cars.key
3.1.1 读取列表中的变量 users.2; 读取变量的属性 user.name
1 2 3 4 5 6 7 8 9 10 | < body > < h3 >{{ msg }}</ h3 > < p style="color: green;"> 第三个用户名: {{ users.2.name }} </ p > < ul > {% for user in users %} < li >{{ user.id }} | {{ user.name }} | {{ user.age }} | {{ user.phone }}</ li > {% endfor %} </ ul > |
3.1.2 字典获取key和value
1 2 3 4 5 6 7 8 9 10 11 12 | < p style="color: red;"> 今天请客人ID: {{ error_index }} </ p > < p style="color: white; "> < span >VIP:</ span > < span >{{ vip.name.upper }} - {{ vip.money }}</ span > </ p > < ul > {% for key, value in vip.items %} < li >{{ key }} = {{ value }}</ li > {% endfor %} </ ul > |
3.1.3 变量的索引
1 2 3 | def user_list3(request: HttpRequest): users = UserEntity.objects.all() error_index = random.randint(0, users.count()-1) |
1 2 3 | < p style="color: red;"> 今天谁请客: {{ users.error_index.name }} # 这样不起作用 </ p > |
3.2 表达式标签 {% %}
for...in 循环
- 遍历集合(数组,列表): {% for 变量 in 列表 %} 语句1 {% empty %} 语句2 {% endfor %}
- forloop: counter 第几次循环,从1开始 / counter0 / revcounter / revcounter0 / first / last
- empty: 集合为空时的处理; {% empty %} 集合对象不能为None, 但是没有元素
- {% cycle "even" "" %}: 轮询的方式选择后面的字符串
if判断
- if表达式: {% if expression %} 语句 {% endif%}; 表达式必须要关闭
- if-else: {% if 表达式 %} 语句 {% else %} 语句 {% endif %}
- if-elif-else: {% if 表达式 %} 语句 {% elif 表达式 %} 语句 {% endif %}
注释
- 单行注释: {# 被注释的内容 #}
- 多行注释: {% comment %} 内容 {% endcomment %}
- 注释的内容在渲染模板之后,不会保留在HTML页面中
ifequal 如果相等 {% ifequal value1 value2%} 语句 {% endifequal %}
ifnotequal 如果不相等
3.2.1 forloop.counter 是从 1 开始, error_index 是从0开始
1 2 3 4 5 6 7 8 9 10 | < ul > {% for user in users %} < li >{{ forloop.counter }} - {{ user.id }} | {{ user.name }} | {{ user.age }} | {{ user.phone }}</ li > {% if forloop.counter == error_index %} < p style="color: red;"> 今天谁请客呢: {{ user.name }} </ p > {% endif %} {% endfor %} </ ul > |
1 | {% if forloop.counter0 == error_index %} |
3.2.2 if 判断 、 for循环、 cycle
1 2 3 4 5 6 7 8 9 10 11 | < head > < meta charset="UTF-8"> < title >Django Index主页</ title > {% include 'base_css.html' %} < style > .even { background-color: lightgoldenrodyellow; } .red { background-color: red; } .blue { background-color: blue; } .green { background-color: green; } </ style > </ head > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | < table class="table table-bordered table-responsive table-hover"> < thead > < th >ID</ th > < th >账号</ th > < th >真实姓名</ th > < th >手机号</ th > </ thead > < tbody > {% if users %} {% for user in users %} < tr class="{% cycle "even" "" %}"> < td >{{ user.id }}</ td > < td >{{ user.name }}</ td > < td >{{ user.realprofile.real_name }}</ td > < td >{{ user.phone }}</ td > </ tr > {% endfor %} {% else %} < tr > < td colspan="4">无数据</ td > </ tr > {% endif %} </ tbody > |
3.2.3 cycle 遍历
1 | <tr class="{% cycle "red" "blue" "green" %} |
3.2.4 empty
1 2 3 4 5 6 7 | < ul > {% for name in names %} < li >{{ name }}</ li > {% empty %} < option >空</ option > {% endfor %} </ ul > |
3.2.5 ifequal
1 | < tr {% ifequal forloop.counter 3 %} class="even" {% else %} class="red" {% endifequal %}> |
3.3 过滤器/逻辑计算
数值运算
- 加减: 通过加上负数的形式实现减法; {{ store.years|add:5 }} {{ store.years|add:-2 }}
- 乘除: {% widthratio 变量 分母 分子 %} 例:{% widthratio price 10 1 %} price 的 10分之1
- 整除: {% if num|divisibleby:2 %}
字符串操作
- lower: {{ p.pname|lower }}
- upper: {{ p.pname|upper }}
- capfirst:{{ value|capfirst }} value的第一个字符转换成大写
- cut: {{ value|cut:arg }} 从给定value中删除所有arg的值
- join: {{ value|join:'-'}} {{ value|join:'-'|escape}} 对iterable进行连接
1 | < tr {% ifequal forloop.counter|divisibleby:2 0 %} class="even" {% endifequal %}> # counter/2余数等于0 |
3.4 default 默认值
格式: {{ value|default:val }} {{ store.address|default:'无'}}
3.5 日期时间
根据指定格式转换日期为字符串, {{ dateVal | date:'Y-m-d H:i:s a'}}
格式: F:月份 / g:Hour(1-12)不带前缀0 / G:Hour(0-23)不带前缀0 / l:星期几 / j: 1-31 不带前缀0
1 2 | {{ now|date: "Y-m-d" }} # 冒号(:) 后面有空格,报错 django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: ': "Y-m-d"' from 'now|date: "Y-m-d"' |
3.6 HTML转义
- escape: 保留原始字符串, "<"之类的符号转换成 < [< <] [> >] ['] ["] [& &]
- 在区域开启escape: {% autoescape on/off %} {% endautoescape %}
- 将接收到的数据当前普通字符串处理还是当成HTML代码来渲染
- 渲染成HTML: 不转义 {{ code|safe }} {% autoescape off %} code {% endautoescape %}
- 不渲染成HTML: 转义 {{ code|escape }} {% autoescape on %} code {% endautoescape %}
- 注意: 开发中尽量保持纯文本; 如果进行html渲染,存在被恶意注入风险
1 2 3 4 5 6 7 8 9 10 11 | {{ info | escape }} {% autoescape off %} {{ info }} {% endautoescape %} {% autoescape on %} < pre > {{ info }} </ pre > {% endautoescape %} |
3.7 其他
- length: {{ value|length }} 返回value的长度
- floatformat
- {{ value|floatformat }} 34.23444 -> 34.2 34.00000 -> 34 34.26000 -> 34.3
- {{ value|floatformat:arg }} 34.23444 -> 34.234 34.00000 -> 34.000 34.26000 -> 34.260
3.7.1 显示文件属性 、数值格式化、 转义
1 2 3 4 5 6 7 8 9 | >>> import os >>> from helloDjango.settings import BASE_DIR >>> file_path = os.path.join(BASE_DIR, 'mainapp/models.py' ) >>> os.stat(file_path) os.stat_result(st_mode = 33206 , st_ino = 562949954054592 , st_dev = 1828079847 , st_nlink = 1 , st_uid = 0 , st_gid = 0 , st_size = 6674 , st_atime = 1680343296 , st_mtime = 1680878778 , st_ctime = 1680343296 ) >>> file_stat = os.stat(file_path) >>> file_stat.st_size 6674 |
1 2 3 4 5 6 | now = datetime.now() file_dir = os.path.join(settings.BASE_DIR, 'mainapp/')< br > # files是一个字典, key是 file_name value是 os.stat(file_dir + file_name) files = {file_name: os.stat(file_dir + file_name) for file_name in os.listdir(file_dir) if os.path.isfile(file_dir+file_name)} price = 19.1356 img_html = "< img width=200 height=200 src='/media/Fruit.jpeg'>" |
1 2 3 4 5 6 7 8 9 10 11 | {% for path, f_stat in files.items %} < p > {{ path }} 的文件大小为 {{ f_stat.st_size | filesizeformat }} </ p > {% endfor %} < p > 价格: {{ price|floatformat:1 }} </ p > < p > {{ img_html|safe }} </ p > |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步