Django框架04 /模板相关

目录

Django框架04 /模板相关

昨日内容回顾

  • 视图相关

  • request对象

request.path  
request.path_info
request.get_full_path()
request.META 
request.GET
request.POST
request.body
request.method
  • response对象

HttpResponse
render
redirect
  • FBV(function based view) 和CBV(class based view)

from django.views import View

class LoginView(View):

    def dispatch()
        ret = super().dispatch()
        return ret
    def get(self,request):
        return ...
    def post(self,request):
        return ...

url(r'^index/',views.LoginView.as_view())
  • 装饰器

from django.utils.decorators import method_decorator

@method_decorator(装饰器名称,name='get')
class LoginView(View):
    @method_decorator(装饰器名称)
    def dispatch()
        ret = super().dispatch()
        return ret
    @method_decorator(装饰器名称)
    def get(self,request):
        return ...
    def post(self,request):
        return ...
  • 模板渲染

{{ 变量 }}  {% 逻辑 %}
  • 万能的点

{{ name }}
{{ l1.1 }}
{{ l1.k1 }}
{{ l1.keys }}
{{ l1.values }}
{{ l1.items }}
{{ l1.p }}
  • 过滤器

内置过滤器  |
{{ name|length }}
{{ name|cut:'xx' }}
default
filesizeformat
truncatchars
truncatwords
slice:'0:3'
join:'+'
date:'Y-m-d H:i:s'
safe  识别成标签
  • 标签

{% for i in data %}
    xx
    {{ forloop.counter }}
{% empty %}
    xx
{% endfor %}

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

{% elif %}

{% else %}

{% endif %}
{% with a=xx.xx.xx %}
{% with xx.xx.xx as a %}
    {{ a }}
{% endwith %}

今日内容

1. 语法

关于模板渲染需要记两种特殊符号(语法):
  {{  }}和{% %}
  变量相关的用{{}},逻辑相关的用{%%}。

2. 变量 --- 万能的点

在Django的模板语言中按此语法使用:{{ 变量名 }}。
1.当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号。
2.深度查询据点符(.)在模板语言中有特殊的含义。当模版系统遇到点("."),它将以这样的顺序查询:
    字典查询(Dictionary lookup)
    属性或方法查询(Attribute or method lookup)
    数字索引查询(Numeric index lookup)
注意事项:
    如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
    如果使用的变量不存在, 模版系统将插入 string_if_invalid 选项的值, 它被默认设置为'' (空字符串) 。

示例

def index(request):
    import datetime
    s = "hello"
    l = [111, 222, 333]  # 列表
    dic = {"name": "yuan", "age": 18}  # 字典
    date = datetime.date(1993, 5, 2)  # 日期对象

    class Person(object):
        def __init__(self, name):
            self.name = name
        def dream(self):
            return 'dreamer'
    person_yuan = Person("chao")  # 自定义类对象
    person_egon = Person("yantao")
    person_alex = Person("jinxin")

    person_list = [person_yuan, person_egon, person_alex]

    return render(request, "index.html", {"l": l, "dic": dic, "date": date, "person_list": person_list})
    # return render(request,'index.html',locals())
    #locals()获取函数内容所有的变量,然后通过render方法给了index.html文件进行模板渲染,如果你图省事,你可以用它,但是很多多余的变量也被传进去了,效率低

模板中支持的写法:
<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
        {{ dic.keys }}
        {{ dic.values }}
        {{ dic.items }}
<h4>日期:{{ date.year }}</h4>

<!--取列表的第1个对象的name属性的值-->
<h4>类对象列表:{{ person_list.0.name }}</h4>
<!--取列表的第1个对象的dream方法的返回值,如果没有返回值,拿到的是none-->
<h4>类对象列表:{{ person_list.0.dream }}</h4>
注意:
    调用对象里面的方法的时候,不需要写括号来执行,并且只能执行不需要传参数的方法,如果你的这个方法需要传参数,那么模板语言不支持,不能帮你渲染

