4.模版渲染

4.1settings文件配置

settings配置文件中的TEMPLATES项是对静态页面的设置,DIRS处需要写上对应的静态文件存放的位置,默认为templates

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]  #别忘了配置这个路径
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

4.2模版语法

在html文件标签中写

{{ 变量 }}   {% 逻辑 %}

4.3万能的点 .

html文件

以下代码中dic.name就是.的运用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{ num }}</h1>
    <h1>{{ str }}</h1>
    <h1>{{ lst }}</h1>
    <h1>{{ dic.name }}</h1>
{#    #注意,调用方法时,不能加括号,所有如果方法带参数,就没法用了#}
    <h1>{{ woman.play }}</h1>
    <h1>{{ woman.xx }}</h1>

</body>
</html>

views文件

from django.shortcuts import render,HttpResponse,redirect
from django.views import View   #CBV进程的类
# Create your views here.

def home(request):
    # return HttpResponse('登陆成功')
    # return render(request,'index.html')
    num = 10
    str = 'I am a running 的草泥马'
    lst = [1,2,3,4,5,6]
    dic = {'name':'小明','age':20}

    class A:
        money = 100
        def __init__(self):
            self.xx = 'oo'
        def play(self):
            return '什么价位?'
    woman = A()

    return render(request,'模版渲染.html',{'num':num,'str':str,'lst':lst,'dic':dic,'woman':woman})

运行后的初次效果

iShot2020-10-16 14.24.24

4.4过滤器

4.4.1过滤器用法

有参数的过滤器用法

{{ 变量|过滤器名称:'参数' }}

没参数的过滤器用法

{{ 变量|过滤器名称 }}

4.4.2内置过滤器

views文件

from django.shortcuts import render,HttpResponse,redirect
from django.views import View   #CBV进程的类
# Create your views here.

def home(request):
    # return HttpResponse('登陆成功')
    # return render(request,'index.html')
    num = 10
    str = 'I am a running 的草泥马'
    lst = [1,2,3,4,5,6]
    dic = {'name':'小明','age':20}

    class A:
        money = 100
        def __init__(self):
            self.xx = 'oo'
        def play(self):
            return '什么价位?'
    woman = A()

    return render(request,'模版渲染.html',{'num':num,'str':str,'lst':lst,'dic':dic,'woman':woman})

4.4.2.1 truncatechars 截断字符串

truncatechars:数字 数字表示要截断的字符数

未截断前

iShot2020-10-16 14.24.48

截断后

truncatechars:5表示截取5个字符,其中包括3个.

<h1>{{ str | truncatechars:5 }}</h1>

iShot2020-10-16 14.25.13

4.4.2.2 default 如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值

在views文件中只有num变量,没有num1变量,因此使用default指定的值

<h1>{{ num1 | default:'没有num1这个变量' }}</h1>

iShot2020-10-16 14.25.30

4.4.2.3 length 获取变量数据长度

<h1>{{ lst | length }}</h1>

4.4.2.4 filesizeformat 大小按照人类可读方式显示

views文件中定义file_size = 1024,注意还需要在render方法中以字典的形式定义返回

<h1>{{ file_size | filesizeformat }}</h1>

iShot2020-10-16 14.25.46

4.4.2.5 slice 切片(顾头不顾腚)

<h1>{{ str | slice:'2:9' }}</h1>

iShot2020-10-16 14.26.06

使用切片截取

iShot2020-10-16 14.26.22

4.4.2.6 date 日期格式化显示

views文件
import datetime
now = datetime.datetime.now()
注意在render方法中返回

html文件
<h1>{{ now | date:'Y-m-d H:i:s' }}</h1>

iShot2020-10-16 14.27.07

4.4.2.7 safe 关闭HTML的自动转义

safe是防止xss攻击让一些js、html等等代码变成普通字符而不执行,但有的时候我们想要执行这些代码,就需要用到safe

Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样就可以搞一些坏事儿了,写个弹窗的死循环,浏览器会一直弹窗,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过 过滤器"|safe" 的方式告诉Django这段代码是安全的不必转义。

views文件中定义了一个a_tag,我门现在就想让这个标签成为一个超链接
a_tag = "<a href='http://www.baidu.com'>百度</a>"

html文件
<h1>{{ a_tag | safe }}</h1>

没有加safe

iShot2020-10-16 14.27.27

加上safe后

iShot2020-10-16 14.27.41

4.4.2.8 join 字符串拼接列表

views文件
lst = [1,2,3,4,5,6]

html文件
<h1>{{ lst | join:"+"}}</h1>

iShot2020-10-16 14.28.01

4.4.2.9 cut 移除变量中所有的与给出的变量相同的字符串

views文件
str = 'I am a running 的草泥马'

html文件
<h1>{{ str | cut:' ' }}</h1>

iShot2020-10-16 14.28.23

4.5标签

4.5.1 for标签

for标签语法

{% for foo in 循环的对象 %}

{% endfor %}

for标签循环列表简单示例

views文件

def home(request):
    lst = [1,2,3,4,5]
    return render(request,'home.html',{'lst':lst})

html文件

<body>
<ul>
    {% for foo in lst %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
</body>

结果如下

iShot2020-10-16 14.28.56

<body>
<ul>
    {% for foo in lst reversed %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
</body>

iShot2020-10-16 14.29.17

for标签循环字典简单示例

views文件

def home(request):
    lst = [1,2,3,4,5]
    dic = {'name':'小明','age':20,'hobby':'唱、跳、rap、篮球'}
    return render(request,'home.html',{'lst':lst,'dic':dic})

html文件

<ol>
    {% for foo in dic.items %}  //这里可以循环字典的键、值、键和值
        <li>{{ foo }}</li>
    {% endfor %}
</ol>


<ol>
    {% for key,value in dic.items %}
        <li>{{ key }}--->{{ value }}</li>
    {% endfor %}
</ol>

iShot2020-10-16 14.30.08

iShot2020-10-16 14.30.33

for标签中的empty

 {% for i in lst1 %} #当没有数据时,会生成empty的内容
        <li>{{ i }}</li>
    {% empty %}
        <p>啥数据也没有!</p>
    {% endfor %}

for标签中的forloop方法,必须在循环内使用

forloop.counter            #当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能
forloop.counter0           #当前循环的索引值(从0开始)
forloop.revcounter         #当前循环的倒序索引值(从1开始)
forloop.revcounter0        #当前循环的倒序索引值(从0开始)
forloop.first              #当前循环是不是第一次循环(布尔值)
forloop.last               #当前循环是不是最后一次循环(布尔值)
forloop.parentloop         #本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

forloop.counter #当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能

<ol>
    {% for key,value in dic.items %}
        <li>{{ forloop.counter }}{{ key }}--->{{ value }}</li>
    {% endfor %}
</ol>

iShot2020-10-16 14.31.35

forloop.counter0 #当前循环的索引值(从0开始)

<ol>
    {% for key,value in dic.items %}
        <li>{{ forloop.counter0 }}{{ key }}--->{{ value }}</li>
    {% endfor %}
</ol>

iShot2020-10-16 14.32.08

forloop.first #当前循环是不是第一次循环(布尔值)

<ol>
    {% for key,value in dic.items %}
        <li>{{ forloop.first }} {{ key }}--->{{ value }}</li>
    {% endfor %}
</ol>

iShot2020-10-16 14.32.34

forloop.parentloop #本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

views文件

def home(request):
    lst = [1,2,3,4,5]
    dic = {'name':'小明','age':20,'hobby':['唱','跳','rap','篮球']}
    return render(request,'home.html',{'lst':lst,'dic':dic})

html文件

<ol>
    {% for key,value in dic.items %}
        <li>{{ forloop.last }} {{ key }}--->{{ value }}</li>
        {% for foo in dic.hobby %}
           {{ forloop.parentloop.counter }}---{{ forloop.counter }}<a href="">{{ foo }}</a>
        {% endfor %}
    {% endfor %}
</ol>

iShot2020-10-16 14.32.55

4.5.2 if标签

if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格

views文件

def home(request):
    num = 100
    str = 'helow'
    lst = [1,2,3,4,5]
    dic = {'name':'小明','age':20,'hobby':'唱、跳、rap、篮球'}
    return render(request,'home.html',{'lst':lst,'dic':dic,'num':num,'str':str})

html文件

普通判断

{% if num == 100 %}
    <p>数字等于100</p>
{% else %}
    <p>数字不等于100</p>
{% endif %}


#语法
{% if %}
{% elif %}
{% else %}
{% endif %}        //以endif结尾

结合过滤器使用

{% if str|length == 5 %}
    <p>字符串长度为5</p>
{% endif %}

4.5.3 with标签

用于给比较长的数据调用起别名,只能在with标签中只用

views文件

def home(request):
    lst = [1,2,{'name':'小明','age':20},4,5]

    return render(request,'home.html',{'lst':lst}

html文件

html文件中想渲染views文件中返回的列表中的元素中的字典的值,如果每一次都写的话会比较长,例如lst.2.name,这个时候我们就可以取一个别名,用于给这个数据的调用,这样的话下次别的地方有引用的时候写起啦会比较简单

//例如,h1标签和a标签中都想引用这个数据的调用,没有起别名之前的写法,这样每次引用都需要在写一遍,比较麻烦
<h1>
    {{ lst.2.name }}
</h1>
<a href="">{{ lst.2.name }}</a>


//这个时候就可以用到with别名的方法
<h1>
    {% with lst.2.name as l %}
        <a href="">{{ l }}</a>
    {% endwith %}
</h1>

4.5.4 csrf_token 通过csrf认证机制

#写法
{% csrf_token %}

csrf_token
    我们以post方式提交表单的时候,会报错,我们在settings里面的中间件配置里面把一个csrf的防御机制给注销了,本身不应该注销的,而是应该学会怎么使用它,并且不让自己的操作被forbiden,通过这个东西就能搞定。

    这个标签用于跨站请求伪造保护,

    在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隐藏的,这个标签的值是个随机字符串,提交的时候,这个东西也被提交了,首先这个东西是我们后端渲染的时候给页面加上的,那么当你通过我给你的form表单提交数据的时候,你带着这个内容我就认识你,不带着,我就禁止你,因为后台我们django也存着这个东西,和你这个值相同的一个值,可以做对应验证是不是我给你的token,就像一个我们后台给这个用户的一个通行证,如果你用户没有按照我给你的这个正常的页面来post提交表单数据,或者说你没有先去请求我这个登陆页面,而是直接模拟请求来提交数据,那么我就能知道,你这个请求是非法的,反爬虫或者恶意攻击我的网站

4.6自定义标签和自定义过滤器

4.6.1自定义标签

1.在应用程序目录中创建一个templatetags目录(名称只能叫templatetags)

2.在templatetabs目录中创建xx.py

3.在xx.py中导入template

from django import template

#变量名称必须叫register
register = template.Library()

#自定义标签
@register.simple_tag
def tag(v1):
    return v1 + 'tag'

使用自定义标签

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
    name = 'hehe'
    return render(request,'tags.html',{'name':name})

tags.html文件

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的标签
{% load xx %}
<h1>
    {% tag name %}
</h1>

args.html文件中不给自定义标签传参数

iShot2020-10-16 14.33.49

views文件中指定给自定义的标签传2个参数,v1是views中tag函数定义的变量name,v2就是args.html中自定义标签传的一个参数

from django import template

#变量名称必须叫register
register = template.Library()

#自定义标签
@register.simple_tag
def tag(v1,v2):
    return v1 + 'tag' + v2

args.html文件中给自定义标签传参

<h1>
    {% tag name '参数1' %}
</h1>

iShot2020-10-16 14.34.19

4.6.2自定义过滤器

1.在应用程序目录中创建一个templatetags目录(名称只能叫templatetags)

2.在templatetabs目录中创建xx.py

3.在xx.py中导入template

from django import template

#变量名称必须叫register
register = template.Library()

#自定义过滤器,最多2个参数    这里自定义一个过滤器,接受任意一个参数,给这个参数后边加一个字符串

@register.filter
def oo(v1):
    return v1 + 'oo'

使用自定义过滤器

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
    name = 'hehe'
    return render(request,'tags.html',{'name':name})

tags.html

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的过滤器
{% load xx %}
<h1>
    {{ name | oo }}
</h1>

结果如下,可以看到,我们自定义的过滤器,接受任意一个参数,给这个参数后边加一个字符串oo

iShot2020-10-16 14.34.54

上述结果是xx.py就是我们自定义的过滤器文件中的函数只传了一个参数,现在我们给这个函数传2个参数(最多传两个参数)

xx.py写法

from django import template

#变量名称必须叫register
register = template.Library()

#自定义过滤器,最多2个参数    这里自定义一个过滤器,接受任意一个参数,给这个参数后边加一个字符串

@register.filter
def oo(v1,v2):
    return v2 + 'oo' + v1

上述代码中v1是views中定义的name变量的值,也就是hehe,v2就是tags.html中函数oo后面传的参数,因此打印的结果就是
哈哈oohehe

urls文件

 url(r'^tags/', views.tags),

views文件

def tags(request):
    name = 'hehe'
    return render(request,'tags.html',{'name':name})

tags.html

//这里表示引入应用程序目录下templatetags目录中自定义的xx.py,这个xx.py中是我们自定义的过滤器
{% load xx %}
<h1>
    {{ name | oo:'哈哈' }}
</h1>

iShot2020-10-16 14.35.15

4.6.3 inclusion_tag 修改引入组件的样式( 非常难理解

inclusion_tag作用如下iShot2020-10-16 14.35.41

接下来开始整个过程

第一步、先在django项目同路径下的templates目录下创建一个菜单静态页面作为一个组件

zujian.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .menus{
            width: 200px;
        }
        .menus .item{
            background-color: green;
            color: white;
            height: 50px;
        }
    </style>
</head>
<body>
<div class="menus">
    <div class="item">菜单1</div>
    <div class="item">菜单2</div>
    <div class="item">菜单3</div>
</div>

</body>
</html>

效果如下

iShot2020-10-16 14.36.22

第二步、分别在urls和views文件中写上对应的访问路径和函数

这里在后边定义一个xx.html,这个xx.html引入组件文件zujian.html,并且访问路径是xx,视图中的函数也叫xx(返回xx.html)

urls文件

url(r'^xx/', views.xx),

views文件

def xx(request):
    return render(request,'xx.html')

第三步、还是在templates目录下创建一个xx.html文件,这个html文件引入刚才创建的组件文件

xx.html文件初始内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .nav{
            height: 200px;
            width: 150px;
            background-color: burlywood;
        }
    </style>
</head>
<body>
<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
</body>
</html>

初始xx.html

iShot2020-10-16 14.36.48

接下来在xx.html文件中引入组件文件的样式

在div标签下引入zujian.html

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{% include 'zujian.html' %}

引入组件后的样式,绿色为zujian.html文件中的内容

iShot2020-10-16 14.37.30

接下来想要将引入的样式中的菜单栏变为其他内容,需要做以下操作,在组件文件zujian.html文件中将想要更改的内容利用for循环便利

zujian.html文件

<div class="menus">
    //利用for循环遍历data变量,foo就是data变量中的所有内容,这样的话就做成了动态的效果,原先的菜单栏div标签现在只需要写一个,因为foo是变量data中所有的值
    {% for foo in data %}
        <div class="item">{{ foo }}</div>
    {% endfor %}

//注释之前的菜单栏,因为我们需要用到动态传入内容
{#    <div class="item">菜单1</div>#}
{#    <div class="item">菜单2</div>#}
{#    <div class="item">菜单3</div>#}
</div>


这里有个问题,现在想把zujian.html文件中的菜单栏做一下动态修改,这里写了从data中取值,但是循环遍历的data是从哪来的???这时就引出了inclusion_tag
inclusion_tag需要写在templatetags目录下自定义的py文件中,而data就是我们自定义的返回给xx.html文件的动态内容,因为xx.html引入zujian.html的样式是固定的,只有zujian.html文件中定义的内容

第四步、在templatetags目录下创建一个mytags.py

templatetags目录是在django项目的应用程序目录下创建的目录,在自定义标签和自定义过滤器的时候必须创建这个目录,且名字只能是这个,在这个templatetags目录下创建的py文件中自定义标签和过滤器

mytags.py

@register.inclusion_tag('zujian.html')是固定写法,括号中的参数就是组件文件,这里的data是我们自定义的字典


@register.inclusion_tag('zujian.html')
def hehe(v1):
    return {'data':['唱','跳','rap','篮球']}

第五步、在xx.html文件中引入动态内容

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %}        //引入自定义函数的那个文件名
{% hehe %}                    //引入自定义函数,用于返回data

最终运行效果如下,引入的组件的背景颜色绿色没有改变,但是改变了之前的菜单栏

iShot2020-10-16 14.38.25

整个过程总结

1.定义urls

url(r'^xx/', views.xx),

2.定义视图

def xx(request):
    return render(request,'xx.html')

3.xx.html文件引入组件文件zujian.html,组件中只定义了一个背景色,但是xx.html文件想要动态的添加一些内容,例如菜单栏,此时需要在组件文件中做如下改动

组件文件中定义的背景色

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .menus{
            width: 200px;
        }
    </style>
</head>
<body>
<div class="menus">
</div>
</body>
</html>

利用for循环去循环一个变量,例如data,这个变量是在django项目下的应用程序目录下的templatetags下的任意名称py文件中利用@register.inclusion_tag('zujian.html')和自定义函数中的return返回值定义的变量

应用程序下templates目录中定义一个mytags.py(名称任意),文件内容如下

inclusion_tag中必须跟一个参数,这个参数必须是组件文件,自定义一个函数hehe(名称任意),return的返回值会返回给组件文件

mytags.py文件内容如下

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')
def hehe():
    return {'data':['唱','跳','rap','篮球']}

4.第3步中的data变量已经返回给了组件文件,因此xx.html文件中需要引入应用程序下的templatetags中定义的那个py文件(这里是mytag.py)

还需要引入这个py文件中自定义的函数的名称(这里是hehe)

mytags.py(自定义标签需要在应用程序下的templatetags目录中定义一个任意的py文件,然后在这个文件中写自定义标签内容)

xx.html文件内容如下

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %}
{% hehe %}


#参数说明
{% load mytags %}    //引入应用程序下的templatetags中定义的那个py文件(这里是mytags.py)

{% hehe %}    //引入这个py文件(mytags.py)中自定义的函数的名称(这里是hehe)

最终的渲染效果就由应用程序下的templatetags中定义的那个py文件(这里是mytags.py)中定义的函数中自定义的返回值决定

这里定义的data是一个字典,data会返回给组件文件用于动态渲染

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')
def hehe():
    return {'data':['唱','跳','rap','篮球']}

关于动态返回内容的一个问题

写在mytags中是写死的,我们应该写成动态的,所以应该写在views中从数据库中获取数据达到动态返回的效果,因此修改mytags文件如下

mytags文件

from django import template
register = template.Library()
@register.inclusion_tag('zujian.html')

#这里的v1就是给xx.html文件中引入hehe函数能够传一个参数
def hehe(v1):
    return {'data':v1}

views文件

def xx(request):
    #这里的lst就相当于从数据库中动态获取的数据
    lst = ['唱1','跳1','rap1','篮球1']
    return render(request,'xx.html',{'lst':lst})

xx.html文件

<div class="nav">我是xx.html,一会我要引入组件中的样式,就是组件中的那个菜单栏,并且我不修改引入的样式,只是修改菜单栏为其他内容</div>
{#{% include 'zujian.html' %}#}
{% load mytags %}
{% hehe lst %}        //在这里引入views中定义的lst

最终真正的动态获取内容效果如下

iShot2020-10-16 14.40.31

4.7组件

组件类似于python中的模块,组件是把其他html页面引入过来,但是不能修改引入的文件的内容

组件文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
</div>
</body>
</html>

iShot2020-10-16 14.40.55

自定义文件

在自定义文件中,我们想引入组件文件中的列表样式,需要如下代码,这个就是在自定义文件中表示引入组件.html文件

#写法
{% include '组件.html' %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .c1{
            background-color: green;
        }
    </style>
</head>
<body>
{% include '组件.html' %}
<div class="c1">我是一个引入了组件文件的自定义文件</div>
</body>
</html>

iShot2020-10-16 14.41.21

4.8模版继承

我们在写多个静态页面的时候可能会有一些相同的样式,这样的话每写一个页面就需要复制相同的代码,这样就造成了代码大量重复,此时就用到了模版继承,我们可以把相同样式的页面的代码单独放在一个模版文件中,其余页面继承这个模版文件,然后在设置自定义内容即可,这样就不用重复写相同样式的代码了

模版文件 base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .nav{
            background-color: pink;
            height: 40px;
        }
        .left-menu{
            display: inline-block;
            width: 200px;
            background-color: mediumpurple;
        }
        .content{
            display: inline-block;
            height: 200px;
            width: 600px;
            background-color: burlywood;
            color:white;
        }
        ul{
            padding: 0;
            margin: 0;
        }

    </style>

      #这里表示预留css样式,子模版继承后可以修改模版的样式
    {% block css %}
    {% endblock %}
</head>
<body>

<div class="nav">
    <a href="">个人中心</a>
    <a href="">登录|注册</a>
</div>

<div class="left-menu">
    <ul>
        <li>
            <a href="/menu01/">菜单1</a>
        </li>
        <li>
            <a href="/menu02/">菜单2</a>
        </li>
        <li>
            <a href="">菜单3</a>
        </li>
    </ul>
</div>

<div class="content">
    {% block content %}
        base页面
        <a href="">xxx</a>
    {% endblock %}

</div>
</body>
    {% block js %}

    {% endblock %}
</html>

模版继承的写法

在模版html文件中需要用到block方法,例如上述示例中,我们想要菜单1和菜单2有自己的自定义界面而不继承模版文件,写法如下
<div class="content">
    {% block content %}
        base页面
        <a href="">xxx</a>
    {% endblock %}
</div>


<div class="content">这个标签就是菜单1和菜单2中需要单独设置样式的标签,为了不继承模版文件,需要在这个标签写如下内容
block中包含的a标签就是菜单1和菜单2的html文件中需要重写的

{% block content %}
        base页面
        <a href="">xxx</a>
{% endblock %} 
这段代码的意思是,模版文件中的base页面不希望被继承,这里就单独把这个页面预留出来,接下来在菜单1和菜单2的html文件中在单独写这块的样式,写法如下

//这里表示继承模版文件base.html  
{% extends 'base.html' %} 

因为不需要继承模版文件中的 base页面  处的内容,而模版文件中也把这一块内容已经预留出来了,并且定义了预留名称为 content,在菜单1和菜单2的html文件中之需要引入这个模版预留名称,这样就可以自定义自己的样式了,写法如下

{% block content %}
    菜单1的内容
{% endblock %}

iShot2020-10-16 14.41.49

base.html文件如上,现在我们设置菜单1、菜单2的自定义内容,需要做以下操作

urls文件

from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #这个就是模版页面
    url(r'^base/', views.base),

    #下边两个是菜单1和菜单2返回的页面
    url(r'^menu01/', views.menu01),
    url(r'^menu02/', views.menu02),
]

views文件

def base(request):
    return render(request,'base.html')

def menu01(request):
    return render(request,'menu01.html')

def menu02(request):
    return render(request,'menu02.html')

menu01.html

{% extends 'base.html' %}
    <style>
        .content{
            display: inline-block;
            height: 200px;
            width: 600px;
            background-color: green;
            color:white;
        }
    </style>
{% endblock %}

{% block content %}
    菜单1的内容
{% endblock %}

menu02.html

{% extends 'base.html' %}

{% block content %}
    菜单2的内容
{% endblock %}

访问base页面,点击菜单1,返回页面如下,因为在menu01.html文件中,我门自己指定了样式,因此背景颜色就和模版的不同了

iShot2020-10-16 14.42.18

访问base页面,点击菜单2,返回页面如下

iShot2020-10-16 14.42.46

block.super()

这个方法就是继承模板预留块的内容的同时在自定义内容

{% block content %}
    {{ block.super }} #将模版中的content这个名称的块中的内容拿过来
    菜单1的内容
{% endblock %}

4.9url别名和反向解析

url别名的作用是当修改了url的访问路径,视图逻辑中返回的url路径也需要改动,其他相关联的地方也可能需要改动,这个时候我们在url中定义一个别名,如果后续更改了url的访问路径,其他地方只需要用到url别名的反向解析就能自动找到别名对应的url路径,这样的话只需要修改url路径而不更改其余地方

写法:
  url(r'^login/v2/', views.login,name='login'),

视图中反向解析:
    from django.urls import reverse

    def login(request):
        print(reverse('login'))  #/login/v2/
        if request.method == 'GET':
        return render(request,'login.html')
    else:
        uname = request.POST.get('uname')
        pwd = request.POST.get('pwd')
        if uname == 'admin' and pwd == 'admin':

            return HttpResponse('ok')
        else:
            return redirect(reverse('login'))  #使用反向解析



html模板渲染时反向解析的语法{% url 别名 %}
    <form action="{% url 'login' %}" method="post">
        {% csrf_token %}
        用户名:<input type="text" name="uname">
        密码:<input type="text" name="pwd">
        <input type="submit">
    </form>

⚠️⚠️⚠️进行html模板渲染时反向解析时,如果定义了命名空间,则在html中需要如下写法

html模板渲染时反向解析的语法{% url 命名空间:别名 %}

4.10include路由分发和url命名空间

4.10.1include路由分发

include路由分发就是将不同的url放在不同的应用程序下的urls文件中,先匹配一个应用程序的路径,然后在分别去这两个应用程序对应的urls文件中找下一级目录

例如,现在有app01和app02两个应用程序,现在设置的访问路径如下

/app01/index

/app02/index

访问到app01就去app01路径下找index


接下来做一下演示

第一步、在项目目录下同名的目录下的urls.py中写入以下内容

代码的意思是访问app01就去找app01.urls文件,访问app02就去找app02.urls文件,namespace是命名空间,为了防止路由分发中出现同名的url别名引发的错误

#需要导入include
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    #注意,初始的admin需要注释
    #url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^app01/', include('app01.urls',namespace='app01')),
    url(r'^app02/', include('app02.urls',namespace='app02')),
]


#匹配说明
/app01/index
先匹配app01这个路径,然后到app01url中写的include包含的urls文件中在去找index路径

第二步、在各个app应用目录下面创建urls.py文件,在urls.py文件中写自己应用的各个路径

app01

from django.conf.urls import url, include
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^index/', views.index, name='index'),
]

app02

from django.conf.urls import url, include
from django.contrib import admin
from app02 import views

urlpatterns = [
    url(r'^index/', views.index,name='index'),
]

第三步、编写views文件

app01 views文件

from django.shortcuts import render,HttpResponse

# Create your views here.

def index(request):
    return HttpResponse('app01-index')

app02 views文件

from django.shortcuts import render,HttpResponse

# Create your views here.

def index(request):
    return HttpResponse('app02-index')

浏览器访问结果

访问127.0.0.1/app01/index

iShot2020-10-16 14.43.24

访问127.0.0.1/app02/index

iShot2020-10-16 14.43.45

4.10.2url命名空间

注意:url命名空间是在进行路由分发的时候写的,而url别名是在urls文件中指定路径的时候写的别名

url命名空间是为了防止url有相同别名而导致的问题

写法:
  url(r'^app01/', include('app01.urls',namespace='app01')), 


将每个应用自己的url路径划分一个空间,将来通过别名反向解析时,通过空间名称可以找到对应应用下面的路径
使用:
    views.py文件中写法
        from django.urls import reverse
        def index(request):
            print('app01反向解析:', reverse('app01:index'))
            #app02反向解析: /app02/index/
            return HttpResponse('app01-index')

#reverse('app01:index')
app01就是命名空间
index就是app01下的index路径

    html中写法:
        {% url 'app01:login' %}
泡泡吐肥皂o © gitbook.pptfz.top 2021 all right reserved,powered by Gitbook文件修订时间: 秃笔南波湾!!!

results matching ""

    No results matching ""