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/

相關文章
相關標籤/搜索