Django之模板层

人生有诗意,永远是少年


模板层

一、模板介绍

基本介绍

在视图层中我们,浏览器将发送的请求信息会转发给视图函数进行处理,而视图函数在经过一系列处理后必须要有返回信息给浏览器。如果我们要返回html标签、css等数据给浏览器进行渲染,我们可以在视图函数中这么做

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

我们直接将HTML代码放到视图函数里,然后进行返回,这可以使我们很直观地看清楚浏览器从发送请求到看到前端界面内容的这个过程中视图函数的基本工作原理。

但是这种将前端代码与后端代码耦合到了一起开发方式,所以直接将HTML硬编码到你的视图里却并不是一个好主意

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
  • Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
  • 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。

将前端页面和Python的代码分离是一种不错的开发模式。 为此 Django专门提供了模板系统 (Template System,即模板层)来实现这种模式。

Django=HTML代码+模板语法

常用语法

只需要两种特殊符号:{{}}{% %}

  • 变量相关的用{{}}
  • 逻辑相关的用{% %}

注释

注释是代码之母:

  • 单行注释:{# #}

  • 多行注释:

    {% comment %}
       <注释内容>
    {% endcomment %}
    

二、变量

如果HTML代码中的数据是动态变化的,则需要HTML中嵌入变量,为此,模板语法提供了变量的概念,允许我们在html代码中嵌入变量,我们只需要在视图函数中用render方法为html文件中指定的变量赋值即可。

**变量名:**由数字,字母,下划线和点组成的,不能以下划线开头。 变量名称中不能有空格或标点符号

模板语法

view:{"HTML变量名" : "views变量名"}
HTML:{{变量名}}

1. 模板语法之传值

python基本数据类型传值
  • 视图层
def index(request):
    # python基本数据类型
    i = 666
    f = 11.11
    s = 'hello world jason egon justin kevin oscar'
    l = [111, 222, 333, 444]
    d = {'username': 'shawn', 'password': 123, 'hobby': ['read', 'study', 'run', {'username': 'jason666'}]}
    t = (111, 222, 333)
    se = {111, 222, 333}
    b = True
    b1 = False
    # 传值方式1:指名道姓,利用字典挨个传值
    return render(request, 'index.html', {'i': i, 'f': f, 's': s})
    # 传值方式2:简单粗暴  locals()将当前名称空间中所有的变量名全部传递给页面
    return render(request, 'index.html', locals())
  • 模板层
<p>{{ i }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>

效果展示:

image-20210326174142943

函数与类的递归
  • 视图层
def test_func(request):

    def aa():
        print("aa--->")
        return 'I am aa'

    class Bar(object):

        def cc(self):
            print("Bar-->cc")

    B1 = Bar()
    return render(request, 'index.html', locals())
  • 模板层
<h1>{{ aa }}</h1>
<h1>{{ Bar }}</h1>
<h1>{{ B1 }}</h1>

效果展示:

image-20210326175554323

总结

后端给HTML文件传递数据的两种方式

# 传值方式1:指名道姓,利用字典挨个传值
return render(request,'index.html',{'i':i,'f':f,'s':s})
# 传值方式2:简单粗暴  locals()将当前名称空间中所有的变量名全部传递给页面
return render(request,'index.html',locals())
补充:()

传值方式的优缺点:

  • 传值方式一:传值精确 不会造成资源浪费
  • 传值方式二:传值粗糙 可能会造成一定的资源浪费

函数名与类名注意点:

  • 传递函数名和类名都会自动加括号调用
  • 模板语法不支持额外的传参,也就是函数无法传参
  • 传入函数名得到的结果是函数的返回值

2. 模板语法之获取值

点(.)在模板语言中有特殊的含义。

  • django模板语法取值只能采用 句点符(.)也就是点
  • 可以根据索引以及键取值,索引、键都可以无限制的点点点……

视图层

def index(request):
    # python基本数据类型
    i = 666
    f = 11.11
    s = 'hello world jason egon justin kevin oscar'
    l = [111, 222, 333, 444]
    d = {'username': 'shawn', 'password': 123, 'hobby': ['read', 'study', 'run', {'username': 'jason666'}]}
    t = (111, 222, 333)
    se = {111, 222, 333}
    b = True
    b1 = False
    return render(request, 'index.html', locals())

模板层

'''取出爱好里面的字典对应的名字'''
# index.html
<p>{{ d.hobby.3.username }}</p>

效果展示:

image-20210326181728611

当模版系统遇到点("."),它将以这样的顺序查询:

  • 字典查询(Dictionary lookup)
  • 属性或方法查询(Attribute or method lookup)
  • 数字索引查询(Numeric index lookup)

三、模板语法之过滤器

Django的模板语言中,通过使用 过滤器 来改变变量的显示,大约有60种过滤器,这里只介绍常用过滤器。

模板语法:

{{ 变量名 | 过滤器:可选参数 }}

eg:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。

视图层:

def index(request):
    # python基本数据类型
    i = 666
    f = 11.11
    s = 'hello world 干饭人 干饭魂 我们都是打工人!'
    l = [111, 222, 333, 444]
    d = {'username': 'shawn', 'password': 123, 'hobby': ['read', 'study', 'run', {'username': 'jason666'}]}
    t = (111, 222, 333)
    se = {111, 222, 333}
    w = 'aa bb cc dd ee ff'
    b = True
    b1 = False
    file_size= 2384024
    return render(request, 'index.html', locals())

模板层:

# 类似于python的内置方法
<p>过滤器:将竖杆左侧的数据当做第一个参数</p>
<p>统计长度:{{ s|length }}</p>
<!-- add数字相加,字符拼接-->
<p>加法运算:{{ i|add:100000000000 }}</p>
<p>字符串拼接:{{ s|add:'heiheihei' }}</p>
<p>拼接:{{ s|join:'@' }}</p>
<p>切片:{{ l|slice:'0:5:2' }}</p>
<p>日期格式:{{ ctime|date:'Y年-m月-d日 H时:i分:s秒' }}</p>
<!-- 如果第一个参数的布尔值是true则显示左边的值,否则显示default后的值-->
<p>默认值:{{ b|default:'哈哈' }}</p>
<p>默认值:{{ b1|default:'哈哈' }}</p>
<!-- 截取内容包含三个点,并且算在字符个数之内-->>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>截取文本(三个点也算):{{ s|truncatechars:6 }}</p>
<!-- 截取内容包含三个点,但不算在单词个数之内,单词识别是以空格来区分的-->
<p>截取文本(三个点不算)空格:{{ s|truncatewords:3 }}</p>

效果展示:

image-20210326184454386

注意事项:

  1. 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
  2. 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
  3. 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:’, ’ }}
  4. '|'左右没有空格没有空格没有空格
