模板相关操作

1. MVC框架和MTV框架

1. MVC框架

    MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。
​      M: model 模型 操作数据库
​      V: view 视图 展示页面 HTML
​      C: controller 控制器 调度 业务逻辑

2. MTV框架

Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

2. 语法

​ 模板渲染的官方文档

  关于模板渲染你只需要记两种特殊符号(语法):

  {{ }}和 {% %}

  变量相关的用{{}},逻辑相关的用{%%}。

3. 变量

1. 万能的点调用

{{ 变量名 }}

变量名由字母数字和下划线组成。

点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。

举例说明

views.py

from django.shortcuts import render
import datetime

def index(request):

    name = "水手"
    num = 100
    lst = [1, 2, "aa", "bb"]
    dic = {"xx": "oo", "xxx": "ooo"}
    date = datetime.date(1993, 5, 2)  # 日期对象

    class Person():
        n = "黑哥"

        def p(self):
            return "床前明月光"

    obj = Person()
    return render(request, "index.html", {"name": name, "num": num, "lst": lst, "dic": dic,"date":date, "obj": obj})
    # print(locals()) 获得全局字典,传的数据多,效率低
    # return render(request, "index.html", locals())

index.html 代码

    <h1>24期官网</h1>
    <h2>{{ name }}</h2>    # 获得后端name的值渲染到页面
    <h2>{{ num }}</h2>     # 获得后端num的值渲染到页面
    <h2>{{ lst }}</h2>     # 获得后端lst的值渲染到页面
    <h2>{{ dic }}</h2>     # 获得后端dic的值渲染到页面
    <h2>{{ obj }}</h2>     # 获得后端obj的对象渲染到页面
    <h2>{{ lst.1 }}</h2>   # {#点索引获取对应的值#}
    <h2>{{ dic.xx }}</h2>   # {#点键获取字典的值#}
    <h2>{{ obj.n }}</h2>    # {#点属性获取值#}
    <h2>{{ obj.p }}</h2>    # {#点方法获取返回值,前端调用不加括号#}
    <h2>{{ dic.keys }}</h2> {#先查找字典中的键,有此键就不调用方法了#}
    <h2>{{ dic.items }}</h2>  # {#点方法获取字典的键值对#}
    						# {# dic.values获取值,dic.keys获取键 #}

2. 查询顺序

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

举例说明

dic = {"xx": "oo", "xxx": "ooo","keys":"我在执行我"}
<h2>{{ dic.keys }}</h2> # 前端执行时先在字典中查询此键,有键就不执行字典的方法了
# 结果是: 我在执行我 而不是: dict_keys(['xx', 'xxx']) 键的列表

3. 注意点

  1. 调用方法不支持传参数
  2. 如果使用的变量不存在, 模版系统将插入 string_if_invalid 选项的值, 它被默认设置为'' (空字符串)

4. 过滤器 filter

作用:修改变量的显示结果

1. 语法

{{ value|filter_name }} # filter_name 过滤器名称

{{ value|filter_name:参数 }}

2. 具体举例

1. default 默认

注意:':'左右没有空格没有空格没有空格,nothing需要引号引起来

<h2>{{ age|default:"Nothing" }}</h2>     
# 变量不存在,显示为空字符串/none时,都会调用default默认值
返回同样是nothing的还有有这个变量,但是值是False,空字典等值为空的

注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用

见上述做修改部分替代default的作用
在settings文件中TEMPLATES的'OPTIONS'字典中再添加一个键值对 "string_if_invalid":"不存在或为空" 为空时或不存在时执行

2. filesizeformat

将值格式化为一个 “人类可读的” 文件格式大小 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)

{{ value|filesizeformat }}   #如果 value 是 123456789,输出将会是 117.7 MB
{{ 1024|filesizeformat }}  # 1.0kb

3. add 添加

用于数字的加减,字符串拼接,列表相加等

<h2>{{ num|add:22 }}</h2>    #  html语法加不加引号效果相同
<h2>{{ num|add:"22" }}</h2>  #  html语法加不加引号效果相同 num=100  结果:122
    <h2>{{ lst|add:lst }}</h2> # 
    <h2>{{ name|add:"bsb" }}</h2> # 也可以用于字符串和列表等的相加

