python 全栈开发,Day69(Django的视图层,Django的模板层)

昨日内容回顾

相关命令:

1 建立项目 django-admin startproject 项目名称
2 建立应用 python manage.py startapp app名称
3 启动项目 python manage.py runserver IP PORT

步骤1,2都是下载过程,下载一些须要的代码。不写IP和端口,默认是8000端口php

请求流程:
      1 url:http://127.0.0.1:8000/index/
      2 path("index",views.index) # index(request)
      3 index视图函数响应HttpResponse(响应体字符串)

request是由path来进行传参的。html

 

django,由4部分组成。路由控制+MTV前端

复制代码
路由控制: 在全局文件夹下的urls.py
1 简单配置
 re_path("^articles/(\d{4})/(\d{2})/$",views.article_month) # article_month(reqeust,2000,12)
2 有名分组
  re_path("^articles/(?P<year>\d{4})/(?P<month>\d{2})/$",views.article_month) # article_month(reqeust,year=2000,month=12)
3 分发(解耦)     
 path('blog/', include('blog.urls')) 
4 反向解析
 path('index_new/', views.index,name="index"),
 re_path("^articles/(\d{4})/(\d{2})$", views.article_year,name="detail_article"), 
 状况1:在模板里:
     <form action="{% url '别名' 参数1 参数2 %}"></form>
     <a href="">
     
 状况2:在视图函数(python脚本)
      
      from django.urls import reverse
      _url=reverse('别名',args=(参数1,参数2))
复制代码

针对状况1:在模板里。python

这里全部的参数必须为字符串类型,除非你这里的url的规则由转换器定义了数据类型,不然必须一致。程序员

 

注意第4点。若是对应的是一个动态的url,好比"^articles/(\d{4})/(\d{2})$"ajax

那么视图函数和模板都须要传参。参数的个数,取决于正则表达式分组的个数。正则表达式

好比上面的正则有2个分组,那么必须传个参数才行。不然form提交以后,访问的url就是不正确的url。数据库

 

有名分组和有名分组的区别
1. 传参不一样。无名是位置参数,有名是关键字参数。
2. 视图函数的形参。无名分组,名字能够随便。有名分组,名字必须和分组名一致django

 

反向解析,就是为了解决URL常常修改的状况。在公司里面,这个url会被常常修改,好比业务下线了,或者业务重组了...后端

因此说,在模板的里面的路径,不能写死。最好用反向解析。

在视图函数里面,也要用反向解析。

在模板里面,会涉及url。好比form表单,那么action的属性不能写死。

 

请求发送方式有几下几种:
1. 地址栏
2. form表单
3. a标签发请求
4. ajax请求

 

对于静态资源,好比img的src,link的src。只要涉及路径的,都要发送请求。静态资源的url通常不会变更。

注意:在模板里面出现的大括号内容,由render来渲染的。由后端完成替换,而不是前端来完成的。

 

1、Django的视图层

视图函数

一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求而且返回Web响应。响应能够是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西均可以。不管视图自己包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此以外没有更多的要求了——能够说"没有什么神奇的地方"。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
View Code

让咱们逐行阅读上面的代码:

  • 首先,咱们从 django.shortcuts模块导入了HttpResponse类,以及Python的datetime库。

  • 接着,咱们定义了current_datetime函数。它就是视图函数。每一个视图函数都使用HttpRequest对象做为第一个参数,而且一般称之为request

    注意,视图函数的名称并不重要;不须要用一个统一的命名方式来命名,以便让Django识别它。咱们将其命名为current_datetime,是由于这个名称可以精确地反映出它的功能。

  • 这个视图会返回一个HttpResponse对象,其中包含生成的响应。每一个视图函数都负责返回一个HttpResponse对象。

视图层,熟练掌握两个对象便可:请求对象(request)和响应对象(HttpResponse)

HttpRequest对象

request属性

django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。 除了特殊说明的以外,其余均为只读的。

