Django之模板层

一. 前言

  Django模板层的知识包括标签,过滤器,自定义标签,自定义过滤器以及inclusion_tag,最重要的是模板的继承和导入,模板层最重要的是模板语法,之前我们涉及到的变量用模板语法{{}},涉及到逻辑用模板语法{% %},这里我们在追加几点,过滤器在模板语法{{ }}中写,而且只能传两个参数;标签在模板语法{% %}中写,且能传多个参数(参数之间用空格隔开).模板的继承和导入也是在模板语法{% %}中写.

  接下来我们回顾下后端朝前端传递数据的两种方式:

from django.shortcuts import render

# Create your views here.

def login(request):
    '''模板语法只有2个:
    渲染变量:{{}} 1.深度查询--->>句点符;2.过滤器
    渲染标签:{% %}
    :param request:
    :return:
    '''
    name = "panshao"
    i = 10      #整型
    l = [1,2,3] #列表 
    info = {"name":"panshao", "age":22} #字典
    b = True    #布尔
    class Person(object):   
        def __init__(self, name, age):
            self.name = name
            self.age = age
    alex = Person("alex",33)  #对象
    egon = Person("egon",38)

    person_list = [alex, egon] 

    #return render(request, "login.html", {"name":name})
    return render(request, "login.html", locals()) #locals是局部变量的意思,这样就不用一个个去对应了;它会把这些局部变量直接传给模板,它传的时候就是按照{“name”:name} {"alex":alex}这种方式传的

  

login.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>index</h1>
    <p>{{ name }}</p>
    <p>{{ i }}</p>
    <p>{{ info }}</p>
    <p>{{ l }}</p>
    <p>{{ alex }}</p>
    <p>{{ person_list }}</p>
    <p>{{ b }}</p>
    <hr>
    深度查询  是用 . 完成的 
    <p>{{ l.1 }}</p>     #我想要第2个元素
    <p>{{ info.name }}</p> #字典下的name那个键
    <p>{{ alex.age }}</p>  #alex这个变量对象
    <p>{{ person_list.1.age }}</p> #person_list中第二个人的年龄

</body>
</html>

  

  两种方法有利有弊,不过在之后我们会选用locals(),后端除了能向前端提交的Python的基本的数据类型: int, float, str, list, dict, tuple, set数据外,还能提交函数与类的对象,当我们传递函数名给前端时,会自动拿到该函数return的结果, 但是不支持传参,只支持传递无参函数.当传递类的对象obj给前端时,相当于print (obj),前端拿到的是该obj的内存地址,因为print(obj)走的是类的__str__()方法.所以传递类对象时,我们重新写__str__()能让前端拿到想要的内容. 前端想要获取后端传递过来的容器类型中的元素时,统一使用句点符(.):

二. 过滤器

  过滤器在模板语法{{ }}中书写,过滤器最多支持传两个参数,(会把|左边的参数当做过滤器的第一个参数传进去),过滤器的基本语法: {{ 参数1|过滤器名字: 参数2}}, 有些过滤器没有参数2

  统计字符串长度{{ s|length}}: 会将s当做length的参数传进去,将s的长度打印出来

  获取的数据为空时就返回default后面定义的值{{ s|default: 's是空的字符串'}}, 这种方法跟后端的get方法很像,default必须要有两个参数

  将数字转化为表示文件大小的格式{{ file_size|filesizeformat}} 给file_size一串数字,会转化为多少兆,多少G之类的,如果file_size是204800,执行该过滤器后就是200kb

  格式化时间{{ ctime|date: 'Y-m-d'}}不需要和后端一样加% ('%Y-%m-%d'),后端代码为

from datetime import datetime
    ctime = datetime.now()

  字符串的切片操作{{s|slice:'0: 8: 2'}},如果s='hello world',执行完该过滤器后是'hlow', slice后面的参数同python字符串切片参数一样,开头: 结尾: 步长,切片顾头不顾尾

  截取固定长度的字符串{{s|truncatechars:10}} 如果s='hello world' 执行完该过滤器后是'hello w...', 超出长度的部分会用...代替,当我们的参数为10时, 实际上截取的字符串长度为7,因为...占3位.

  按照空格截取文本内容{{s|truncatewords:2}}  如果s='he llo wor ld',执行完该过滤器后是:‘he llo ...’,截取至前两个空格,之后的内容用...表示。

  加法亦或是字符串拼接{{ n1|add:n2}}  如果n1=2, n2=4,那么结果为6。如果n1='hello', n2='world',那么结果为'helloworld'

   当我们后端向前端提交的字符串含有标签时,比如'<h1>this is title</h1>',为了防止脚本攻击(比如<script>while(1){alert('come on')}</script>),前端之后把你当成普通的字符串。当我们想要让前端帮我们执行提交的字符串中的标签内容时,有两种方式。

  1. 在前端通过{{字符串|safe}}告诉前端字符串很安全,可以大胆执行

  2. 后端用模块操作一下字符串,告诉前端我们给它的字符串很安全。

 
