【8.0】Django框架之模板层

发布时间 2023-07-17 11:35:08作者: Chimengmeng

【一】模板语法的传值

{{}} : 变量相关

{%%} : 逻辑相关

【1】数据准备

路由

# 模板语法传值
url(r'^index/',views.index),

【2】基本数据类型

(1)视图

def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())

(2)前端

<p>整型 {{ a }}</p>
<p>浮点型 {{ b }}</p>
<p>字符串 {{ c }}</p>
<p>列表 {{ d }}</p>
<p>字典 {{ e }}</p>
<p>布尔 {{ f }}</p>
<p>元祖 {{ g }}</p>
<p>集合 {{ h }}</p>

(3)页面展示

整型 123

浮点型 11.11

字符串 这是一个示例

列表 ['你好', '我好', '大家好']

字典 {'username': 'dream', 'password': 1223, 'host': 'localhost'}

布尔 True

元祖 (11, 22, 33)

集合 {'可可', '阳阳'}

【3】函数

无返回值

from django.shortcuts import render, HttpResponse

# Create your views here.
from django.views import View


class MyLogin(View):

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        return HttpResponse('POST OK')


def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}
    # 函数
    def func():
        pass

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())
函数 None

有返回值

from django.shortcuts import render, HttpResponse

# Create your views here.
from django.views import View


class MyLogin(View):

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        return HttpResponse('POST OK')


def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}

    # 函数
    def func():
        print("正在执行中....")
        return '执行完成....'

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())
  • 终端打印 正在执行中....
    • 页面展示 执行完成....
整型 123

浮点型 11.11

字符串 这是一个示例

列表 ['你好', '我好', '大家好']

字典 {'username': 'dream', 'password': 1223, 'host': 'localhost'}

布尔 True

元祖 (11, 22, 33)

集合 {'阳阳', '可可'}

函数 执行完成....

总结

  • 函数放到模版语法中会自动调用
    • 但是模版语法不支持给函数添加其他的参数

【4】类与对象

类与对象

def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}

    # 函数
    def func():
        print("正在执行中....")
        return '执行完成....'

    # 类
    class MyClass(object):
        # 普通方法
        def get_self(self):
            return 'my_self'

        # 静态方法
        @staticmethod
        def get_func():
            return 'my_func'

        # 绑定给类的静态方法
        @classmethod
        def get_class(cls):
            return 'my_class'

    # 实例化对象
    obj = MyClass()

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())

整型 123

浮点型 11.11

字符串 这是一个示例

列表 ['你好', '我好', '大家好']

字典 {'username': 'dream', 'password': 1223, 'host': 'localhost'}

布尔 True

元祖 (11, 22, 33)

集合 {'可可', '阳阳'}

函数 执行完成....

自定义类 <app01.views.index.<locals>.MyClass object at 0x00000205E98FB048>

实例化对象 <app01.views.index.<locals>.MyClass object at 0x00000205E98D5358>
  • 传类的时候也会自动调用类实例化出对象
    • 对象就是原来的对象

对象调用方法

整型 123

浮点型 11.11

字符串 这是一个示例

列表 ['你好', '我好', '大家好']

字典 {'username': 'dream', 'password': 1223, 'host': 'localhost'}

布尔 True

元祖 (11, 22, 33)

集合 {'阳阳', '可可'}

函数 执行完成....

自定义类 <app01.views.index.<locals>.MyClass object at 0x000001FE31405438>

实例化对象 <app01.views.index.<locals>.MyClass object at 0x000001FE313DF2B0>

对象调用方法get_func my_func

对象调用方法get_class my_class

对象调用方法get_self my_self
  • 可以调用对象的方法并拿到对应的返回值!

类对象内部的 __str__方法

def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}

    # 函数
    def func():
        print("正在执行中....")
        return '执行完成....'

    # 类
    class MyClass(object):
        # 普通方法
        def get_self(self):
            return 'my_self'

        # 静态方法
        @staticmethod
        def get_func():
            return 'my_func'

        # 绑定给类的静态方法
        @classmethod
        def get_class(cls):
            return 'my_class'
		
        # 类被调用时一定会触发该方法
        # 对象被展示到页面上时,就类似于执行了打印操作,也会触发__str__方法
        def __str__(self):
            return "我被调用啦!"

    # 实例化对象
    obj = MyClass()

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())

整型 123

浮点型 11.11

字符串 这是一个示例

列表 ['你好', '我好', '大家好']

字典 {'username': 'dream', 'password': 1223, 'host': 'localhost'}

布尔 True

元祖 (11, 22, 33)

集合 {'阳阳', '可可'}

函数 执行完成....

自定义类 我被调用啦!

实例化对象 我被调用啦!

对象调用方法get_func my_func

对象调用方法get_class my_class

对象调用方法get_self my_self
  • 类被调用时一定会触发该方法

  • 对象被展示到页面上时,就类似于执行了打印操作,也会触发__str__方法

【小结】

  • 模版语法会自动判断当前位置的变量名是否可以加括号调用
    • 如果可以就会自执行
    • 如果不能执行就会忽略
  • 一般针对的是对象和类