4. widthratio 实现加减乘除

<h2>{{ num|add:10 }}</h2>           #等同于   num+10
<h2>{{ num|add:-10 }}</h2>          #等同于   num-10
<h2>{% widthratio num 1 5 %}</h2>   #等同于   num/1*5
<h2>{% widthratio num 5 1 %}</h2>   #等同于   num/5*1    必须3个参数  格式 参数1/参数2*参数3
<h2>{% widthratio 10 5 2 %}</h2>    #等同于   10/5*2=4

5. length 长度

<h2>{{ name|length }}</h2>  # 字符长度
<h2>{{ lst|length }}</h2>   # 列表长度
<h2>{{ dic|length }}</h2>   # 字典长度
<h2>{{ name|add:"bsb"|length }}</h2>  # 多重操作

6. slice 切片

<h2>{{ name|add:"abcdefg"|slice:"2:-1:2" }}</h2>  # ace  支持切片和步长

7. first 取第一个值

<h2>{{ name|first }}</h2>  # 获取第一个值
<h2>{{ value|last }}</h2>  # 获取最后一个值      

8. join 拼接

<h2>{{ name|join:"//" }}</h2>  # 结果 水//手 相当于字符串拼接
<h2>{{ dic|join:"//" }}</h2>   # 键拼接  xx//xxx
<h2>{{ lst|join:"//" }}</h2>   # 迭代拼接 1//2//aa//bb

9. truncatechars

如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾

<h2>{{ "abcdefghigk"|truncatechars:3 }}</h2>  #  ...    保留几个字符,小于三也是三个点
<h2>{{ "abcdefghigk"|truncatechars:6 }}</h2>  # abc...  保留6个,有三个点

10. date日期格式化

date = datetime.date(1993, 5, 2)  # 日期对象
now = datetime.datetime.now()     # 现在时间

<h2>{{ date|date:"Y-m-d"}}</h2>   #
<h2>{{ now|date:"Y-m-d H:i:s"}}</h2> #  设置显示格式

扩展,不过滤,在设置settings中修改

# USE_L10N = True
USE_L10N = False

DATETIME_FORMAT = "Y-m-d H:i:s"
DATE_FORMAT = "Y-m-d"
TIME_FORMAT = "H:i:s"

<h2>{{ date }}</h2>   #
<h2>{{ now }}</h2> #  设置显示格式

11. lower 小写

<h2>{{ "NAme"|lower }}</h2>   # 全部小写   name

12. upper 大写

<h2>{{ "NAme"|upper }}</h2>   # 全部大写   NAME

13. title 标题,首字母大写

<h2>{{ "woShiShui"|title }}</h2> # 首字母大写  Woshishui

14. safe 告诉django不需要转义

​ Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。

# 语法:{{ value|safe }}
'jjss':'<script> for (var i=0 ;i<5;i++){alert("123")}</script>'
        {{ jjss|safe }} # 告诉浏览器这是安全的代码
        {{ jjss }} # Django这个代码当做字符串处理 <script> for (var i=0 ;i<5;i++){alert("123")}</script>
        
    # 或者使用mark_save()方法
    from django.utils.safestring import mark_safe
    'jjss':mark_safe('<script> for (var i=0 ;i<5;i++){alert("123")}</script>')
bd = '<a href="http://www.baidu.com">百度</a>' # 后端

前端:
    <h2>{{ bd }}</h2>     # 显示字符串 <a href="http://www.baidu.com">百度</a>
    <h2>{{ bd|safe }}</h2> # 设置safe,显示为a标签 百度

通过自定义标签,实现网址

from django import template

register = template.Library()

@register.filter
def show_a(v1,v2):

    return f'<a href="http://{v1}">{v2}</a>'