from django.utils.safestring import mark_safe

def login(request):
    html = reverse('login')
    s = '<h1>this is title</h1>'
    s = mark_safe(s)
    return render(request, 'login.html', locals())

# 前端直接{{ s }}即可

三. 标签

  标签在模板语法中{% %}书写, {% %}涉及到逻辑,标签一般是for循环,f判断以及它们的嵌套使用,除此之外还有empty标签。

  for 循环中可以使用forloop来给我们提供一些信息:

   for循环

<!--l = [1, 2, 3, 4, 5]-->
{% for foo in l %}
    <p>{{ foo }}</p>
    <p>{{ forloop }}</p>
{% endfor %}

  

  if判断

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

  

  if与for嵌套使用

{% for foo in s %}
    {% if forloop.first %}
        <p>这是第一次</p>
    {% elif forloop.last %}
        <p>这是最后一次</p>
    {% else %}
        <p>keep up</p>
    {% endif %}
{% endfor %}

  

  empty

{#{% for foo in '' %}#}
{#    {% if forloop.first %}#}
{#        <p>这是我的第一次</p>#}
{#        {% elif forloop.last %}#}
{#        <p>这是最后一次了啊</p>#}
{#        {% else %}#}
{#        <p>来啊来啊!!!</p>#}
{#    {% endif %}#}
{#    {% empty %}#}
{#    <p>当for循环的对象为空的时候 会走empty</p>#}
{#{% endfor %}#}

  

四. 自定义inclusion_tag

  要自定义过滤器与标签,必须先做三件事

  1. 在应用文件夹下新建templatetags文件夹(必须叫这个名字)
  2. 在templatetags文件夹中新建一个py文件,名字任意,不过最好不要有中文 
  3. 在该py文件中固定写以下两句代码
    from django import template
    
    register = template.Library()

  自定义inclusion_tag

from django import template

register = template.Library()


@register.inclusion_tag('login.html', name='login')
def login(n):
    l = ['第%s项' % i for i in range(n)]
    return {'l': l}

  

<!--login.html-->
<ur>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ur>

  在该例子中, 我们在前端调用inclusion_tag时:

{% load my_tags %}
{% login 5 %} 

  首先会将参数5传给login函数,函数执行完后的结果提交至login.html,然后将login.html的页面显示在调用该inclusion_tag的地方。

  inclusion_tag会将渲染过的login.html界面返回至调用它的位置,正是因为这种机制,所以它所渲染那个html页面中可以不需要head和body等各种标签,你需要返回什么就在里面写什么。

五. 模板的继承

  1. 模板的继承

  首先需要被继承的模板中划分多个区域:

{% block 给区域起的名字 %}

{% endblock %}

  通常情况下一个模板至少需要三块区域:

{% block css %}
    页面css代码块
{% endblock %}

{% block js %}
    页面js代码块
{% endblock %}

{% block content %}
    页面主体内容
{% endblock %}

  子模板继承模板,首先要继承所有的内容:

{% extends 'home.html' %}
{#先继承home,必须写在首行,不然它不知道block是什么意思 跟include不一样,它有它自己独特的优势#}

  根据被block快的名字修改指定区域的内容

{% block content %}
    <h1>登录页面</h1>
    <form action="">
        <p>username:<input type="text" class="form-control"></p>
    <p>password:<input type="text" class="form-control"></p>
    <input type="submit" class="btn btn-success">
    </form>
{% endblock %}

  可以使用{{block.super}}使用父模板的该block的内容(使用该方法没有提示,要手撸)

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

  注意:原模板中的block区域越多越好,因为越多代表可以修改的细节很多,扩展性就越强。继承后,子模板只能修改block区域中的内容。

  2. 静态文件配置

  当我们为了让路由名字改变时我们不需要修改HTML页面和视图函数中的内容,我们引入了反向解析。同理,为了防止settins.py文件夹中static文件夹的接口前缀改变而我们不需要html页面中head中script和link的接口前缀(需要修改的前提是他们导入的是static文件夹中的东西),我们引入了静态文件配置。

{% load static %}  
    
<link rel='stylesheet' href="{% static 'css/mycss.css'%}">  # 第一种方式
<link rel='stylesheet' href="{% get_static_prefix %}css/mycss.css">  # 第二种方式

  

生前无需久睡,死后自会长眠,努力解决生活中遇到的各种问题,不畏将来,勇敢面对,加油,你是最胖的,哈哈哈
原文地址:https://www.cnblogs.com/panshao51km-cn/p/11546207.html