Django框架-Django視圖(views)系統
Django的視圖系統
定義:一個視圖函數(或類),簡稱為視圖,是一個簡單的python函數或類,它接受web請求並且返回web響應。
響應可以是一張網頁的html內容,一個重定向,一個404錯誤,一個xml文檔,或一張圖片。
無論視圖本身包含什麽邏輯,都要返回響應,代碼寫在那裏都無所謂,只要它在你當前項目目錄下面。為了將代碼放在某處,大家預定成俗將視圖放在項目project或應用程序app目錄中的名為views.py的文件中。
1、每個視圖函數,都使用HttpRequest對象作為第一個參數,並且通常稱之為request。
2、每個視圖函數,都會返回一個HttpResponse對象,其中包含生成的響應。
Django使用請求和響應對象來通過系統傳遞狀態。
當瀏覽器向服務端請求一個頁面是,Django創建一個HttpRequest對象,該對象包含關於請求的元數據,然後,Django加載相應的視圖,將這個HttpRequest對象作為第一個參數傳遞給視圖函數,每個視圖函數負責返回一個HttpResponse對象。
常見的render,redirect,HttpResponse對象返回的都是一個HttpResponse對象。
Django中視圖編碼分類
主要分為兩類:FBV(創建視圖函數)和CBV(創建視圖類)
FBV(function based view):就是將業務邏輯寫在一個函數中
-----views.py
1 from django.shortcuts import render,Httpresponse,redirect 2 from app_name import models 3 4 def add_class(request): 5 if request.method ==‘POST‘: 6 class_name = request.POST.get(‘class_name‘) 7 models.Classes.objects.create(name=class_name) 8return redirect(‘/class_list/‘) 9 return render(request,‘add_class.html‘)
----urls.py
1 from app_name from views
2 urlpatterns = [
3 url(r‘^addclass/$‘,views.add_class),]
CBV(class based view): 就是以類的方式寫
-----views.py
1 from django.views import View 2 from app_name import models 3 4 class Add_class(View): # 必須繼承類View 5 6 def get(self,request): 7 return render(request,‘add_class.html‘) 8 9 10 def post(self,request): 11 class_name = request.POST.get(‘class_name‘) 12 models.Classes.objects.create(name=class_name) 13 return tedirect(‘/class_list/‘)
使用CBV時,urls.py中也做對應的修改:
1 # urls.py中 2 url(r‘^add_class/$‘, views.AddClass.as_view()),
CBV的流程:
1、views.AddClass.as_view() ===》返回view函數對象
2、請求到來的時候執行view函數
2.1、實例化AddClass,賦值給self
self.reuest= request
2.2、執行self.dispatch方法(AddClass如果有,執行自己的,沒有的話執行View的)
2.2.1、判斷請求方法是否被允許
通過反射獲取到請求方法類型
允許:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
不允許:
拿到一個http_method_not_allowed方法
2.2.2、執行獲取到的方法類型對應類中定義的方法,get(request,)或post(request,)
2.2.3、得到httpResponse對象對象,返回給self.dispatch
2.2.4、得到HttpResponse對象,返回django處理
給視圖加裝飾器
1、FBV加裝飾器
操作:直接在函數上方加裝飾器 @wrapper_name
2、CBV加裝飾器
必須導入:from django.utils.decorators import method_decorator
操作:三種方案
2.1、直接在方法上加:
1 @method_decorator(wapper_name) 2 def get(self,request):pass
2.2、給自定義的dispatch方法加:
1 @method_decorator(wrapper_name) 2 def dispatch(self,request,*args,**kwargs)
2.3、給類加
1 # 直接在類上面加 2 @method_decorator(wapper_name, name=‘post‘) #給方法post加裝飾器 3 @method_decorator(wapper_name, name=‘get‘) 4 class AddClass(View) 5 6 註:其實也可以直接給View中的dispatch方法加裝飾器,這樣同樣可以實現給自己類下的所有方法加裝飾器(自己未定義dispatch方法時) 7 @method_decorator(wapper_name, name=‘dispatch‘) 8 class AddClass(View)
Requset對象和Respondse對象
request對象
當一個頁面被請求時,Django就會船艦一個包含本次請求原信息的HttpReques對象。
Django會將這個對象自動傳遞給響應的視圖函數,一般視圖函數預定俗稱的使用request參數承接這個對象。
請求相關的常用值
- path_info 返回用戶訪問的url,不包含域名,僅path不帶參數 /index/
- path 同上
- get_full_path() 返回完整路徑,不含域名 /midd/index/?wd=333&key=3333
- method 請求中使用的HTTP方法的字符串表示,全大寫表示
- GET 包含所有HTTP GET參數的類字典對象
- POST 包含所有HTTP POST參數的類字典對象
- body 請求體,byte類型的request.POST的數據就是從body裏面提取到的
- FILES 上傳文件,{} 註意form標簽加enctype="multipart/form-data"屬性
- HTTP_REFERER 跳轉到上次訪問的頁面,用戶在未登錄前要訪問的頁面,登錄後跳轉到該頁面, redirect(request.Meta.get(‘HTTP_REFERER‘,‘‘)
HTTP_REFERER
屬性
所有的屬性應該被認為是只讀的,除非另有說明。
1 屬性: 2 django將請求報文中的請求行、頭部信息、內容主體封裝成 HttpRequest 類中的屬性。 3 除了特殊說明的之外,其他均為只讀的。 4 5 6 0.HttpRequest.scheme 7 表示請求方案的字符串(通常為http或https) 8 9 1.HttpRequest.body 10 11 一個字符串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,例如:二進制圖片、XML,Json等。 12 13 但是,如果要處理表單數據的時候,推薦還是使用 HttpRequest.POST 。 14 15 另外,我們還可以用 python 的類文件方法去操作它,詳情參考 HttpRequest.read() 。 16 17 18 19 2.HttpRequest.path 20 21 一個字符串,表示請求的路徑組件(不含域名)。 22 23 例如:"/music/bands/the_beatles/" 24 25 26 27 3.HttpRequest.method 28 29 一個字符串,表示請求使用的HTTP 方法。必須使用大寫。 30 31 例如:"GET"、"POST" 32 33 34 35 4.HttpRequest.encoding 36 37 一個字符串,表示提交的數據的編碼方式(如果為 None 則表示使用 DEFAULT_CHARSET 的設置,默認為 ‘utf-8‘)。 38 這個屬性是可寫的,你可以修改它來修改訪問表單數據使用的編碼。 39 接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取數據)將使用新的 encoding 值。 40 如果你知道表單數據的編碼不是 DEFAULT_CHARSET ,則使用它。 41 42 43 44 5.HttpRequest.GET 45 46 一個類似於字典的對象,包含 HTTP GET 的所有參數。詳情請參考 QueryDict 對象。 47 48 49 50 6.HttpRequest.POST 51 52 一個類似於字典的對象,如果請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。 53 54 POST 請求可以帶有空的 POST 字典 —— 如果通過 HTTP POST 方法發送一個表單,但是表單中沒有任何的數據,QueryDict 對象依然會被創建。 55 因此,不應該使用 if request.POST 來檢查使用的是否是POST 方法;應該使用 if request.method == "POST" 56 57 另外:如果使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。 58 59 7.HttpRequest.COOKIES 60 61 一個標準的Python 字典,包含所有的cookie。鍵和值都為字符串。 62 63 64 65 8.HttpRequest.FILES 66 67 一個類似於字典的對象,包含所有的上傳文件信息。 68 FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。 69 70 註意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會 71 包含數據。否則,FILES 將為一個空的類似於字典的對象。 72 73 74 75 9.HttpRequest.META 76 77 一個標準的Python 字典,包含所有的HTTP 首部。具體的頭部信息取決於客戶端和服務器,下面是一些示例: 78 79 CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。 80 CONTENT_TYPE —— 請求的正文的MIME 類型。 81 HTTP_ACCEPT —— 響應可接收的Content-Type。 82 HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。 83 HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。 84 HTTP_HOST —— 客服端發送的HTTP Host 頭部。 85 HTTP_REFERER —— Referring 頁面。 86 HTTP_USER_AGENT —— 客戶端的user-agent 字符串。 87 QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。 88 REMOTE_ADDR —— 客戶端的IP 地址。 89 REMOTE_HOST —— 客戶端的主機名。 90 REMOTE_USER —— 服務器認證後的用戶。 91 REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。 92 SERVER_NAME —— 服務器的主機名。 93 SERVER_PORT —— 服務器的端口(是一個字符串)。 94 從上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,請求中的任何 HTTP 首部轉換為 META 的鍵時, 95 都會將所有字母大寫並將連接符替換為下劃線最後加上 HTTP_ 前綴。 96 所以,一個叫做 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。 97 98 99 10.HttpRequest.user 100 101 一個 AUTH_USER_MODEL 類型的對象,表示當前登錄的用戶。 102 103 如果用戶當前沒有登錄,user 將設置為 django.contrib.auth.models.AnonymousUser 的一個實例。你可以通過 is_authenticated() 區分它們。 104 105 例如: 106 107 if request.user.is_authenticated(): 108 # Do something for logged-in users. 109 else: 110 # Do something for anonymous users. 111 112 113 user 只有當Django 啟用 AuthenticationMiddleware 中間件時才可用。 114 115 ------------------------------------------------------------------------------------- 116 117 匿名用戶 118 class models.AnonymousUser 119 120 django.contrib.auth.models.AnonymousUser 類實現了django.contrib.auth.models.User 接口,但具有下面幾個不同點: 121 122 id 永遠為None。 123 username 永遠為空字符串。 124 get_username() 永遠返回空字符串。 125 is_staff 和 is_superuser 永遠為False。 126 is_active 永遠為 False。 127 groups 和 user_permissions 永遠為空。 128 is_anonymous() 返回True 而不是False。 129 is_authenticated() 返回False 而不是True。 130 set_password()、check_password()、save() 和delete() 引發 NotImplementedError。 131 New in Django 1.8: 132 新增 AnonymousUser.get_username() 以更好地模擬 django.contrib.auth.models.User。 133 134 135 136 11.HttpRequest.session 137 138 一個既可讀又可寫的類似於字典的對象,表示當前的會話。只有當Django 啟用會話的支持時才可用。 139 完整的細節參見會話的文檔。request屬性相關
方法
1 1.HttpRequest.get_host() 2 3 根據從HTTP_X_FORWARDED_HOST(如果打開 USE_X_FORWARDED_HOST,默認為False)和 HTTP_HOST 頭部信息返回請求的原始主機。 4 如果這兩個頭部沒有提供相應的值,則使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有詳細描述。 5 6 USE_X_FORWARDED_HOST:一個布爾值,用於指定是否優先使用 X-Forwarded-Host 首部,僅在代理設置了該首部的情況下,才可以被使用。 7 8 例如:"127.0.0.1:8000" 9 10 註意:當主機位於多個代理後面時,get_host() 方法將會失敗。除非使用中間件重寫代理的首部。 11 12 13 14 2.HttpRequest.get_full_path() 15 16 返回 path,如果可以將加上查詢字符串。 17 18 例如:"/music/bands/the_beatles/?print=true" 19 20 21 22 3.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt=‘‘, max_age=None) 23 24 返回簽名過的Cookie 對應的值,如果簽名不再合法則返回django.core.signing.BadSignature。 25 26 如果提供 default 參數,將不會引發異常並返回 default 的值。 27 28 可選參數salt 可以用來對安全密鑰強力攻擊提供額外的保護。max_age 參數用於檢查Cookie 對應的時間戳以確保Cookie 的時間不會超過max_age 秒。 29 30 復制代碼 31 >>> request.get_signed_cookie(‘name‘) 32 ‘Tony‘ 33 >>> request.get_signed_cookie(‘name‘, salt=‘name-salt‘) 34 ‘Tony‘ # 假設在設置cookie的時候使用的是相同的salt 35 >>> request.get_signed_cookie(‘non-existing-cookie‘) 36 ... 37 KeyError: ‘non-existing-cookie‘ # 沒有相應的鍵時觸發異常 38 >>> request.get_signed_cookie(‘non-existing-cookie‘, False) 39 False 40 >>> request.get_signed_cookie(‘cookie-that-was-tampered-with‘) 41 ... 42 BadSignature: ... 43 >>> request.get_signed_cookie(‘name‘, max_age=60) 44 ... 45 SignatureExpired: Signature age 1677.3839159 > 60 seconds 46 >>> request.get_signed_cookie(‘name‘, False, max_age=60) 47 False 48 復制代碼 49 50 51 52 4.HttpRequest.is_secure() 53 54 如果請求時是安全的,則返回True;即請求通是過 HTTPS 發起的。 55 56 57 58 5.HttpRequest.is_ajax() 59 60 如果請求是通過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是否是字符串‘XMLHttpRequest‘。 61 62 大部分現代的 JavaScript 庫都會發送這個頭部。如果你編寫自己的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 可以工作。 63 64 如果一個響應需要根據請求是否是通過AJAX 發起的,並且你正在使用某種形式的緩存例如Django 的 cache middleware, 65 你應該使用 vary_on_headers(‘HTTP_X_REQUESTED_WITH‘) 裝飾你的視圖以讓響應能夠正確地緩存。請求相關方法
註意:鍵值對的值是多個的時候,比如checkbox類型的input標簽,select標簽,需要用:
request.POST.getlist("hobby")
上傳文件示例
def upload(request): """ 保存上傳文件前,數據需要存放在某個位置。默認當上傳文件小於2.5M時,django會將上傳文件的全部內容讀進內存。從內存讀取一次,寫磁盤一次。 但當上傳文件很大時,django會把上傳文件寫到臨時文件中,然後存放到系統臨時文件夾中。 :param request: :return: """ if request.method == "POST": # 從請求的FILES中獲取上傳文件的文件名,file為頁面上type=files類型input的name屬性值 filename = request.FILES["file"].name # 在項目目錄下新建一個文件 with open(filename, "wb") as f: # 從上傳的文件對象中一點一點讀 for chunk in request.FILES["file"].chunks(): # 寫入本地文件 f.write(chunk) return HttpResponse("上傳OK")
Respondse對象
與由Django自動創建的HttpRequest對象相比,HttpResponse對象是我們的職責範圍了。我們寫的每個視圖都需要實例化,填充和返回一個HttpResponse。
HttpResponse類位於django.http模塊中。
使用
傳遞字符串
from django.http import HttpResponse response = HttpResponse("Here‘s the text of the Web page.") response = HttpResponse("Text only, please.", content_type="text/plain")
設置或刪除響應頭信息
response = HttpResponse() response[‘Content-Type‘] = ‘text/html; charset=UTF-8‘ del response[‘Content-Type‘]
屬性
HttpResponse.content:響應內容
HttpResponse.charset:響應內容的編碼
HttpResponse.status_code:響應的狀態碼
JsonResponse對象
JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。
from django.http import JsonResponse response = JsonResponse({‘foo‘: ‘bar‘}) print(response.content) b‘{"foo": "bar"}‘
默認只能傳遞字典類型,如果要傳遞非字典類型需要設置一下safe關鍵字參數。
response = JsonResponse([1, 2, 3], safe=False)
render()
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數:
- request: 用於生成響應的請求對象。
- template_name:要使用的模板的完整名稱,可選的參數
- context:添加到模板上下文的一個字典。默認是一個空字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。
- content_type:生成的文檔要使用的MIME類型。默認為 DEFAULT_CONTENT_TYPE 設置的值。默認為‘text/html‘
- status:響應的狀態碼。默認為200。
- useing: 用於加載模板的模板引擎的名稱。
一個簡單的例子:
from django.shortcuts import render def my_view(request): # 視圖的代碼寫在這裏 return render(request, ‘myapp/index.html‘, {‘foo‘: ‘bar‘})
上面的代碼等於:
from django.http import HttpResponse from django.template import loader def my_view(request): # 視圖代碼寫在這裏 t = loader.get_template(‘myapp/index.html‘) c = {‘foo‘: ‘bar‘} return HttpResponse(t.render(c, request))
redirect()
參數可以是:
- 一個模型:將調用模型的get_absolute_url() 函數
- 一個視圖,可以帶有參數:將使用urlresolvers.reverse 來反向解析名稱
- 一個絕對的或相對的URL,將原封不動的作為重定向的位置。
默認返回一個臨時的重定向;傳遞permanent=True 可以返回一個永久的重定向。
示例:
你可以用多種方式使用redirect() 函數。
傳遞一個具體的ORM對象(了解即可)
將調用具體ORM對象的get_absolute_url() 方法來獲取重定向的URL:
from django.shortcuts import redirect def my_view(request): ... object = MyModel.objects.get(...) return redirect(object)
傳遞一個視圖的名稱
def my_view(request): ... return redirect(‘some-view-name‘, foo=‘bar‘)
傳遞要重定向到的一個具體的網址
def my_view(request): ... return redirect(‘/some/url/‘)
當然也可以是一個完整的網址
def my_view(request): ... return redirect(‘http://example.com/‘)
默認情況下,redirect() 返回一個臨時重定向。以上所有的形式都接收一個permanent 參數;如果設置為True,將返回一個永久的重定向:
def my_view(request): ... object = MyModel.objects.get(...) return redirect(object, permanent=True)
擴展閱讀:
臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來說是沒什麽區別的,它主要面向的是搜索引擎的機器人。
A頁面臨時重定向到B頁面,那搜索引擎收錄的就是A頁面。
A頁面永久重定向到B頁面,那搜索引擎收錄的就是B頁面。
小結:
response ——》httpresponse對象
1、HttpResponse(‘字符串’) ----》頁面顯示字符串內容 【Content-Type : text/html;charset=utf8】
2、render(request,‘模板文件名’,{}) ----》返回一個完整的頁面
3、redirect(‘/index/’) 跳轉,重定向 Location:/index/
4.JsonResponse(dict) ———》 Content-Type:application/json
Django框架-Django視圖(views)系統