Django_渲染详解

Django_render

模板语法

模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。

静态网页:页面上的数据都是写死的,万年不变

动态网页:页面上的数据是从后端动态获取的(比如后端获取当前时间;后端获取数据库数据然后传递给前端页面)

Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)。DTL官方文档

要在django框架中使用模板引擎把视图中的数据更好的展示给客户端,需要完成3个步骤:

  1. 在项目配置文件中指定保存模板文件的模板目录。一般模板目录都是设置在项目根目录或者主应用目录下。

  2. 在视图中基于django提供的渲染函数绑定模板文件和需要展示的数据变量

  3. 在模板目录下创建对应的模板文件,并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。

配置模板目录:在当前项目根目录下创建了模板目录templates. 然后在settings.py, 模板相关配置,找到TEMPLATES配置项,填写DIRS设置模板目录。

render内部本质

image-20220908194058936

def index(request):
	name = "hello world!"
	# 1. 初始化模板,读取模板内容,实例化模板对象
    # get_template会从项目配置中找到模板目录,我们需要填写的参数就是补全模板文件的路径
	template = get_template("index.html")
	# 2. 识别context内容, 和模板内容里面的标记[标签]替换,针对复杂的内容,进行正则的替换
	context = {"name": name}
	content = template.render(context, request) # render中完成了变量替换成变量值的过程,这个过程使用了正则。
	print(content)
	# 3. 通过response响应对象,把替换了数据的模板内容返回给客户端
	return HttpResponse(content)
	# 上面代码的简写,直接使用 django.shortcuts.render
	# return render(request, "index.html",context={"name":name})
    # return render(request,"index3.html", locals())
    # data = {}
    # data["name"] = "xiaoming"
    # data["message"] = "你好!"
    # return render(request,"index3.html", data)
  1. DTL模板文件与普通html文件的区别在哪里?

DTL模板文件是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端。

  1. 开发中,我们一般把开发中的文件分2种,分别是静态文件和动态文件。
    • 静态文件,数据保存在当前文件,不需要经过任何处理就可以展示出去。普通html文件,图片,视频,音频等这一类文件叫静态文件。
    • 动态文件,数据并不在当前文件,而是要经过服务端或其他程序进行编译转换才可以展示出去。 编译转换的过程往往就是使用正则或其他技术把文件内部具有特殊格式的变量转换成真实数据。 动态文件,一般数据会保存在第三方存储设备,如数据库中。django的模板文件,就属于动态文件。

模板语法内容

  1. 变量渲染(深度查询、过滤器)

    {{val}}
    {{val|filter_name:参数}}
    
  2. 标签

    {% tag_name %}
    
  3. 嵌套和继承

1.1 深度查询

def index(request):
    name = "ZhangJR"
    age = 22
    is_married = True
    course = ["global education","hongkong economy"]

    regina = {
        "name":"ZhangJR",
        "age": 22,
        "is_married": True,

    }

    class info():
        def __init__(self,name,age):
            self.name = name
            self.age = age
    Info = info("ZhangJR",22)

    Info1 = info("ZhangJR",22)
    Info2 = info("regina", 23)
    Info3 = info("ivnalee", 24)
    Info4 = info("qianniu", 25)
    Infos = [Info1,Info2,Info3,Info4]

    return render(request,"index.html",locals())

深度查询在查询属性或者取值的过程都用.作为判断,locals函数代表将视图函数所有的内容全部传送给模板文件渲染

分别通过普通类型,字典类型,类,类的列表进行学习

<h3>深度查询:句点符"."</h3>
<hr>普通类型
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p>婚否:{{is_married}}</p>
<p>课程:{{course}}</p>
<p>第一个课程:{{course.0}}</p>

<hr>字典
<p>个人信息:{{regina}}</p>
<p>个人名字:{{regina.name}}</p>
<p>个人年龄:{{regina.age}}</p>

<hr>类对象
<p>类对象名字:{{Info.name}}</p>
<p>类对象年龄:{{Info.age}}</p>

<hr>类列表取值
<p>第二个人的姓名:{{Infos.1.name}}</p>

