Django模板层

后端向前端模板层发送数据的两种方式

第一种直接发送字典的形式:

后端view视图函数层
def index(request):
    name = 'ZhaoKang'
    return render(request,'index.html',{'name':name})

前端模板层:
<p>{{ name }}</p>  # 注意前端要拿后端发送过来的数据的时候一定要用{{}}来接收 然后取字典的键就可以拿出值
后端view视图函数层
def index(request):
    name = 'ZhaoKang'
    return render(request,'index.html',{'name':name})

前端模板层:
<p>{{ name }}</p>  # 注意前端要拿后端发送过来的数据的时候一定要用{{}}来接收 然后取字典的键就可以拿出值

方式二locals():

# locals() 将当前所在的名称空间中的名字全部传递给前端页面
后端view视图层
def index(request):
    name = 'ZhaoKang'
    return render(request,'index.html',locals())
前端模板层
<p>{{ name }}</p>
# locals() 将当前所在的名称空间中的名字全部传递给前端页面
后端view视图层
def index(request):
    name = 'ZhaoKang'
    return render(request,'index.html',locals())
前端模板层
<p>{{ name }}</p>

不知道你们有没有发现,我上面传的是字符串类型,既然我上面传的是字符串类型不防试试,数字类型(整型和浮点型),列表,字典,元祖,集合,函数,类,看看能不能传到前端?

后端视图层
def index(request):
    name = 'ZhaoKang'
    age = 18
    salary = 16000.666
    l = [1,3.14,'zk',[1,2,3],{'name':'zk'},(1,2),{3,4}]
    dic = {'name':'zhaokang','age':18}
    t = (1,2)
    s = {1,2,3,4}
    def func():
        print(111)


    class C(object):
        def __init__(self,name):
            self.name = name

        def index(self):
            return self.name

        @classmethod
        def func(cls):
            return cls

    obj = C('zhaokang')
    print(obj)
    return render(request,'index.html',locals())

前端模板层
<p>{{ name }}</p>  # ZhaoKang
<p>{{ age }}</p>  # 18
<p>{{ salary }}</p> # 16000.666
<p>{{ l }}</p> # [1, 3.14, 'zk', [1, 2, 3], {'name': 'zk'}, (1, 2), {3, 4}]
<p>{{ dic }}</p> # {'name': 'zhaokang', 'age': 18}
<p>{{ t }}</p> # (1, 2)
<p>{{ s }}</p> # {1, 2, 3, 4}
<p>{{ func }}</p> # None
<p>{{ obj }}</p> # <app01.views.index.<locals>.C object at 0x04178D90>

后端视图层
def index(request):
    name = 'ZhaoKang'
    age = 18
    salary = 16000.666
    l = [1,3.14,'zk',[1,2,3],{'name':'zk'},(1,2),{3,4}]
    dic = {'name':'zhaokang','age':18}
    t = (1,2)
    s = {1,2,3,4}
    def func():
        print(111)


    class C(object):
        def __init__(self,name):
            self.name = name

        def index(self):
            return self.name

        @classmethod
        def func(cls):
            return cls

    obj = C('zhaokang')
    print(obj)
    return render(request,'index.html',locals())

前端模板层
<p>{{ name }}</p>  # ZhaoKang
<p>{{ age }}</p>  # 18
<p>{{ salary }}</p> # 16000.666
<p>{{ l }}</p> # [1, 3.14, 'zk', [1, 2, 3], {'name': 'zk'}, (1, 2), {3, 4}]
<p>{{ dic }}</p> # {'name': 'zhaokang', 'age': 18}
<p>{{ t }}</p> # (1, 2)
<p>{{ s }}</p> # {1, 2, 3, 4}
<p>{{ func }}</p> # None
<p>{{ obj }}</p> # <app01.views.index.<locals>.C object at 0x04178D90>

各种数据类型以及函数,类,都是可以完成传值的,但是有几点问题

第一:为什么函数拿到的结果是None,函数不是在被加括号的时候才能执行函数体内的代码吗,这里我单独拿出来试试。

后端view层
    def func():
        return '你调用了我'
    前端模板层
    <p>{{ func }}</p> # 你调用了我
    后端view层
    def func():
        return '你调用了我'
    前端模板层
    <p>{{ func }}</p> # 你调用了我

有没有发现这里返回的是“你调用了我”,所以这里可以得出结论是:后端传函数名到前端,会自动加括号调用,且拿到的是函数的返回值。