/*

1.HttpRequest.GET

  一个相似于字典的对象,包含 HTTP GET 的全部参数。详情请参考 QueryDict 对象。

2.HttpRequest.POST

  一个相似于字典的对象,若是请求中包含表单数据,则将这些数据封装成 QueryDict 对象。

  POST 请求能够带有空的 POST 字典 —— 若是经过 HTTP POST 方法发送一个表单,可是表单中没有任何的数据,QueryDict 对象依然会被建立。
   所以,不该该使用 if request.POST  来检查使用的是不是POST 方法;应该使用 if request.method == "POST"
  另外:若是使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
   
   注意:键值对的值是多个的时候,好比checkbox类型的input标签,select标签,须要用:
        request.POST.getlist("hobby")

3.HttpRequest.body

  一个字符串,表明请求报文的主体。在处理非 HTTP 形式的报文时很是有用,例如:二进制图片、XML,Json等。
  可是,若是要处理表单数据的时候,推荐仍是使用 HttpRequest.POST 。


4.HttpRequest.path

  一个字符串,表示请求的路径组件(不含域名)。
  例如:"/music/bands/the_beatles/"

5.HttpRequest.method

  一个字符串,表示请求使用的HTTP 方法。必须使用大写。
  例如:"GET""POST"


6.HttpRequest.encoding

  一个字符串,表示提交的数据的编码方式(若是为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
   这个属性是可写的,你能够修改它来修改访问表单数据使用的编码。
   接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
   若是你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。


7.HttpRequest.META

   一个标准的Python 字典,包含全部的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:

    CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
    CONTENT_TYPE —— 请求的正文的MIME 类型。
    HTTP_ACCEPT —— 响应可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
    HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
    HTTP_HOST —— 客服端发送的HTTP Host 头部。
    HTTP_REFERER —— Referring 页面。
    HTTP_USER_AGENT —— 客户端的user-agent 字符串。
    QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
    REMOTE_ADDR —— 客户端的IP 地址。
    REMOTE_HOST —— 客户端的主机名。
    REMOTE_USER —— 服务器认证后的用户。
    REQUEST_METHOD —— 一个字符串,例如"GET""POST"。
    SERVER_NAME —— 服务器的主机名。
    SERVER_PORT —— 服务器的端口(是一个字符串)。
   从上面能够看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 以外,请求中的任何 HTTP 首部转换为 META 的键时,
    都会将全部字母大写并将链接符替换为下划线最后加上 HTTP_  前缀。
    因此,一个叫作 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。

8.HttpRequest.FILES

  一个相似于字典的对象,包含全部的上传文件信息。
   FILES 中的每一个键为<input type="file" name="" /> 中的name,值则为对应的数据。
  注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的状况下才会
   包含数据。不然,FILES 将为一个空的相似于字典的对象。


9.HttpRequest.COOKIES

  一个标准的Python 字典,包含全部的cookie。键和值都为字符串。



10.HttpRequest.session

   一个既可读又可写的相似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
    完整的细节参见会话的文档。


11.HttpRequest.user(用户认证组件下使用)

  一个 AUTH_USER_MODEL 类型的对象,表示当前登陆的用户。

  若是用户当前没有登陆,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你能够经过 is_authenticated() 区分它们。

    例如:

    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.


       user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。

     -------------------------------------------------------------------------------------

    匿名用户
    class models.AnonymousUser

    django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具备下面几个不一样点:

    id 永远为None。
    username 永远为空字符串。
    get_username() 永远返回空字符串。
    is_staff 和 is_superuser 永远为False。
    is_active 永远为 False。
    groups 和 user_permissions 永远为空。
    is_anonymous() 返回True 而不是False。
    is_authenticated() 返回False 而不是True。
    set_password()、check_password()、save() 和delete() 引起 NotImplementedError。
    New in Django 1.8:
    新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。

*/
View Code

request经常使用方法