image-20220908201405331

1.2 内置过滤器

语法:

{{obj|过滤器名称:过滤器参数}}

内置过滤器

过滤器 用法 代码
last 获取列表/元组的最后一个成员 {{list | last}}
first 获取列表/元组的第一个成员 {{list|first}}
length 获取数据的长度 {{list | length}}
default 当变量没有值的情况下, 系统输出默认值, {{str|default:"默认值"}}
safe 让系统不要对内容中的html代码进行实体转义 {{htmlcontent| safe}}
upper 字母转换成大写 {{str | upper}}
lower 字母转换成小写 {{str | lower}}
title 每个单词首字母转换成大写 {{str | title}}
date 日期时间格式转换 `{{ value
cut 从内容中截取掉同样字符的内容 {{content | cut:"hello"}}
list 把内容转换成列表格式 {{content | list}}
add 加法 {{num| add}}
filesizeformat 把文件大小的数值转换成单位表示 {{filesize | filesizeformat}}
join 按指定字符拼接内容 {{list| join("-")}}
random 随机提取某个成员 {list | random}}
slice 按切片提取成员 {{list | slice:":-2"}}
truncatechars 按字符长度截取内容 {{content | truncatechars:30}}
truncatewords 按单词长度截取内容 同上
Infos = [Info1.name,Info2.name,Info3.name,Info4.name]
<p>信息的最后一个人的姓名:{{Infos | last}}</p>
<p>信息的第一个人的姓名:{{Infos | first}}</p>
<p>共有{{Infos | length}}个人</p>

image-20220908202840812

  • 默认值

    如果渲染的值为空,可以添加默认渲染值,效果如图

    Name= ""
    
    姓名{{Name}}
    

    image-20220908203046383

如果变成<p>姓名 {{Name|default:"regina"}}</p>(default后面不能有空格)

image-20220908203351068

  • 日期转换

    now = datetime.datetime.now()
    <p>当前时间默认格式:{{now}}</p>
    <p>格式化日期:{{now|date:"Y-m-d"}}</p>
    <p>格式化日期2:{{now|date:"D/d/m/Y"}}</p>
    

    image-20220908204007197

  • 文件大小

    filesizeformat过滤器自动会识别字节大小进行单位的选择

     file1 = 717
      file2 = 127717
      file3 = 1271221
      file4 = 1155178797
    <p>文件大小:{{file1|filesizeformat}}</p>
    <p>文件大小:{{file2|filesizeformat}}</p>
    <p>文件大小:{{file3|filesizeformat}}</p>
    <p>文件大小:{{file4|filesizeformat}}</p>
    

    image-20220908204656545

  • 按字符截断

    str = "ABCDEFGHIJK"
    <p>content: {{str | truncatechars:6}}</p>
    

    image-20220908205214957

    这个...默认算作了一个字符

  • safe过滤

    如果我们输入的是一段带有标签的html语言,类似于

        link = "<a href='www.gs.cuhk.edu.hk'>cuhk</a>"
        script = "<script>alert('regina')</script>"
    

    如果正常传输,那网页上得到的则是

    image-20220909102044206

    并不是一个我们想要的效果,因为默认过滤器会对一些字符进行转义,打开页面源码就会发现这一问题

    image-20220909102146093

    如果我们加上safe过滤器

    <p>link:{{link| safe}}</p>
    <p>script:{{script|safe}}</p>
    

    image-20220909102248840

    image-20220909102306168

    image-20220909102323379

    代码也没有进行任何的修改

1.3 自定义过滤器

虽然官方已经提供了许多内置的过滤器给开发者,但是很明显,还是会有存在不足的时候。例如:希望输出用户的手机号码时, 13912345678 ---->> 139*****678,这时我们就需要自定义过滤器。要声明自定义过滤器并且能在模板中正常使用,需要完成2个前置的工作:

  1. 当前使用和声明过滤器的子应用必须在setting.py配置文件中的INSTALLED_APPS中注册了!!!

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
    

    这里面并没有添加自定义的app进去,现在我们找到如下文件,并在上述代码添加regina.apps.ReginaConfig

    image-20220914094726582

    1. 自定义过滤器函数必须被 template.register进行装饰使用,而且过滤器函数所在的模块必须在templatetags包里面保存

      在home子应用下创建templatetags包[必须包含__init__.py], 在包目录下创建任意py文件

      image-20220914095239114

      myfilters的名字是自定义的,这里就是存储过滤函数,并需要在最开始加上一些头文件

      from django import template
      register = template.Library()
      
      @register.filter("mobile")
      def mobile(number):
          return number[:3]+"****"+number[-3:]
      
    2. 在需要使用的模板文件中顶部使用load标签加载过滤器文件my_filters.py并调用自定义过滤器{% load myfilters %}

      过滤的函数要和myfilters文件里面的函数是同名的

      最终当输入一个手机号时,得到就是一个隐藏后的手机号

      image-20220914101648307

2.1 标签

{% tagname %}

if标签

is_married = True
{% if is_married == True %}
    <p>张女士已婚</p>
{% else %}
    <p>张女士未婚</p>
{% endif %}

这里需要注意的几个点:

  1. {% if condition %}这里的condition和if都需要和周围的%空开一格
  2. {% if is_married == true %}这里要用双等号
  3. 最后一定要加

image-20220914155633365

<div>
    {% if age < 20 %}
        <p>太小</p>
    {% elif age < 22 %}
        <p>还行</p>
    {% else %}
        <p>正好</p>
    {% endif %}
</div>

for循环

<ul>
    {% for name in course %}
    <li>{{ name }}</li>
    {% endfor %}
</ul>

image-20220914161141722

<table width="800" border="1" align="center">
    <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>

{% for info in Infos %}
    <tr align="center">
        <td>{{ forloop.counter }}</td>
        <td>{{ info.name }}</td>
        <td>{{ info.age }}</td>
    </tr>
{% endfor %}
</table>

image-20220914162916027

还可以结合if判断

{% for info in Infos %}
    {% if forloop.first %}
        <tr align="center" class="pink">
        <td>{{ forloop.counter }}</td>
        <td>{{ info.name }}</td>
        <td>{{ info.age }}</td>
    </tr>
    {% else %}
        <tr align="center">
            <td>{{ forloop.counter }}</td>
            <td>{{ info.name }}</td>
            <td>{{ info.age }}</td>
        </tr>
    {% endif %}

{% endfor %}

image-20220914163318861

或者还可以

    {% elif info.age > 23 %}
        <tr align="center" >
            <td>{{ forloop.counter }}</td>
            <td class="blue">{{ info.name }}</td>
            <td>{{ info.age }}</td>
        </tr>

image-20220914164050224

循环中, 模板引擎提供的forloop对象,用于给开发者获取循环次数或者判断循环过程的.

属性 描述
forloop.counter 显示循环的次数,从1开始
forloop.counter0 显示循环的次数,从0开始
forloop.revcounter0 倒数显示循环的次数,从0开始
forloop.revcounter 倒数显示循环的次数,从1开始
forloop.first 判断如果本次是循环的第一次,则结果为True
forloop.last 判断如果本次是循环的最后一次,则结果为True
forloop.parentloop 在嵌套循环中,指向当前循环的上级循环

3 嵌套继承

传统的模板分离技术,依靠{% include "模板文件名"%}实现,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.因此, Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.

{% include "模板文件名"%}  # 模板嵌入
{% extends "base.html" %} # 模板继承 

3.1 include

假设现在有两个页面公用一个同样式的东西,即页面底部有一个广告~

image-20220914165809050

在每一个页面里都添加一句

{% include "same.html" %}

image-20220914170307750

image-20220914170328853

此时两个页面就同时拥有了这一元素

3.2 extends继承

因为一个页面继承的东西可能有很多,而且有很多的固定框架,不可能每一个都用include进行继承,此时就需要extends关键字,首先我们来用bootstrap学习一下,然后在我们需要自己渲染的位置上添加区块

 <div class="col-md-10">
   <div class="theme-showcase" role="main">
     {% block content %}
     <p>hello world!</p>
     {% endblock %}
   </div>
</div>

其中content是自定义的名字,在模板文件里也同样要用这个名字,然后在其他文件里进行导入这个文件

{% extends "same.html" %}
.....
{% block content %}
原来渲染的内容
{% endblock %}

被extends的文件在未使用时是这样的

image-20220915000327456

我们看到有两个块是要传递给模板文件渲染的,index.htmltest.html同时继承了这一文件,效果如图

image-20220915000446635

image-20220915000506977

  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
  • 为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:{``% block content``%``}``...``{``% endblock content``%``},在大型模版中,这个方法帮你清楚的看到哪一个  {% block %} 标签被关闭了。
  • 不能在一个模版中定义多个相同名字的 block 标签。

在最开始的same页面中,我们是添加了一句话的,虽然这句话并不重要,但是如果我们继承的时候也想要这句话,就需要把语句改为

{% block content %}
{{ block.super }}
....

image-20220915001014323

此时原来same.html里面的block内容也可以得到继承

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Django_渲染详解 - Python技术站

(0)
上一篇 2023年4月2日 下午4:59
下一篇 2023年4月2日

相关文章

  • django中间件以及自定义中间件

    middleware 中间件就是在目标和结果之间进行的额外处理过程,在Django中就是request和response之间进行的处理,相对来说实现起来比较简单,但是要注意它是对全局有效的,可以在全局范围内改变输入和输出结果,因此需要谨慎使用,否则不仅会造成难以定位的错误,而且可能会影响整体性能。 中间件有什么用 如果想要修改HttpRequest或者Htt…

    2023年4月2日
    00
  • pandas数据清洗

    数据清洗 数据清洗是对一些没有用的数据进行处理的过程。 很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况,如果要对使数据分析更加准确,就需要对这些没有用的数据进行处理。 在这个教程中,我们将利用 Pandas包来进行数据清洗。 处理丢失数据 有两种丢失数据: None np.nan(NaN) 两种丢失数据的区别 为什么在数据分析中需要用到的是浮…

    2023年4月2日
    00
  • mysql面试小结

    MySQL 1. 索引 1.1 什么是索引 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。 索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。 更通俗的说,索引就相当于目录。为了方便查找书中的内容,…

    MySQL 2023年4月18日
    00
  • phpt文件内容解析

    phpt测试文件说明 phpt文件用于PHP的自动化测试,这是PHP用自己来测试自己的测试数据用例文件。 测试脚本通过执行PHP源码根目录下的run-tests.php,读取phpt文件执行测试。 phpt文件包含 TEST,FILE,EXPECT 等多个段落的文件。在各个段落中,TEST、FILE、EXPECT是基本的段落, 每个测试脚本都必须至少包括这三…

    PHP 2023年4月19日
    00
  • django学习_路由

    django2 路由控制器 Route路由,是一种映射关系。路由是把客户端请求的url路径和用户请求的应用程序,这里意指django里面的视图进行绑定映射的一种关系。 请求路径和视图函数不是一一对应的关系 在django中所有的路由最终都被保存到一个叫urlpatterns的文件里,并且该文件必须在主应用下的urls.py里进行声明,这是由setting文件…

    2023年4月2日
    00
  • django_响应对象

    Django_响应对象 响应对象 响应对象有三种形式: HttpResponse() render() Redirect() (1) HttpResponse() django服务器接收到客户端发来的请求之后,会将提交上来的数据封装成一个HttpResponse对象传给视图函数。视图函数在处理完相关逻辑之后,也需要一个返回响应给浏览器。而这个响应方式,我们必…

    2023年4月2日
    00
  • Django_模型详解

    Django_模型ORM Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。 O是object,也就类对象的意思。 R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思。 M是mapping,是映射的意思。 映射: 类:sql语句table表 类成…

    2023年4月2日
    00
  • CSRF和token以及用django实现

    csrf CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在未授权的情况下执行在权限保护之下的操作,具有很大的危害性。具体来讲,可以这样理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的…

    2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部