{% load my_tags %}
{{ 'www.baidu.com'|show_a:'百度'|safe }}
# 第二种方法 
# index函数传 a = "www.taobao.com" 通过 render{"a":a}传到前端,前段通过{{ a|show_a:'百度'|safe }}传参到自定义标签
# 第三种方法
@register.filter(is_safe=True)  #不能使用index传参
def show_a(v1,v2):

    return f'<a href="http://{v1}">{v2}</a>'
{% load my_tags %}
{{ 'www.baidu.com'|show_a:'百度' }}
# 第四种方法
导入一个模块 mark_safe,用mark_safe将返回的结果包起来
from django.utils.safestring import mark_safe
@register.filter
def show_a(v1,v2):

    return mark_safe(f'<a href="http://{v1}">{v2}</a>')
#return mark_safe('<a href="http://{}">{}</a>'.format(v1,v2)) 传参

15. truncatewords

msg = "我 是 i love you my baby"

<h3>{{ msg|truncatewords:2 }}</h3> # {#  以空格区分截断,不是字符字节  #} 我 是 ...
<h3>{{ msg|truncatechars:2 }}</h3> # 注意二者的区分  ...

16. divisibleby 是否整除

<h1>{{ 10|divisibleby:2 }}</h1>   # True
<h1>{{ 10|divisibleby:3 }}</h1>   # False

5. 自定义过滤器

1. 自定义过滤器

1.在app下创建一个名叫templatetags的包 (templatetags名字不能改)

2.在包内创建py文件 (文件名可自定义 my_tags.py)

3.在my_tags.py中写代码:

from django import template
register = template.Library()  # register名字不能错,固定

4. 写上一个函数 + 加装饰器

@register.filter
def xx(v1,v2):
    ret = v1+v2
    return ret.upper()

5. 使用

index.html 中

{% load my_tags %}   # 加载py文件
{{ "alex"|xx:"dsb" }}  # alex和dsb 分别对应两个参数,渲染返回值
					# 参数至多两个,至少一个   name = "alex"可以通过index函数传递

6. 其他写法

from django import template

register = template.Library()

@register.filter
def xx(v1,v2="dsb"):
    ret = v1 + v2
    return ret.upper()

{% load my_tags %}  # html文件调用,先加载py文件
{{ "alex"|xx }}     # 后端添加默认参数,得到返回值  ALEXDSB

只有一个参数

from django import template

register = template.Library()

@register.filter
def xx(v1):
    ret = v1
    return ret.upper()

{% load my_tags %}
{{ "alex"|xx }}     # 后端添加默认参数,得到返回值,页面展示  ALEX

给函数起一个别名

from django import template

register = template.Library()

@register.filter(name="xxsb")
def xx(v1,v2):
    ret = v1 + v2
    return ret.upper()

{% load my_tags %}
{{ "alex"|xxsb:"dsb" }}   # 注意用别名xxsb,而不是xx  ALEXDSB

6. 模板中的标签

1. 语法{% tags %}

2. for 循环标签

1. for的一些参数

{{ forloop.counter }}      循环的索引 从1开始
{{ forloop.counter0 }}     循环的索引 从0开始
{{ forloop.revcounter }}   循环的索引(倒叙) 到1结束
{{ forloop.revcounter0 }}   循环的索引(倒叙) 到0结束
{{ forloop.first }}        判断是否是第一次循环  是TRUE
{{ forloop.last }}         判断是否是最后一次循环  是TRUE
{{ forloop.parentloop }}   当前循环的外层循环的相关参数
# forloop其实是一个字典,上边是通过.键取的值

2. 举个栗子

table = [[1,2,3],["a","b","c"],[7,8,9]]  # 后端传导前端

# 使偶数行偶数列变红
<table border="2">
    <tbody>
        {% for lst in table %}
            <tr>
            {% for foo in lst %}
                <td style="{% if forloop.counter|divisibleby:2 and forloop.parentloop.counter|divisibleby:2 %}color: red{% endif %}">{{ forloop.counter }}{{ foo }}</td>
            {% endfor %}
            </tr>
        {% endfor %}
    </tbody>
</table>

3. for ... empty

如果没有lst1时则显示empty的内容

    <ul>
        {% for i in lst1 %}
        <li>{{ i }}</li>
            {% empty %}
            <li>列表不存在</li>
        {% endfor %}
    </ul>

3. if 条件标签