转义

要保证 views.py 传过来的数据绝对安全,才能用 safe。

和后端 views.pymark_safe 效果相同。

Django 会自动对 views.py 传到HTML文件中的标签语法进行转义,令其语义失效。加 safe 过滤器是告诉 Django 该数据是安全的,不必对其进行转义,可以让该数据语义生效。

要关闭模板上下文字符串的转义:

语法:

前端:
    可以使用
        {{ 模板变量|safe}}
    也可以使用
        {% autoescape off %}
                模板语言代码
        {% endautoescape %}
后端:
    	from django.utils.safestring import mark_safe
    	sss1 = mark_safe('<h2>老子要挣大钱</h2>')

后端使用转义

def index(request):
    h = "<h1>困了吗?</h1>"
    sss = "<script>alert(123)</script>"
    from django.utils.safestring import mark_safe
    sss1 = mark_safe('<h2>老子要挣大钱</h2>')
    nnn = []
    views_str = "<a href='https://www.meizitu.com'>点我进入百度</a>"
    return render(request, 'index.html', locals())

前端使用转义

<p>{{ h|safe }}</p>
<p>{{ sss }}</p>
<p>{{ sss1 }}</p>
<p>{{ views_str|safe }}</p>

总结:前端代码不一定非要在前端页面写,可以在后端写好后传递给前端页面使用,这样的话,你就可以利用到后端更加多的逻辑语法。

效果展示:

image-20210329145212998

四、模板语法之标签(逻辑相关)

1. 模板中的for循环