【二】模版语法的取值

Django模版语法的取值,是固定的格式,只能采用“句点符”取值

  • 可以通过 .键 取值
  • 也可以通过 .索引 取值
<p>取值{{ e.username }}</p>
<p>取值{{ d.0 }}</p>
取值dream

取值你好

【三】过滤器

【1】过滤器

  • 过滤器就类似于模版语法内置的内置方法
    • Django内置有60多个过滤器

【2】语法

{{数据|过滤器:参数}}

【3】统计字符串长度

{{ c|length }}
6
  • 源码
def length(value):
    """Returns the length of the value - useful for lists."""
    try:
        return len(value)
    except (ValueError, TypeError):
        return 0

【4】默认值

<p>默认值 {{ f|default:"这是默认值" }}</p>
  • 类似于 get 方法

    • 第一个参数如果是True,就会展示第一个值

    • 如果第一个参数取不到,就会展示第二个值

  • 源码

def default_if_none(value, arg):
    """If value is None, use given default."""
    if value is None:
        return arg
    return value

【5】文件大小

<p>文件大小 {{ file|filesizeformat }}</p>
  • 源码
def filesizeformat(bytes_):
    """
    Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB,
    102 bytes, etc.).
    """
    try:
        bytes_ = float(bytes_)
    except (TypeError, ValueError, UnicodeDecodeError):
        value = ungettext("%(size)d byte", "%(size)d bytes", 0) % {'size': 0}
        return avoid_wrapping(value)

    def filesize_number_format(value):
        return formats.number_format(round(value, 1), 1)

    KB = 1 << 10
    MB = 1 << 20
    GB = 1 << 30
    TB = 1 << 40
    PB = 1 << 50

    negative = bytes_ < 0
    if negative:
        bytes_ = -bytes_  # Allow formatting of negative numbers.

    if bytes_ < KB:
        value = ungettext("%(size)d byte", "%(size)d bytes", bytes_) % {'size': bytes_}
    elif bytes_ < MB:
        value = ugettext("%s KB") % filesize_number_format(bytes_ / KB)
    elif bytes_ < GB:
        value = ugettext("%s MB") % filesize_number_format(bytes_ / MB)
    elif bytes_ < TB:
        value = ugettext("%s GB") % filesize_number_format(bytes_ / GB)
    elif bytes_ < PB:
        value = ugettext("%s TB") % filesize_number_format(bytes_ / TB)
    else:
        value = ugettext("%s PB") % filesize_number_format(bytes_ / PB)

    if negative:
        value = "-%s" % value
    return avoid_wrapping(value)

【6】日期格式化

原始格式

current_time = datetime.datetime.now()
<p>日期格式化 {{ current_time }}</p>
日期格式化 July 12, 2023, 3:57 p.m.

格式化输出

<p>日期格式化 {{ current_time|date:'Y-m-d H:m:s' }}</p>
日期格式化 2023-07-12 15:07:45

【7】切片操作

支持步长切片

c = "这是一个示例"
<p>切片操作 {{ c|slice:'0:4:2' }}</p>
切片操作 这一

【8】切取摘要

  • 可以指定切取长度
  • 按照空格切分

字符

  • 会将 . 算进切取个数
# 一串长文本只想截取某段数据
    page = '# Nginx是什么? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 ,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名 ...'
<p>切取字符 {{ page|truncatechars:10 }}</p>
切取字符 # Nginx...

单词

  • 不会将 . 算进切取个数
 # 切取单词
 sentence = 'I just need someone who will never abandon me'

<p>切取单词 {{ sentence|truncatewords:9 }}</p>
切取单词 I just need someone who will never abandon me

【9】移除指定字符

sentence = 'I just need someone who will never abandon me'
<p>移除指定字符,例空格 {{ sentence|cut:" " }}</p>
移除指定字符,例空格 Ijustneedsomeonewhowillneverabandonme

【10】拼接字符

d = ["你好", "我好", "大家好"]
<p>拼接字符 {{ d|join:"$" }}</p>
拼接字符 你好$我好$大家好

【11】加法

a = 123
<p>拼接字符(加法) {{ a|add:10 }}</p>
拼接字符(加法) 133
  • 源码
def add(value, arg):
    """Adds the arg to the value."""
    try:
        return int(value) + int(arg)
    except (ValueError, TypeError):
        try:
            return value + arg
        except Exception:
            return ''

【12】取消转义

以后在写全栈项目时,前端代码不一定必须在前端页面书写

也可以选择先在后端写好,再传递给前端页面展示

前端转义

msg = '<h1>斋藤</h1>'
<p>转义字符(不转义) {{ msg }}</p>

<p>转义字符(转义) {{ msg|safe }}</p>
转义字符(不转义) <h1>斋藤</h1>

转义字符(转义)

斋藤(已变成h1标题格式)

后端转义

from django.utils.safestring import mark_safe
res = mark_safe('<h1>飞鸟</h1>')
<p>转义字符(转义) {{ res }}</p>
转义字符(转义)

飞鸟(已变成h1标题格式)

【四】标签

【1】forloop