注意:后端传函数名到前端,会自动加括号调用,但是不支持传参,如果不行不防可以试试。

第二:为什么后端传对象到前端只能拿到一个内存地址呢?

因为后端传对象到前端的时候自动会帮你打印这个对象。

还可以通过对象点的方式拿到类里面的属性和方法,你信你试试

<p>{{ obj.name }}</p> # zhaokang
<p>{{ obj.func }}</p> # <class 'app01.views.index.<locals>.C'>
<p>{{ obj.index }}</p> # zhaokang
<p>{{ obj.name }}</p> # zhaokang
<p>{{ obj.func }}</p> # <class 'app01.views.index.<locals>.C'>
<p>{{ obj.index }}</p> # zhaokang

第三我列表,字典,元祖,集合,里面有多个值我怎么获取到里面的某个值呢。

<p>{{ l.0 }}</p> # 拿到的就是列表的第一个元素就相当于索引取值
<p>{{ t }}</p> # 元祖也是一样通过 点索引的方式
<p>{{ s }}</p> # 集合也是一样通过 点索引的方式
<p>{{ dic.name }}</p> # 几点可以通过点它的键的方式来获取它的值
<p>{{ l.0 }}</p> # 拿到的就是列表的第一个元素就相当于索引取值
<p>{{ t }}</p> # 元祖也是一样通过 点索引的方式
<p>{{ s }}</p> # 集合也是一样通过 点索引的方式
<p>{{ dic.name }}</p> # 几点可以通过点它的键的方式来获取它的值

补充:字符串,列表,字典,元祖,集合可以点出所有的内置方法的,不是所有的方法都是在前端可以用的,只有那些不需要传参的内置方法才可以实现,比如字典 values(),items(),keys()

过滤器:

<p>前端统计字符串的长度:{{ l|length }}</p>  <!--结果为7-->
flag = None # 我后端给flag设置值为None
<p>前端获取数据如果是空就返回default后面默认的参数值:{{ flag|default:'你这个东西是个空'}}</p>

<p>将数字格式化成表示文件大小的单位:{{ file_size|filesizeformat }}</p>
<p>格式化时间(不要加百分号){{ ctime|date:'Y-m-d' }}</p>
<p>字符串的切片操作:{{ res|slice:'0:8' }}</p>
<p>{{ res|slice:'0:8:2' }}</p> 从0开始到7个字符且步长为2 相当于python中的切片顾头不顾尾
<p>截取固定的长度的字符串 三个点也算:{{ res|truncatechars:10 }}</p>
<p>按照空格截取文本内容:{{ res|truncatewords:4 }}</p>
<p>前端统计字符串的长度:{{ l|length }}</p>  <!--结果为7-->
flag = None # 我后端给flag设置值为None
<p>前端获取数据如果是空就返回default后面默认的参数值:{{ flag|default:'你这个东西是个空'}}</p>

<p>将数字格式化成表示文件大小的单位:{{ file_size|filesizeformat }}</p>
<p>格式化时间(不要加百分号){{ ctime|date:'Y-m-d' }}</p>
<p>字符串的切片操作:{{ res|slice:'0:8' }}</p>
<p>{{ res|slice:'0:8:2' }}</p> 从0开始到7个字符且步长为2 相当于python中的切片顾头不顾尾
<p>截取固定的长度的字符串 三个点也算:{{ res|truncatechars:10 }}</p>
<p>按照空格截取文本内容:{{ res|truncatewords:4 }}</p>

过滤器

描述

示例

upper

以大写方式输出

{{ user.name | upper }}

add

给value加上一个数值

{{ user.age | add:”5” }}

addslashes

单引号加上转义号

capfirst

第一个字母大写

{{ ‘good’| capfirst }} 返回”Good”

center

输出指定长度的字符串,把变量居中

{{ “abcd”| center:”50” }}

cut

删除指定字符串

{{ “You are not a Englishman” | cut:”not” }}

date

格式化日期

default

如果值不存在,则使用默认值代替

{{ value | default:”(N/A)” }}

default_if_none

如果值为None, 则使用默认值代替

dictsort

按某字段排序,变量必须是一个dictionary

{% for moment in moments | dictsort:”id” %}

dictsortreversed

按某字段倒序排序,变量必须是dictionary

divisibleby

判断是否可以被数字整除

{{ 224 | divisibleby:2 }} 返回 True

escape

按HTML转义,比如将”<”转换为”&lt”