/*

1.HttpRequest.get_full_path()

  返回 path,若是能够将加上查询字符串。

  例如:"/music/bands/the_beatles/?print=true"


2.HttpRequest.is_ajax()

  若是请求是经过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是不是字符串'XMLHttpRequest'。

  大部分现代的 JavaScript 库都会发送这个头部。若是你编写本身的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 能够工做。

  若是一个响应须要根据请求是不是经过AJAX 发起的,而且你正在使用某种形式的缓存例如Django 的 cache middleware,
   你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应可以正确地缓存。

*/
View Code

举例:

修改urls.py,增长index

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
]
View Code

修改views.py,增长index视图函数

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
    '''
    request: 全部请求信息的封装对象
    HttpResponse: 最终return的必定是HttpResponse的实例对象
    :param request:
    :return:
    '''
    print(request.method)  # 请求方式
    print(request.path)    # 请求路径
    print(request.GET)     # GET请求数据,返回QueryDict对象
    print(request.POST)    # POST请求的数据,返回QueryDict对象
    print(request.get_full_path())  # 包含GET请求参数的请求路径
    print(request.is_ajax())  #判断是否为ajax请求,返回布尔值

    return HttpResponse("OK")
View Code

访问index页面,带一个参数

http://127.0.0.1:8000/index/?a=3

效果以下:

查看Pycharm控制台输出信息

复制代码
GET
/index/
<QueryDict: {'a': ['3']}>
<QueryDict: {}>
/index/?a=3
False
复制代码

解释:

请求方式为GET

请求路径为/index

GET请求数据是一个QueryDict类型,它是字典格式

POST请求数据为空,它是一个空字典

完整url为: /index/?a=3

它不是ajax请求,因此返回false

 

HttpResponse对象

响应对象主要有三种形式:

  • HttpResponse()
  • render()
  • redirect()

HttpResponse()括号内直接跟一个具体的字符串做为响应体,比较直接很简单,因此这里主要介绍后面两种形式。

render()

render(request, template_name,[context])
 
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

参数:

  • request: 用于生成响应的请求对象。
  • template_name:要使用的模板的完整名称,可选的参数
  • context:添加到模板上下文的一个字典。默认是一个空字典。若是字典中的某个值是可调用的,视图将在渲染模板以前调用它。

render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面做为响应体。

 举例:

修改views.py,使用render渲染index.html。传一个参数name

def index(request):
    '''
    request: 全部请求信息的封装对象
    HttpResponse: 最终return的必定是HttpResponse的实例对象
    :param request:
    :return:
    '''
    print(request.method)  # 请求方式
    print(request.path)    # 请求路径
    print(request.GET)     # GET请求数据,返回QueryDict对象
    print(request.POST)    # POST请求的数据,返回QueryDict对象
    print(request.get_full_path())  # 包含GET请求参数的请求路径
    print(request.is_ajax())  #判断是否为ajax请求,返回布尔值

    # return HttpResponse("OK")
    name = 'xiao'
    return render(request,"index.html",{"name":name})
View Code

在templates目录下,建立index.html文件,内容以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>INDEX</h3>
<p>Hi, {{ name }}</p>
</body>
</html>
View Code

从新访问index页面

 

redirect()

传递要重定向的一个硬编码的URL

def my_view(request):
    ...
    return redirect('/some/url/')
View Code

也能够是一个完整的URL:

def my_view(request):
    ...
    return redirect('http://example.com/') 
View Code

redirect使用了2次请求

 

 举例:

修改urls.py,新增login

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('login/', views.login),
]
View Code

在templates目录下,建立login.html文件,内容以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <lable>用户名</lable><input type="text" name="user">
    <lable></lable><input type="password" name="pwd">
    <input type="submit">
</form>
</body>
</html>
View Code

修改views.py

先导入redirect类

from django.shortcuts import render,HttpResponse,redirect

增长视图函数login,else能够不写。若是直接用HttpResponse返回一个登录成功。