{% for 循环变量  in  循环对象  %}

		循环执行的语句
{%empty%}
		循环对象本身是空的时候,执行的代码
{% endfor%} {# 结束循环 #}

2. 模板中的判断语句

{%  if  条件  %}
		满足条件执行的语句
{% elif  条件 %}
		满足条件执行的语句
{%  else  %}
		以上条件都不满足时执行的语句
{%  endif  %}

3.示例

# 类似于python的流程控制
{% for foo in s %}
    {% if forloop.first %}
        <p>这是我的第一次~~</p>
    {% elif forloop.last %}
        <p>这是最后一次了啊~</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
    
    {% empty %}
        <p>传入的数据是空的</p>
{% endfor %}

# 了解
{# 取别名 #}
{% with d.hobby.3.username as name %}
    {{ name }}
    {{ d.hobby.3.username }}
{% endwith %}

五、自定义过滤器、标签、inclusion_tag

类似于python里面的自定义函数

1. 前期准备工作:

  1. 在应用下创建一个名字必须叫"templatetags"文件夹

  2. 在上述文件夹内创建一个任意名称的py文件

  3. 在该py文件内固定先书写以下两句话

    from django import template
    register = template.Library()
    

2.自定义过滤器

  • 自定义过滤器最多只能有两个形参
from .templatetags.mytag import register

# 在模板层导入自定义的过滤器时使用的是这里指定的名字
@register.filter(name='myfilter')  
def sums(a, b):   # 函数名随便起什么
    return a + b  # 返回两个参数的和

#模板层
{% load mytag %}  # 导入tag文件
<p>{{ i|myfilter:100 }}</p>  # 使用myfilter过滤器

image-20210326213409432

3.自定义标签

  • 自定义标签可以有多个参数
# 视图层
from .templatetags.mytag import register

# 在模板层导入自定义的标签时使用的是这里指定的名字
@register.simple_tag(name="my_tag")
def my_join(a,b,c,d):          # 函数名任意
    return f'{a}/{b}/{c}/{d}'  # 返回参数拼接后的结果

# 模板层
{% load mytag %}  # 导入tag文件
{% my_tag '嗨' '加油' '干饭人' '奥利给' %}  # 标签之后的多个参数彼此之间用空格隔开

image-20210326220531388

4.自定义inclusion_tag

inclusion_tag:当某个区域需要反复使用并且数据不是固定的

  • inclusion_tag 的内部原理:
  • 在HTML页面中导入写好的 inclusion_tag 并调用了
  • 触发了py文件中一个函数的执行并产生结果
  • 产生的结果通过模板语法传递给一个HTML页面进行渲染
  • 渲染完毕后又返回调用 inclusion_tag 的位置

img

#视图层
from .templatetags.mytag import register
@register.inclusion_tag('login.html',name='my_inclusion_tag')	 # 第一个参数是需要渲染的HTML页面
def func2(n):
    l = []
    for i in range(1,n+1):
        l.append('第%s页'%i)
    return locals()

#模板层
{% load mytag %}
<p>{% my_inclusion_tag 6 %}</p>

#login.html
<ul>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

image-20210326223535605

六、模板的导入

  • 类似于后端到模块 想要什么局部页面直接导入即可
'''静态导入'''
{% include 'myform.html' %}

'''动态导入'''
# 被导入的text.html
<p>{{ name }}</p>   {# 这里的name就是"egon"#}

# 导入html的文件
{% include 'text.html' with name='"egon"' %}
    
# 不过上面的导入的参数是写死的. 如果你想动态的通过模板语法传参, 你可以这样
{% include 'text.html' with name=username %}    {#注意哦! 这里的username是视图层传过来的哦!#}
# 被导入文件中如果想{{ name }}模板以后是字符串的格式你可以这也指定即可!
<p>'{{ name }}'</p>   {#注意: 如果不加引号, 这种字符串的格式的话, 那么name模板传值以后就是一个变量.#

七、模板的继承

模板可以用继承的方式来实现复用,减少冗余内容。

网页的头部和尾部内容一般都是一致的,我们就可以通过模板继承来实现复用。

父模板用于放置可重复利用的内容,子模板继承父模板的内容,并放置自己的内容。

1.模板继承的使用

  • 模板的继承首先需要选择一个模板页面, 在该页面里面使用 block 划定可以被更改的区域
# 母板页面 'home.html' 文件
{% block [区域名称] %}
......
{% endblock %}

  • 想要继承的页面可以使用 extends 来继承某一个页面
# 子版
{% extends 'home.html' %}
{% block [区域名称] %}
......
{% endblock %}

子版继承了模板, 那么子版的整体格式与模板一样, 被 block 划分了的区域可以自己随意更改

2.模板的三个区域

  • 母板在划分区域的时候一般有三个区域
{% block css %}
    # css区域
{% endblock %}

{% block content %}
    # HTML区域
{% endblock %}

{% block js %}
    # js区域
{% endblock %}

目的是为了让子版具有独立的css、js等,增加扩展性

3.示例

  • 路由层
urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/', views.func),
    path('index/', views.func2,name='index_name'),
]
  • 模板层
# home.html
{% block left-body %}
<div class="jumbotron">
    <h1>Hello, world!</h1>
    <p>这里是一个block划分的区域</p>
    <p><a class="btn btn-primary btn-lg" href="{% url 'index_name' %}" role="button">Learn more</a></p>
</div>
{% endblock %}

# index.html
{% extends 'home.html' %}
{% block left-body %}
    <div class="row">
      <div class="col-xs-6 col-md-4 col-md-offset-2">
        <a href="#" class="thumbnail">
          <img src="../static/img/11.png" alt="...">
        </a>
      </div>
        <div class="col-xs-6 col-md-4 col-md-offset-2">
            <a href="#" class="thumbnail">
              <img src="../static/img/11.png" alt="...">
            </a>
        </div>
    </div>
{% endblock %}

  • home.html页面

image-20210319153623274

  • index.html 页面

image-20210319153709598

总结:

  • 在父模板中可以定义块,子类可以重写该部分内容。
  • 模板继承也是为了重用html页面内容,减少代码的冗余。

参考资料:菜鸟教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾维斯Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值