{% if num > 100 or num < 0 %}
    <p>无效</p>  <!--不满足条件,不会生成这个标签-->
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}  <!--也是在if标签结构里面的-->
    <p>凑活吧</p>
{% endif %}
  1. if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
  2. if支持过滤器语法 {% if 10|add:2 %} {{ "成功" }} {% endif %}
  3. if 不支持算数运算 + - * / %
  4. 不支持连续判断 10 > 5 > 1 false 与Python不同,先判断10>5 的True,无法与1比较

4. with 给变量起别名

方法1
{% with total=business.employees.count %}  #注意等号两边不能有空格
    {{ total }} <!--只能在with语句体内用-->
{% endwith %}
方法2
{% with business.employees.count as total %}
    {{ total }}
{% endwith %}   # 就是名字太长时节省写法,只能在with标签内使用

7. {% csrf_token %} 防止跨站请求伪造

<form action="" method="post">
    #  name="csrfmiddlewaretoken" 
    {% csrf_token %}    # 会添加一个隐藏的input框. 当提交数据是,协同csrf令牌一同提交. 
    <input type="text" name="name">
    <button>提交</button>
</form>

8. 模板和继承

1. 模板继承(母版继承)

1. 创建一个base.html页面(作为母版,其他页面来继承它使用)
2. 在母版中定义block块(可以定义多个,整个页面任意位置)
	{% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->

	{% endblock %}

3 其他页面继承写法
	{% extends 'base.html' %}  必须放在页面开头
4 页面中写和母版中名字相同的block块,从而来显示自定义的内容
    {% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
        {{ block.super }}  #这是显示继承的母版中的content中的原内容
        这是xx1
    {% endblock %}

2. 继承问题

{% extends 'base.html' %} 必须放在页面开头

  1. 建base文件,可以命名多个block,不同名即可
  2. 想自定义自己继承后文件的属性,style要放在block中即可
  3. {{ block.super }} 继承父类,注意格式,双括号

3. 组件

网站 www.jq22.com

1 创建html页面,里面写上自己封装的组件内容,title.html
2 新的xx.html页面使用这个组件
	{% include 'title.html' %}

9. 静态文件

1. 标签法

# 引用静态文件      
    {% load static %}       # 自动寻找到static对应的静态资源.
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/dashboard.css' %}">

# 引用js
    {% load static %}    # 自动寻找到static对应的静态资源.
    <script src="{% static "mytest.js" %}"></script> #'/static/mytest.js'

# 多出引用同一个资源时, 可以重新命名.
    {% load static %}
    {% static "images/hi.jpg" as myphoto %}
    <img src="{{ myphoto }}"></img>

2. 别名法

<link rel="stylesheet" href="/static/css/dashboard.css">

3. get_static_prefix

{% load static %}   
<link rel="stylesheet" href="{% get_static_prefix  %}css/dashboard.css">
{% get_static_prefix  %} == /static/ 别名

4. 静态文件配置

1 项目目录下创建一个文件夹,例如名为jingtaiwenjianjia,将所有静态文件放到这个文件夹中
2 settings配置文件中进行下面的配置
	# 静态文件相关配置
    STATIC_URL = '/abc/'  #静态文件路径别名

    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'jingtaiwenjianjia'),
    ]

10. 自定义标签

1. 自定义标签和过滤器

1 在应用app01下创建一个叫做templatetags的包(名称不能改),在里面创建一个py文件,例如my_tags.py
2 在my_tags.py文件中引用django提供的template类,写法
	from django import template
	#register名称不可变,library大写
	register = template.Library()
	
	#自定义过滤器
    @register.filter   # 参数至多两个
    def xx(v1,v2):
        return v1+v2
	#使用:
		{% load my_tags %}   # 加载上文件名xxoo,相当于引入xxoo.py文件
		{{ name|xx:'oo' }}  # xx是函数名 传两个参数
	
# 自定义标签 没有参数个数限制
@register.simple_tag
def num_my(*args,**kwargs):  # 给的参数没有限制
    return '_'.join(args) + "*".join(kwargs.values()) #返回的值是已经处理过的.