它并不会跳转,须要用户本身手动跳转,用户体验很差!这个时候,须要用到redirect重定向。

def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get('pwd')
        if user == 'xiao' and pwd == '123':
            #return HttpResponse("登陆成功") # 它并不会跳转,须要用户本身手动跳转,体验很差!
            return redirect('/index/')  # 重定向到index

    return render(request,'login.html')
View Code

修改mysite下面的settings.py,关闭csrf

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
View Code

访问页面

http://127.0.0.1:8000/login/

点击提交以后,会跳转到index页面

 

 修改views.py里面的login视图函数。修改return部分

return HttpResponse("登陆成功") # 它并不会跳转,须要用户本身手动跳转,体验很差!
# return redirect('/index/')  # 重定向到index

访问login页面,这个时候,打开浏览器控制台-->network。点击提交按钮

查看控制台,它只有一次请求。查看浏览器地址,它的路径仍是login

 

修改views.py里面的login视图函数。修改return部分

#return HttpResponse("登陆成功") # 它并不会跳转,须要用户本身手动跳转,体验很差!
return redirect('/index/')  # 重定向到index

从新访问login页面,这个时候,打开浏览器控制台-->network。点击提交按钮

页面跳转至首页

查看控制台,注意:它用了2次链接。一次是302,一次是200

 查看login的响应体,发现它是空的

index是有响应体的

关于重定向,简单来讲:

经过修改http协议的header部分,对浏览器下达重定向指令的,让浏览器对location中指定的url提出请求,使浏览器显示重定向网页的内容。

 

关于301与302

1)301和302的区别。

  301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址能够从响应的Location首部中获取
  (用户看到的效果就是他输入的地址A瞬间变成了另外一个地址B)——这是它们的共同点。

  他们的不一样在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向以后的网址;

  302表示旧地址A的资源还在(仍然能够访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301


2)重定向缘由:
(1)网站调整(如改变网页目录结构);
(2)网页被移到一个新地址;
(3)网页扩展名改变(如应用须要把.php改为.Html或.shtml)。
        这种状况下,若是不作重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户获得一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的
    网站,也须要经过重定向让访问这些域名的用户自动跳转到主站点等。
View Code

 

思考一个问题

修改views.py中login里面的return部分

return redirect('/index/') 
return render(request,"index.html")

这2个,有什么不一样?
render一样也能够渲染index页面,那么为何须要redirect?

 

咱们来验证一下:

先注释掉redirect,打开render

#return redirect('/index/') 
return render(request,"index.html")

从新访问login页面 http://127.0.0.1:8000/login/

这个时候,打开浏览器控制台-->network。点击提交按钮!

页面输出index

 查看控制台,它只有一次请求。

区别就显现了!

那么问题来了,为何页面hi后面,没有显示xiao,是空的。而redirect确是正确的呢?

先来分析一下过程。

render

点击form表单提交按钮时,浏览器发送请求。服务器接收到请求后,判断用户名和密码。执行return render(request,"index.html")

注意:它是没有传参的。render逐行读取index.html文件,读到{{ name }} 时,发现没有传参,替换为空。因此最终页面,name并无展现出来,它是空的。

redirect

点击form表单提交按钮时,浏览器发送请求。服务器接收到请求后,判断用户名和密码。执行return redirect('/index/'),服务器经过修改http协议的header部分,对浏览器下达重定向指令。浏览器对location中指定的url提出请求,服务器接收到index的url,进入URL控制层,调用index视图函数,执行return,将name参数传给模板,渲染页面,替换index.html中的变量,最终浏览器展现处理后的网页。

 

虽然在login视图函数里面,能够用render给index.html传参,可是不能这么作。由于不必传参,index视图函数已经有了。

 

APPEND_SLASH

用redirect能够解释APPEND_SLASH的用法!

举例:

浏览器直接输入地址: http://127.0.0.1:8000/index,它会自动将url修改成:http://127.0.0.1:8000/index/