d = ["你好", "我好", "大家好"]
{% for re in d %}

    <p>{{ forloop }}</p>

{% endfor %}
标签
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 3, 'revcounter0': 2, 'first': True, 'last': False}

{'parentloop': {}, 'counter0': 1, 'counter': 2, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}

{'parentloop': {}, 'counter0': 2, 'counter': 3, 'revcounter': 1, 'revcounter0': 0, 'first': False, 'last': True}
  • first

    • 标识 for 循环是否是第一次
  • last

    • 标识 for 循环是否是以后一次
  • counter0

    • 类似索引
  • counter

    • 计数
  • 取值

d = ["你好", "我好", "大家好"]
{% for re in d %}

    <p>{{ re }}</p>

{% endfor %}
你好

我好

大家好

【2】if语句

f = True
{% if f %}
    <p>你好</p>
{% else %}
    <p>我好</p>
{% endif %}
你好

【3】混用 forloop + if

d = ["你好", "我好", "大家好"]
{% for re in d %}
    {% if forloop.first %}
        <p>第一次循环</p>
    {% elif  forloop.last %}
        <p>最后一次循环</p>
    {% else %}
        <p>{{ re }}</p>
    {% endif %}
{% empty %}
    <p>for循环的对象是空,不支持for循环</p>

{% endfor %}
第一次循环

我好

最后一次循环

【五】自定义过滤器标签/inclusion_tag

  • 三步走

    • 要在应用下创建一个名字必须是templatetags文件夹

    • 在该文件夹内创建 任意 名称的py文件

    • 在该文件内必须写下面的话

      from django import template
      
      register = template.Library()
      

【1】自定义过滤器

  • 过滤器只能最多两个参数

(1)templatetags/my_tag.py

from django import template

register = template.Library()


@register.filter(name='dream')
def my_sum(x, y):
    return x + y

(2)前端

import datetime

from django.shortcuts import render, HttpResponse
from django.utils.safestring import mark_safe

# Create your views here.
from django.views import View


class MyLogin(View):

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        return HttpResponse('POST OK')


def index(request):
    # 模板语法可以传递的后端Python数据类型
    # 整型
    a = 123
    # 浮点型
    b = 11.11
    # 字符串
    c = "这是一个示例"
    # 列表
    d = ["你好", "我好", "大家好"]
    # 字典
    e = {"username": "dream", "password": 1223, "host": "localhost"}
    # 布尔
    f = True
    # 元祖
    g = (11, 22, 33)
    # 集合
    h = {"阳阳", "可可"}

    # 函数
    def func():
        print("正在执行中....")
        return '执行完成....'

    # 类
    class MyClass(object):
        # 普通方法
        def get_self(self):
            return 'my_self'

        # 静态方法
        @staticmethod
        def get_func():
            return 'my_func'

        # 绑定给类的静态方法
        @classmethod
        def get_class(cls):
            return 'my_class'

        def __str__(self):
            return "我被调用啦!"

    # 实例化对象
    obj = MyClass()

    current_time = datetime.datetime.now()

    # 一串长文本只想截取某段数据
    page = '# Nginx是什么? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 ,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名 ...'

    # 切取单词
    sentence = 'I just need someone who will never abandon me'

    # 转义
    msg = '<h1>斋藤</h1>'

    from django.utils.safestring import mark_safe
    res = mark_safe('<h1>飞鸟</h1>')

    # 将所有数据打包发送给前端
    return render(request, 'index.html', locals())
<h1>自定义标签的使用</h1>
{% load my_tag %}
<p>{{ a|dream:666 }}</p>
789

【2】自定义标签

from django import template

register = template.Library()


@register.simple_tag(name='plus')
def index(a, b, c, d):
    return f'{a}:{b}:{c}:{d}'
  • 前端页面
<h1>自定义标签的使用</h1>
{% load my_tag %}

<p>{% plus 'dream' 521 369 789 %}</p>
dream:521:369:789

【3】自定义inclusion_tag

  • 先定义一个方法
  • 在页面上调用该方法,并且可以传值
  • 该方法会生成一些数据然后传递给一个前端页面
  • 再将渲染好的页面返回给前端

(1)templatetags/my_tag.py

# 自定义inclusion_tag
@register.inclusion_tag('left_menu.html')
def left(n):
    data = ['第 {} 项'.format(n) for n in range(n)]
    return locals()  # 将data传递给 left_menu

(2)left_menu.html

<ul>
    {% for datum in data %}
        <li>{{ datum }}</li>
    {% endfor %}

</ul>

(3)index.html

<h1>自定义标签的使用</h1>
{% load my_tag %}

{% left 10 %}
  • 前端展示
第 0 项
第 1 项
第 2 项
第 3 项
第 4 项
第 5 项
第 6 项
第 7 项
第 8 项
第 9 项

(4)总结

  • 当html页面的某一个地方的页面需要传参数才能动态的渲染出来,并且在多个页面上都需要使用到的局部,那么就考虑将该局部页面做成 inclusion_tag 形式

【六】模版的继承

  • 某些页面的整体大差不差,但是某一些局部在做变化