3 .过滤器

在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
1.过滤器的语法: {{ value|filter_name:参数 }}
2.使用管道符"|"来应用过滤器。
  例如:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。

注意事项:
    1.过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
    2.过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
    3.过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
    4.'|'左右没有空格没有空格没有空格

常用过滤器

Django的模板语言中提供了大约六十个内置过滤器

1.default
    如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。
    {{ value|default:"nothing"}}
    如果value没有传值或者值为空的话就显示nothing
2.length
    返回值的长度,作用于字符串和列表。
    {{ value|length }}
    返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
3.filesizeformat
    将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
    {{ value|filesizeformat }}
    如果 value 是 123456789,输出将会是 117.7 MB。
4.slice
    切片,如果 value="hello world",还有其他可切片的数据类型
    {{value|slice:"2:-1"}}
5.date
    格式化,如果 value=datetime.datetime.now()
    {{ value|date:"Y-m-d H:i:s"}}
   关于时间日期的可用的参数(除了Y,m,d等等)还有很多
6.safe
    Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样你是不是可以搞一些坏事儿了,写个弹窗的死循环,那浏览器还能用吗,是不是会一直弹窗啊,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
    我们去network那个地方看看,浏览器看到的都是渲染之后的结果,通过network的response的那个部分可以看到,这个a标签全部是特殊符号包裹起来的,并不是一个标签,这都是django搞得事情。
比如:
    value = "<a href='#'>点我</a>"和value="<script>alert('123')</script>"
    {{ value|safe}}
    很多网站,都会对你提交的内容进行过滤,一些敏感词汇、特殊字符、标签、黄赌毒词汇等等,你一提交内容,人家就会检测你提交的内容,如果包含这些词汇,就不让你提交,其实这也是解决xss攻击的根本途径,例如博客园:
7.truncatechars
    如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
    参数:截断的字符数
    {{ value|truncatechars:9}} 
    #注意:最后那三个省略号也是9个字符里面的,也就是这个9截断出来的是6个字符+3个省略号,有人会说,怎么展开啊,配合前端的点击事件就行啦
8.truncatewords
    在一定数量的字后截断字符串,是截多少个单词。(是通过空格区分不同的字符串)
    例如:‘hello girl hi baby yue ma’,
    {{ value|truncatewords:3}}  
    #上面例子得到的结果是 'hello girl h1...'
9.cut
    移除value中所有的与给出的变量相同的字符串
    {{ value|cut:' ' }}
    如果value为'i love you',那么将输出'iloveyou'.
10.join
    使用字符串连接列表,就像Python的str.join(list)(有空格的话,也要将空格包含在引号的里边)
    {{ list|join:', ' }}
11.timesince(了解)
    将日期格式设为自该日期起的时间(例如,“4天,6小时”)。
    采用一个可选参数,它是一个包含用作比较点的日期的变量(不带参数,比较点为现在)。 例如,如果blog_date是表示2006年6月1日午夜的日期实例,并且comment_date是2006年6月1日08:00的日期实例,则以下将返回“8小时”:
    {{ blog_date|timesince:comment_date }}
    分钟是所使用的最小单位,对于相对于比较点的未来的任何日期,将返回“0分钟”。
12.timeuntil(了解)
    似于timesince,除了它测量从现在开始直到给定日期或日期时间的时间。 例如,如果今天是2006年6月1日,而conference_date是保留2006年6月29日的日期实例,则{{ conference_date | timeuntil }}将返回“4周”。
使用可选参数,它是一个包含用作比较点的日期(而不是现在)的变量。 如果from_date包含2006年6月22日,则以下内容将返回“1周”:
    {{ conference_date|timeuntil:from_date }}

4. 标签Tags

标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。

4.1 for标签