filesizeformat

增加数字的可读性,转换结果为13KB,89MB,3Bytes等

{{ 1024 | filesizeformat }} 返回 1.0KB

first

返回列表的第1个元素,变量必须是一个列表

floatformat

转换为指定精度的小数,默认保留1位小数

{{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入

get_digit

从个位数开始截取指定位置的数字

{{ 123456 | get_digit:’1’}}

join

用指定分隔符连接列表

{{ [‘abc’,’45’] | join:’’ }} 返回 abc45

length

返回列表中元素的个数或字符串长度

length_is

检查列表,字符串长度是否符合指定的值

{{ ‘hello’| length_is:’3’ }}

linebreaks



标签包裹变量

{{ “Hi\n\nDavid”|linebreaks }} 返回

Hi

David

linebreaksbr


标签代替换行符

linenumbers

为变量中的每一行加上行号

ljust

输出指定长度的字符串,变量左对齐

{{‘ab’|ljust:5}}返回 ‘ab ’

lower

字符串变小写

make_list

将字符串转换为列表

pluralize

根据数字确定是否输出英文复数符号

random

返回列表的随机一项

removetags

删除字符串中指定的HTML标记

{{value | removetags: “h1 h2”}}

rjust

输出指定长度的字符串,变量右对齐

slice

切片操作, 返回列表

{{[3,9,1] | slice:’:2’}} 返回 [3,9] {{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’

slugify

在字符串中留下减号和下划线,其它符号删除,空格用减号替换

{{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23

stringformat

字符串格式化,语法同python

time

返回日期的时间部分

timesince

以“到现在为止过了多长时间”显示时间变量

结果可能为 45days, 3 hours

timeuntil

以“从现在开始到时间变量”还有多长时间显示时间变量

title

每个单词首字母大写

truncatewords

将字符串转换为省略表达方式

{{ 'This is a pen' | truncatewords:2 }}返回``This is ...

truncatewords_html

同上,但保留其中的HTML标签

{{ '<p>This is a pen</p>' | truncatewords:2 }}返回``<p>This is ...</p>

urlencode

将字符串中的特殊字符转换为url兼容表达方式

{{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}}

urlize

将变量字符串中的url由纯文本变为链接

wordcount

返回变量字符串中的单词数

yesno

将布尔变量转换为字符串yes, no 或maybe

{{ True | yesno }}{{ False | yesno }}{{ None | yesno }} ``返回 ``yes``no ``maybe

转义和取消转义:

当我们在后台写一串字符串的写的是前端html的标签,然后在发送给前端这时我们会发现得到的根本不是我们想要的,如果我们写一段html标签前面也展示出来了,那就意味着别人就可以实现脚本攻击,对你的网站进行攻击。

后端
def index(request):
    s = '<p>苍茫的天涯是我的爱</p>'
    return render(request,'index.html',locals())
前端
{{ s }} # 打印结果是:<p>苍茫的天涯是我的爱</p>
后端
def index(request):
    s = '<p>苍茫的天涯是我的爱</p>'
    return render(request,'index.html',locals())
前端
{{ s }} # 打印结果是:<p>苍茫的天涯是我的爱</p>

如果我就是想要我后端发一段前端html的代码前端就显示出,那怎么办呢,可以通过safe来实现?

前端实现方式
{{ s|safe  }} <!--结果就是带段落标签的一段话了-->
后端实现方式
作为调包侠肯定想到的就是调包啊
from django.utils.safestring import mark_safe
s = mark_safe('<p>苍茫的天涯是我的爱</p>')
前端实现方式
{{ s|safe  }} <!--结果就是带段落标签的一段话了-->
后端实现方式
作为调包侠肯定想到的就是调包啊
from django.utils.safestring import mark_safe
s = mark_safe('<p>苍茫的天涯是我的爱</p>')

标签:

for循环

for循环
            {% for foo in l %}
                <p>{{ foo }}</p>
                <p>{{ forloop }}</p>
            {% endfor %}
for循环
            {% for foo in l %}
                <p>{{ foo }}</p>
                <p>{{ forloop }}</p>
            {% endfor %}

if判断

if判断
            {% if flag %}
                <p>flag不为空</p>
                {% else %}
                <p>flag是空</p>
            {% endif %}
if判断
            {% if flag %}
                <p>flag不为空</p>
                {% else %}
                <p>flag是空</p>
            {% endif %}

嵌套使用

{% for foo in l %}
    {% if forloop.first %}
    <p>这是我的第一次</p>
    {% elif forloop.last %}
    <p>这是最后一次了啊</p>
    {% else %}
    <p>嗨起来!!!</p>
    {% endif %}
{% endfor %}
{% for foo in l %}
    {% if forloop.first %}
    <p>这是我的第一次</p>
    {% elif forloop.last %}
    <p>这是最后一次了啊</p>
    {% else %}
    <p>嗨起来!!!</p>
    {% endif %}
{% endfor %}

empty

empty
            当你的for循环对象为空的时候会自动走empty代码块儿的内容
            后端:
                l = None
            前端:
            {% for foo in l %}
                {% if forloop.first %}
                    <p>这是我的第一次</p>
                {% elif forloop.last %}
                    <p>这是最后一次了啊</p>
                {% else %}
                    <p>嗨起来!!!</p>
                {% endif %}
                {% empty %}
                    <p>你给我的容器类型是个空啊,没法for循环</p>
            {% endfor %}
empty
            当你的for循环对象为空的时候会自动走empty代码块儿的内容
            后端:
                l = None
            前端:
            {% for foo in l %}
                {% if forloop.first %}
                    <p>这是我的第一次</p>
                {% elif forloop.last %}
                    <p>这是最后一次了啊</p>
                {% else %}
                    <p>嗨起来!!!</p>
                {% endif %}
                {% empty %}
                    <p>你给我的容器类型是个空啊,没法for循环</p>
            {% endfor %}

自定义过滤器:

必须做三件事情

1.在应用名下新建一个名为templates文件夹(必须叫这个名字)

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

3.在该py文件中需要固定写下面两句代码

from django import template

register = template.Library()

自定义过滤器

from django import template
from django.utils.safestring import mark_safe
register = template.Library()  #register的名字是不可变的固定写法

@register.filter
def filter_multi(v1,v2):
    return v1*v2
from django import template
from django.utils.safestring import mark_safe
register = template.Library()  #register的名字是不可变的固定写法

@register.filter
def filter_multi(v1,v2):
    return v1*v2

前端使用

{% load templatetags %}
{{ 2|filter_multi:6 }} # 得到的结果是12
{% load templatetags %}
{{ 2|filter_multi:6 }} # 得到的结果是12

注意:标签用在{%%}里面,过滤器用在{{}}里面

自定义标签:

后端

from django import template
from django.utils.safestring import mark_safe
register = template.Library()  # register的名字是不可变的固定写法
@register.simple_tag() # 这里可以给个name='' 去别名 前端用的话直接拿别名就可以了
def add1(a1,a2,a3):
    return a1+a2+a3  # 一定要有返回值

from django import template
from django.utils.safestring import mark_safe
register = template.Library()  # register的名字是不可变的固定写法
@register.simple_tag() # 这里可以给个name='' 去别名 前端用的话直接拿别名就可以了
def add1(a1,a2,a3):
    return a1+a2+a3  # 一定要有返回值

前端

{% add1 'zk' ' is' ' 很帅' %} 结果 zk is 很帅
{% add1 'zk' ' is' ' 很帅' %} 结果 zk is 很帅

注意:在你新定义一个标签过滤器一定要重新django项目不然会抛异常

标签是不能使用在if中的,而过滤器可以

过滤器

{% if 2|filter_multi:6 %}
        <p>ok</p>  结果是ok
    {% endif %}

标签

{% if add 'zk' 'is' '很帅' %}   这个地方直接就报错了
<p>ok</p>
{% endif %}

模板的导入:

1 模版导入-->写了一个好看的组件,可以复用,
        1 写一个模板
        2 在模板中:{% include '模板的名字'%}

2 模板的继承
        1 写一个母版,留一个可扩展的区域(盒子),可以留多个盒子(留的越多,可扩展性越高)
            {%block 名字%}
                可以写内容
            {%endblock%}
        2 在子模板中使用:
            {%block 名字%}
                子模板的内容
            {%endblock 名字%}

3 静态文件相关
        1 写死静态文件:<link rel="stylesheet" href="/static/css/mycss.css">
        2 使用 static标签函数:
            -{%load static%}
            #static返回值,会拼上传参的路径
            -{% static "传参"%}
        3 使用get_static_prefix 标签
            -{%load static%}
            #get_static_prefix返回值是:静态文件的地址,相当于/static/
            -{% get_static_prefix %}css/mycss.css