#使用
    {% load my_tags %}
	{% num_my "1" "2" "3" a="alex" b="taibai" %} # 注意返回值时join,可迭代,不能是数字,其他方法可以返回数字

    # inclusion_tag 返回html片段的标签
    @register.inclusion_tag('result.html')
    def res(n1): #n1 : ['aa','bb','cc']

        return {'li':n1 }
	使用:
		{% res a %}
	

2. 自定义标签和过滤器大前提

1 在应用下创建一个叫做templatetags的文件夹(名称不能改),在里面创建一个py文件,例如my_tags.py

2 在xx.py文件中引用django提供的template类,写法
	from django import template
	#register名称不可变,library大写
	register = template.Library()

3.自 定义过滤器执行流程

1. 页面请求 127.0.0.1/new/
2. 找到 url(r'^test/', views.test) 执行 test函数
3. test有第三个参数,render{"name":"Alex"}传到test.html文件中
4. {{ name|addoo:"dsb"}}加载my_tags.py文件,调用my_tags中的addoo函数
5. 执行my_tags中的addoo函数 return n1+n2,参数一一对应
6.替换test.html中内容,响应浏览器,显示结果

4. 自定义标签执行流程

1. 页面请求 127.0.0.1/new/
2. 找到 url(r'^new/', views.new) 执行 new函数
3. new有第三个参数,{"name":"Alex"}传到new.html文件中
4. {% load xx %}加载xx.py文件,调用{% res name "dsb" %}函数
5. 执行xx中的res函数 return n1+n2,参数一一对应
6.替换new.html中内容,响应浏览器,显示结果

5. inclusion_tag 返回html片段的标签执行流程

1. 页面请求 127.0.0.1/new/
2. 找到 url(r'^test/', views.test) 执行 test函数
3. test有第三个参数,{"a":a}传到test.html文件中
4. {% load xx %}加载xx.py文件,调用{% res a "s2" %}函数
5. 执行xx中的res函数
6. 将return值返回给@register.inclusion_tag("result.html")的result.html文件
7. 修饰后依次跳回test.html文件,响应浏览器,显示结果

11. 自定义过滤器和标签的区别

1. 前者最多接受2个参数,后者没有限制      {% if 10|add:2 %}
2. 前者可以在作为if的判断条件,后者不可以 不能识别

12. 面试题

cdn地址:https://www.bootcdn.cn/

   模板中使用{% sqr_list 3 %},生成如下的dropdown list 控件(下拉菜单)
    key    text
    1        1的平方是1
    2        2的平方是4
    3        3的平方是9

    请写出sqr_list的实现

views.py

    from django.shortcuts import render

    def index(request):

        return render(request,"index.html")

使用inclusion_tag标签

在app应用中创建templatetags的my_tags.py

from django import template
register = template.Library()

# 第一中方法,列表
@register.inclusion_tag('dropdown_list.html')
def sqr_list(num):
    data = [f'{i} ---{i}的平方是{i**2}' for i in range(1,num+1)]
    return {'data':data} # 传给showhome.html

#第二种方法,字典
@register.inclusion_tag('dropdown_list.html')
def sqr_list(num):
    return {"i":{i:f'{i}的平方是{i**2}' for i in range(1,num+1)}}

index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    {# <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> #}
</head>
<body>
	{% load my_tags %}  # 加载my_tags.py文件
	{% sqr_list 10 %}    # 调用了my_tags文件,传参
    <script src="{% static 'jquery.js' %}"></script>
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>

    {#<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
    {##}

</body>
</html>

showhome.html

# 第一种方法
<div class="dropdown">
    <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown"
            aria-haspopup="true" aria-expanded="false">
        key  text
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
        {% for foo in data %}
            <li><a href="#">{{ foo }}</a></li>
        {% endfor %}
    </ul>
</div>
# 第二种方法
<div class="dropdown">
    <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown"
            aria-haspopup="true" aria-expanded="false">
        key  text
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
        {% for k,v in i.items %}
            <li><a href="#">{{ k }}&nbsp;&nbsp;{{ v }}</a></li>
        {% endfor %}
    </ul>
</div>
原文地址:https://www.cnblogs.com/lvweihe/p/11754647.html