1.遍历每一个元素:

 写个for,然后 tab键自动生成for循环的结构,循环很基础,就这么简单的用,没有什么break之类的,复杂一些的功能,要通过js   
{% for person in person_list %}
    <p>{{ person.name }}</p>  <!--凡是变量都要用两个大括号括起来-->
{% endfor %}
可以利用{% for obj in list reversed %}反向完成循环。

2.遍历一个字典:

{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

3.for ... empty

for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}
forloop

4.forloop

{% for i in data %}
    xx
    {{ forloop.counter }}
{% empty %}
    xx
{% endfor %}

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

4.2 if标签

{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。

1. if else

{% if user_list|length > 5 %}  <!--结合过滤器来使用-->
  七座豪华SUV
{% else %}
    黄包车
{% endif %}

2.if elif else

{% if num > 100 or num < 0 %}
    <p>无效</p>  <!--不满足条件,不会生成这个标签-->
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}  <!--也是在if标签结构里面的-->
    <p>凑活吧</p>
{% endif %}

4.3 with

使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的

例如:
    注意等号左右不要加空格。
    {% with total=business.employees.count %}
        {{ total }} <!--只能在with语句体内用-->
    {% endwith %}
或
    {% with business.employees.count as total %}
        {{ total }}
    {% endwith %}

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