那么这个动做是谁来作的呢?不少人会认为是浏览器作的,它有那么智能吗?实际上是django作的。不信?验证一下

打开浏览器控制台-->network

访问url:http://127.0.0.1:8000/index  直接回车。查看控制台

发现,它经历了2次请求。为何呢?

由于咱们的URL模式要求尾部有一个斜杠(/),那个申请URL将不匹配。 然而,默认地,任何不匹配或尾部没有斜杠(/)的申请URL,将被重定向至尾部包含斜杠的相同字眼的URL。 (这是受配置文件setting中APPEND_SLASH项控制的)

Django seetings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 做用就是自动在网址结尾加'/'。

修改seetings.py,最后一行添加:

APPEND_SLASH = False

浏览器是有缓存的,开一个隐身模式的窗口,访问url: http://127.0.0.1:8000/index

页面就会提示404

修改seetings.py,将最后一行删掉。由于默认的加斜杠,仍是蛮好的!

 

 重点:request和HttpResponse里面的render、redirect

 

2、Django的模板层

你可能已经注意到咱们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
View Code

尽管这种技术便于解释视图是如何工做的,但直接将HTML硬编码到你的视图里却并非一个好主意。 让咱们来看一下为何:

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改每每比底层 Python 代码的修改要频繁得多,所以若是能够在不进行 Python 代码修改的状况下变动设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不一样的工做,大多数专业的网站开发环境都将他们分配给不一样的人员(甚至不一样部门)来完成。 设计者和HTML/CSS的编码人员不该该被要求去编辑Python的代码来完成他们的工做。

  • 程序员编写 Python代码和设计人员制做模板两项工做同时进行的效率是最高的,远胜于让一我的等待另外一我的完成对某个既包含 Python又包含 HTML 的文件的编辑工做。

基于这些缘由,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 咱们可使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。

django的模板:HTML代码+模板语法

写法:

def current_time(req):
    # ================================原始的视图函数
    # import datetime
    # now=datetime.datetime.now()
    # html="<html><body>如今时刻:<h1>%s.</h1></body></html>" %now


    # ================================django模板修改的视图函数
    # from django.template import Template,Context
    # now=datetime.datetime.now()
    # t=Template('<html><body>如今时刻是:<h1>{{current_date}}</h1></body></html>')
    # #t=get_template('current_datetime.html')
    # c=Context({'current_date':str(now)})
    # html=t.render(c)
    #
    # return HttpResponse(html)


    #另外一种写法(推荐)
    import datetime
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
View Code

 举例:

修改

修改urls.py,增长路径timer

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('login/', views.login),
    path('timer/', views.timer),
]
View Code

修改views.py,增长timer视图函数。

def timer(request):
    import time
    ctime = str(time.time())
    html = '<html><body>如今时刻是:<h1>%s</h1></body></html>'%ctime
    return HttpResponse(html)
View Code

访问url:http://127.0.0.1:8000/timer/

这样写效率低,容易出错

推荐写法:

在templates目录下建立timer.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
如今时刻是:<h1>{{ now }}</h1>
</body>
</html>
View Code

修改views.py,修改timer函数

def timer(request):
    import time
    ctime = str(time.time())
    return render(request,"timer.html",{'now':ctime})
View Code

再次访问页面,效果是同样的。

 

1. 模板语法之变量

在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法:  

{{var_name}}

views.py:

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
 
    person_yuan=Person("yuan")  # 自定义类对象
    person_egon=Person("egon")
    person_alex=Person("alex")
 
    person_list=[person_yuan,person_egon,person_alex]
 
 
    return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
View Code

template: 

<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>
<h4>类对象列表:{{ person_list.0.name }}</h4>
View Code

注意:句点符也能够用来引用对象的方法(无参数方法):

<h4>字典:{{ dic.name.upper }}</h4>

 

深度查询

举例1:字符串

修改index视图函数

def index(request):
    name = 'xiao'
    return render(request,"index.html",{"name":name})
View Code