1. 创建一个xx.html页面(作为母版,其他页面来继承它使用)
2. 在母版中定义block块(可以定义多个,整个页面任意位置)
    {% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
    {% endblock %}
3 其他页面继承写法
    {% extends 'base.html' %}  必须放在页面开头
4 页面中写和母版中名字相同的block块,从而来显示自定义的内容
    {% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
        {{ block.super }}  #这是显示继承的母版中的content这个块中的内容
        这是xx1
    {% endblock %}

注意:
   1.三个钩子/css钩子/body钩子/js钩子
   2.extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。
   3.如果使用 {% extends %} 标签,它必须是模版中的第一个标签。否则模版继承都将无法工作,模板渲染的时候django都不知道你在干啥
   4.为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:
        {% block content %}
        ...
        {% endblock content %}  
   在大型模版中,这个方法帮你清楚的看到哪一个{% block %} 标签被关闭了。

   5.不能在一个模版中定义多个相同名字的 block 标签。

base.html --- 模板/母板


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>base</title>
    <style>
        body{
            margin:0;
        }

        h1{
            margin:0;
            background-color:tomato;
            height: 50px;
            text-align:center;
        }
        .d1{
            margin-top:0;
            background-color:darkcyan;
            height:120px;
            width:20%;
            float:left;
        }
        .d2{
            margin-top:0;
            background-color:yellow;
            height:120px;
            width:80%;
            float:right;
            text-align:center;
            line-height:120px;
        }
    </style>
</head>
<body>
<div>
<h1>头条</h1>
</div>
<div class="d">
<div class="d1">
<ul>
    <a href="/menu1/"><li>菜单1</li></a>
    <a href="/menu2/"><li>菜单2</li></a>
    <a href="/menu3/"><li>菜单3</li></a>

</ul>
</div>
<div class="d2">
    {% block content %}
        模板
    {% endblock %}
</div>
</div>
</body>

</html>

home.html --- 主页

{#继承#}
{% extends 'base.html'%}

{% block content %}#}
主页
{% endblock %}

menu.html --- 菜单页

{% extends 'base.html'%}

{% block content %}
菜单一
{% endblock %}

既用到母板内容,又要新增内容

{% extends 'base.html'%}

{% block content %}
{{ block.super }}
菜单二
{% endblock %}

6. 组件

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

组件与插件的区别

1.组件是提供某一完整功能的模块,如:编辑器组件,QQ空间提供的关注组件 等。
2.而插件更倾向封闭某一功能方法的函数。
3.这两者的区别在 Javascript 里区别很小,组件这个名词用得不多,一般统称插件。

template.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template</title>
    <style>
        div{
            background-color:tomato;
            height:40px;
        }
    </style>
</head>
<body>
<div>
    <span>首页</span>
    <span>手机</span>
    <span>家居生活</span>
    <span>户外</span>
    <span>户内</span>
</div>
</body>
</html>

home.html

{% include 'template.html' %}

7. 自定义标签和过滤器

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

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

    定义过滤器
        @register.filter   参数至多两个
        def xx(v1,v2):
            return xxx
    使用:
        {% load xx %}
        {{ name|xx:'oo' }}

    # 自定义标签 没有参数个数限制
    @register.simple_tag
    def huxtag(n1,n2):  #哈哈xx  '嘿嘿'
        '''
        :param n1:  变量的值 管道前面的
        :param n2:  传的参数 管道后面的,如果不需要传参,就不要添加这个参数
        :return:
        '''
        return n1+n2

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

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

自定义过滤器、自定义标签

filters.py

from django import template
register = template.Library()  #register的名字是固定的,不可改变

# 自定义过滤器
@register.filter     
def filt(n1):
    return n1+'heihei'

# 自定义标签
@register.simple_tag
def tags(n1,n2):
    return n1+n2

test.html

{#自定义过滤器#}
{% load filters %}
{{ name|filt }}

{#自定义标签#}
{% load filters %}
{% tags name '888' %}

自定义经过加工的标签

view.py

def home(request):
    return render(request,'home.html',{'name':['aa','bb','cc','dd']})

home.html

{#自定义经过加工的标签#}
{% load filters %}
{% res name %}

filters.py

#自定义经过加工的标签
from django import template
register = template.Library()

@register.inclusion_tag('result.html')  
#将result.html里面的内容用下面函数的返回值渲染,然后作为一个组件一样,加载到使用这个函数的html文件里面
def res(n1):
    return {'l1':n1}

result.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>result</title>
</head>
<body>
<ul>
    {% for i in l1 %}
    <li>{{ i }}+{{ i }}</li>
    {% endfor %}
</ul>
</body>

</html>

8. 静态文件配置

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

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

3 引入<link rel="stylesheet" href="/static/css/index.css">

home.html


<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>static_files</title>
    <link rel="stylesheet" href="/static/css/one.css">
</head>
<body>
<div>
    <span>头条</span>
</div>
</body>
</html>

static_files > css > one.css

div{
    background-color:tomato;
    height:50px;
    text-align:center;
    line-height:50px;
    font-weight:bold;
}

settings.py

STATIC_URL = '/static/'

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

9. url别名和反向解析

写法
    url(r'^index2/', views.index,name='index'),
反向解析
    后端: from django.urls import reverse
         reverse('别名')  例如:reverse('index') -- /index2/
    html: {% url '别名' %} -- 例如:{% url 'index' %} -- /index2/

10. url命名空间

路由分发 include

1 在每个app下创建urls.py文件,写上自己app的路径
2 在项目目录下的urls.py文件中做一下路径分发,看下面内容
    from django.conf.urls import url,include
    from django.contrib import admin

    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^app01/', include('app01.urls')),#app01/home/
        url(r'^app02/', include('app02.urls')),
    ]

命名空间namespace

from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^app01/',include('app01.urls',namespace='app01')),#app01/home/
    url(r'^app02/', include('app02.urls',namespace='app02')),   
]

使用:
    后端:reverse('命名空间名称:别名') -- reverse('app01:home') 
    hmtl:{% url '命名空间名称:别名' %}  -- {% url 'app01:home' %}

item > urls

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

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^app01/', include('app01.urls',namespace='app01')),
    url(r'^app02/', include('app02.urls',namespace='app02')),
]

app01 > urls

from django.conf.urls import url
from app01 import views

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

app02 > urls

from django.conf.urls import url
from app02 import views

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

app01 > views

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse

def home(request):
    print('app01>>>',reverse('app01:home'))
    return HttpResponse('app01的home页面')

app02 > views

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse

def home(request):
    print('app02>>>',reverse('app02:home'))
    return HttpResponse('app02的home页面')

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。