修改index.html,修改body部分

<p>{{ name }}</p>

访问网页,输出:

 

举例2:列表

修改index视图函数

def index(request):
    li = [123, 456, 567]
    return render(request,"index.html",{"li":li})
View Code

修改index.html,修改body部分

<p>{{ li }}</p>
取第一个元素
<p>{{ li.0 }}</p>
取第二个元素
<p>{{ li.1 }}</p>
取第三个元素
<p>{{ li.2 }}</p>
View Code

访问网页,输出:

 

 

举例2:字典

修改index视图函数

def index(request):
    info = {'name':'xiao','age':'23'}
    return render(request,"index.html",{"info":info})
View Code

修改index.html,修改body部分

<p>{{ info }}</p>
取name
<p>{{ info.name }}</p>
取age
<p>{{ info.age }}</p>
View Code

访问网页,输出:

 

举例3:类

修改index视图函数

def index(request):
    class Annimal(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def call(self):
            return "汪汪汪"

    dog = Annimal("旺财", 3)
    cat = Annimal("小雪", 4)
    duck = Annimal("小黄", 5)

    animal_list = [dog, cat, duck]

    return render(request,"index.html",{"animal_list":animal_list})
View Code

修改index.html,修改body部分

<p>{{ animal_list }}</p>
取一个对象:
<p>{{ animal_list.0 }}</p>
取属性:
<p>{{ animal_list.0.name }}</p>
取方法:
<p>{{ animal_list.0.call }}</p>
View Code

访问网页,输出:

注意:取方法的时候,不要加括号。它不能接收参数!

call方法,必须用return。不然取方法时,结果输出None

总结:深度查询,就是不停的点点点就好了。

 

2. 模板之过滤器

语法:

{{obj|filter__name:param}}

add

给一个变量作加法运算

{{ value|add:number }}

举例:

修改index视图函数

def index(request):
    num = 50
    return render(request,"index.html",{"num":num})
View Code

修改index.html,修改body部分

<p>{{ num|add:100 }}</p>

访问网页,输出:

 

default

若是一个变量是false或者为空,使用给定的默认值。不然,使用变量的值。例如:

{{ value|default:"nothing" }}

举例:

修改index视图函数

def index(request):
    book_list = []
    return render(request,"index.html",{"book_list":book_list})
View Code

修改index.html,修改body部分

<p>{{ book_list|default:'没有任何书籍' }}</p>

访问网页,输出:

 

length

返回值的长度。它对字符串和列表都起做用。例如:

{{ value|length }}

若是 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。

举例:

修改index视图函数

def index(request):
    female_star = ['赵丽颖','宋茜','霍思燕','唐嫣']
    return render(request,"index.html",{"female_star":female_star})
View Code

修改index.html,修改body部分

<p>{{ female_star|length }}</p>

访问网页,输出:

 

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB''4.1 MB''102 bytes', 等等)。例如:

{{ value|filesizeformat }}

若是 value 是 123456789,输出将会是 117.7 MB。  

举例:

修改index视图函数

def index(request):
    file_size = 123456789
    return render(request,"index.html",{"file_size":file_size})
View Code

修改index.html,修改body部分

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

访问网页,输出:

 

date

若是 value=datetime.datetime.now()

{{ value|date:"Y-m-d" }}

举例:

修改index视图函数

def index(request):
    import datetime
    now = datetime.datetime.now()
    return render(request,"index.html",{"now":now})
View Code

修改index.html,修改body部分

<p>{{ now|date:'Y-m-d H:i:s' }}</p>

访问网页,输出:

 

slice

若是 value="hello world"

{{ value|slice:"2:-1" }}

举例:

修改index视图函数

def index(request):
    val = 'hello world'
    return render(request,"index.html",{"val":val})
View Code

修改index.html,修改body部分

<p>{{ val|slice:'1:-1' }}</p>

访问网页,输出:

注意:它和python切片方法是同样的,顾头不顾尾巴。

 

truncatechars

若是字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

参数:要截断的字符数

例如:

{{ value|truncatechars:9 }}

举例:

好比后台管理页面,展现文章内容部分,通常取前20个字符串,后面直接用...来代替。

修改index视图函数

def index(request):
    text = 'Django 教程 Python下有许多款不一样的 Web 框架。Django是重量级选手中最有表明性的一位。许多成功的网站和APP都基于Django。'
    return render(request,"index.html",{"text":text})
View Code

修改index.html,修改body部分

<p>{{ text|truncatechars:20 }}</p>

访问网页,输出:

 

safe

Django的模板中会对HTML标签和JS等语法标签进行自动转义,缘由显而易见,这样是为了安全。可是有的时候咱们可能不但愿这些HTML元素被转义,好比咱们作一个内容管理系统,后台添加的文章中是通过修饰的,这些修饰多是经过一个相似于FCKeditor编辑加注了HTML修饰符的文本,若是自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,若是是一个单独的变量咱们能够经过过滤器“|safe”的方式告诉Django这段代码是安全的没必要转义。好比:

value="<a href="">点击</a>"

html文件

{{ value|safe}}

举例:

修改index视图函数,注意:a标签要有内容才行!

def index(request):
    link = '<a href="http://www.py3study.com/">click</a>'
    return render(request,"index.html",{"link":link})
View Code

修改index.html,修改body部分

<p>{{ link }}</p>

访问网页,输出:

咦,为何页面不是a标签样式呢?明明传了一个a标签样式啊?

由于django的模板中会对HTML标签和JS等语法标签进行自动转义,这样作是为了安全!

若是包含js代码,那么就能够执行脚本,进行攻击了。

 

打开控制台-->network,从新刷新页面

查看index的Respone,发现被转义了

若是确认是安全的,不须要转义,加一个safe便可。

修改index.html,修改body部分

<p>{{ link|safe }}</p>

刷新网页,输出:

 

这里简单介绍一些经常使用的模板的过滤器,更多详见

完整Django 1.8.2 文档,请参考如下连接

https://yiyibooks.cn/xx/django_182/ref/templates/builtins.html

 

3 模板之标签 

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

for标签

遍历每个元素:

{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %}

能够利用{% for obj in list reversed %}反向完成循环。

举例:遍历列表

修改index视图函数

def index(request):
    li = [123, 456, 567]
    return render(request, "index.html", {"li": li})
View Code

修改index.html,修改body部分

<p>
    {% for item in li %}
    <span>{{ item }}</span>
    {% endfor %}
</p>
View Code

访问网页,输出:

 

遍历一个字典:

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

注:循环序号能够经过{{forloop}}显示

forloop.counter            The current iteration of the loop (1-indexed)
forloop.counter0           The current iteration of the loop (0-indexed)
forloop.revcounter         The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0        The number of iterations from the end of the loop (0-indexed)
forloop.first              True if this is the first time through the loop
forloop.last               True if this is the last time through the loop
View Code

中文解释:

forloop.counter         从1开始计数
forloop.counter0       从0开始基数
forloop.revcounter    倒序到1结束
forloop.revcounter0  倒序到0结束
forloop.first              是一个布尔值,若是该迭代是第一次执行,那么它被置为True
forloop.last               是一个布尔值,若是该迭代是最后一次执行,那么它被置为True
View Code

forloop只能在循环里面 使用

 

举例:

修改index视图函数

def index(request):
    female_star = {'name':'赵丽颖', 'age':'25', 'job':'movie', 'place':'Beijing'}
    return render(request, "index.html", {"female_star": female_star})
View Code

修改index.html,修改body部分

<p>
    {% for key,val in female_star.items %}
    <span>序号:{{ forloop.counter }} {{ key }}:{{ val }}</span><br/>
    {% endfor %}
</p>
View Code

访问网页,输出:

 

for ... empty

for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,能够有所操做。

复制代码
{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}
复制代码

举例:

修改index视图函数

def index(request):
    person_list = []
    return render(request, "index.html", {"person_list": person_list})
View Code

修改index.html,修改body部分

<div>
    {% for person in person_list %}
    <p>{{ person.name }}</p>

    {% empty %}
        <p>对不起,这里没有人</p>
    {% endfor %}
</div>
View Code

访问网页,输出:

由于列表为空,因此输出没有人。

修改index视图函数,增长数据

def index(request):
    person_list = [{'name':'赵丽颖'},{'name':'宋茜'},{'name':'霍思燕'}]
    return render(request, "index.html", {"person_list": person_list})
View Code

刷新网页,输出:

 

 

if 标签

{% if %}会对一个变量求值,若是它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

复制代码
{% if num > 100 or num < 0 %}
    <p>无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>凑活吧</p>
{% endif %}
复制代码

举例:

博客园右上角部分,未登陆时,显示登陆和注册。登陆以后,显示注销和修改密码。

修改index视图函数

def index(request):
    login_user = 'xiao'
    return render(request, "index.html", {"login_user": login_user})
View Code

修改index.html,修改body部分

<div>
    {% if login_user %}
    <p>{{ login_user.name }}</p>
    <a href="">注销</a>
    <a href="">修改密码</a>
    {% else %}
        <a href="">登录</a>
        <a href="">注册</a>
    {% endif %}
</div>
View Code

访问网页,输出:

 

with

使用一个简单地名字缓存一个复杂的变量,当你须要使用一个“昂贵的”方法(好比访问数据库)不少次的时候是很是有用的

例如:

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

举例:

修改index视图函数

def index(request):
    class Annimal(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def call(self):
            return "汪汪汪"

    dog = Annimal("旺财", 3)
    cat = Annimal("小雪", 4)
    duck = Annimal("小黄", 5)

    animal_list = [dog, cat, duck]
    return render(request, "index.html", {"animal_list": animal_list})
View Code

修改index.html,修改body部分

<div>
    {% with f_name=animal_list.1.name %}
    <p>{{ f_name }}</p>
    {% endwith %}
</div>
View Code

访问网页,输出:

 

csrf_token

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

编辑settings.py,查看MIDDLEWARE配置,确保CsrfViewMiddleware这一行内容没有被注释掉。默认是开启的

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
View Code

修改index.html,修改body部分。

action为空,表示提交至当前页面

<form action="" method="post">
    <lable>用户名:</lable>
    <input type="text" name="user">
    <input type="submit">
</form>
View Code

访问网页,输出:

输出内容,点击提交

页面提示被csrf拒绝了

增长csrf_token,就能够经过了。

修改index.html,修改body部分。

注意:csrf_token必须在form表单里面!!!

<form action="" method="post">
    {% csrf_token %}
    <lable>用户名:</lable>
    <input type="text" name="user">
    <input type="submit">
</form>
View Code

再次提交,就不会被拒绝了。

使用浏览器控制台,查看html代码

能够看到,它加了input框,是django帮你加的。

注意:它的属性值是hidden,表示隐藏。

它的name值是csrfmiddlewaretoken,那么点击提交时。它会提交给django服务器。

查看Headers,发送了post数据

django接收到这个数据时,就会认为它是安全的。

 

今日重点:

1 request的属性
2 render,redirect
3 深度查询    句点符号  .
4 过滤器  {{变量|filter_name:参数}}
   date
   filesizeformat
   safe
   default
5  for 标签
       {% for i in [] %}
       {% endfor%}
  
       {{forloop.last}}
       {{forloop.counter}}
       
   if 标签
       {% if 条件%}
        <p>1111</p>
       {% elif 条件%}
       <p>2222</p>
       {% else %}
       <p>3333</p>
       {% endif %}
View Code

 


参考资料:

Django 基础教程

转载声明:
做者:肖祥
出处: https://www.cnblogs.com/xiao987334176/

相关文章
相关标签/搜索