原文連接:https://www.cnblogs.com/maple-shaw/articles/9285269.htmlhtml
一個視圖函數(類),簡稱視圖,是一個簡單的Python 函數(類),它接受Web請求而且返回Web響應。前端
響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片。python
不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你當前項目目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,你們約定成俗將視圖放置在項目(project)或應用程序(app)目錄中的名爲views.py的文件中。mysql
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
讓咱們來逐行解釋下上面的代碼:web
首先,咱們從 django.http模塊導入了HttpResponse類,以及Python的datetime庫。ajax
接着,咱們定義了current_datetime函數。它就是視圖函數。每一個視圖函數都使用HttpRequest對象做爲第一個參數,而且一般稱之爲request。sql
注意,視圖函數的名稱並不重要;不須要用一個統一的命名方式來命名,以便讓Django識別它。咱們將其命名爲current_datetime,是由於這個名稱可以比較準確地反映出它實現的功能。數據庫
這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每一個視圖函數都負責返回一個HttpResponse對象。django
Django使用請求和響應對象來經過系統傳遞狀態。json
當瀏覽器向服務端請求一個頁面時,Django建立一個HttpRequest對象,該對象包含關於請求的元數據。而後,Django加載相應的視圖,將這個HttpRequest對象做爲第一個參數傳遞給視圖函數。
每一個視圖負責返回一個HttpResponse對象。
CBV :class based views FBV :function based views
咱們以前寫過的都是基於函數的view,就叫FBV。還能夠把view寫成基於類的。
就拿咱們以前寫過的添加班級爲例:
# FBV版添加班級 def add_class(request): if request.method == "POST": class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/") return render(request, "add_class.html")
# CBV版添加班級 from django.views import View class AddClass(View): def get(self, request): return render(request, "add_class.html") def post(self, request): class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/")
注意:
使用CBV時,urls.py中也作對應的修改:
# urls.py中 url(r'^add_class/$', views.AddClass.as_view()),
新增出版社函數分get請求和post請求,各自返回不一樣的內容,邏輯代碼以下
# 新增出版社 def add_publisher(request): error = '' # 對請求方式進行判斷 if request.method == 'POST': # 處理POST請求 # 獲取到出版社的名稱 publisher_name = request.POST.get('publisher_name') # 判斷出版社名稱是否有重複的 if models.Publisher.objects.filter(name=publisher_name): error = '出版社名稱已存在' # 判斷輸入的值是否爲空 if not publisher_name: error = '不能輸入爲空' if not error: # 使用ORM將數據插入到數據庫中 obj = models.Publisher.objects.create(name=publisher_name) # 跳轉到展現出版社的頁面 return redirect('/publisher_list/') # 返回一個包含form表單的頁面 return render(request, 'add_publisher.html', {'error': error})
1)咱們要將函數改爲類,這個類不能直接只是咱們本身寫,由於須要不少功能,本身寫的而後須要繼承Django的View類。
2)定義的類中寫get和post等方法,須要接收參數request。方法中是各自請求作的操做以及返回的一個響應
3)當請求到來時根據請求方法會執行對應的方法,而後返回響應的內容
4)這樣執行的好處是把各個請求的代碼分開了,是邏輯更清楚
5)若是還有其餘的請求,那麼繼續寫對應請求的方法。
6)使用CBV:將以前對應的函數寫成對應的類,而且模塊.類.as_views() 執行,這樣就實現了CBV寫法,get請求就走get方法
若是沒有加as_views(),那麼報錯:
沒有執行報錯:
如此纔是正確的
url(r'^add_publisher/', views.AddPblisher.as_view()),
class View(object): """ Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking. """ http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in six.iteritems(kwargs): setattr(self, key, value) @classonlymethod def as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view
cls指的是當前的類,就是咱們在views模塊中定義的類,url中執行了as_view(),由下圖可知它的返回值是view,也就是views.AddPblisher.as_view()執行就是定義了一個view方法並返回的就是這個view方法。
這就是至關於從上到下執行,而後到了這裏就執行view函數
下面再看view函數作的
cls()將本身寫的類AddPblisher實例化一個對象,並賦予self。而後這個子函數view中就能以self代替AddPblisher的對象作操做。
view函數中將request賦值給實例變量self.request,這樣就能在CBV方式的類中get或其它方法裏使用self.request,從而操做請求對象。而在FBV方式中直接使用request。
class View(object): """ Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking. """ http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in six.iteritems(kwargs): setattr(self, key, value) @classonlymethod def as_view(cls, **initkwargs): #cls指的是當前的類,就是咱們在views模塊中定義的類 """ Main entry point for a request-response process. """ for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) # cls()將本身寫的類AddPblisher實例化一個對象,並賦予self。而後在類AddPblisher中就能以self代替AddPblisher的對象作操做。 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request #在這裏request和self.request是同樣的,這樣作是爲了在本身建立的類中能用self.的方法 self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) #view返回的是dispatch方法的返回值。 view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. #http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] if request.method.lower() in self.http_method_names: #若是請求方式變小寫後在上面的列表中,那麼讓handler經過反射獲取到你的請求方法,不然讓它 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) #等於 self.http_method_not_allowed else: handler = self.http_method_not_allowed #不然handler等於 self.http_method_not_allowed 方法 return handler(request, *args, **kwargs) #返回handler的執行結果給as_view中的view,有人調用as_view方法是,那麼返回的就是view的返回值,view方法的返回值是 #當url中執行了as_view方法時,返回的是view這個實現閉包並封裝了數據的函數地址,url中至關於寫的是view這個函數,那麼url路由以後會執行view這個函數。 view執行的返回值就是dispatch執行的返回值。dispatch執行的返回值就是handler函數的返回值。[1]若是瀏覽器的請求方式在個人方式列表中(通常是8個)存在,那麼handler就是self對象自己和請求方式經過反射獲取到小寫的請求方式的方法。[2]若是不是那麼讓它等於另外一個方法。[3]若是handler是【1】,那麼get方法首先從我寫的類中找,咱們在類中寫了get請求方法,那麼handler執行的返回值就是咱們get的返回內容。也就是咱們在本身建立的類中寫了對應請求的方法,那麼就會執行咱們寫的對應請求的方法。[4]若是handler是【2】,那麼返回的self.http_method_not_allowed是不被容許訪問的方法執行返回結果。即打印405錯誤碼並返回執行不被容許的的返回方法。 def http_method_not_allowed(self, request, *args, **kwargs): logger.warning( 'Method Not Allowed (%s): %s', request.method, request.path, extra={'status_code': 405, 'request': request} ) return http.HttpResponseNotAllowed(self._allowed_methods())
#當url中執行了as_view方法時,返回的是view這個實現閉包並封裝了數據的函數地址,url中至關於寫的是view這個函數,那麼url路由以後會執行view這個函數。
view執行的返回值就是dispatch執行的返回值。dispatch執行的返回值就是handler函數的返回值。[1]若是瀏覽器的請求方式在個人方式列表中(通常是8個)存在,那麼handler就是self對象自己和請求方式經過反射獲取到小寫的請求方式的方法。[2]若是不是那麼讓它等於另外一個方法。[3]若是handler是【1】,那麼get方法首先從我寫的類中找,咱們在類中寫了get請求方法,那麼handler執行的返回值就是咱們get的返回內容。也就是咱們在本身建立的類中寫了對應請求的方法,那麼就會執行咱們寫的對應請求的方法。[4]若是handler是【2】,那麼返回的self.http_method_not_allowed是不被容許訪問的方法執行返回結果。即打印405錯誤碼並返回執行不被容許的的返回方法。
若是get不到也是執行不被容許的方法
base.py class View(object): http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls ................. return view def dispatch(self, request, *args, **kwargs): if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): logger.warning( 'Method Not Allowed (%s): %s', request.method, request.path, extra={'status_code': 405, 'request': request} ) return http.HttpResponseNotAllowed(self._allowed_methods()) 另外一個文件:response.py class HttpResponseNotAllowed(HttpResponse): status_code = 405 def __init__(self, permitted_methods, *args, **kwargs): super(HttpResponseNotAllowed, self).__init__(*args, **kwargs) self['Allow'] = ', '.join(permitted_methods) def __repr__(self): return '<%(cls)s [%(methods)s] status_code=%(status_code)d%(content_type)s>' % { 'cls': self.__class__.__name__, 'status_code': self.status_code, 'content_type': self._content_type_for_repr, 'methods': self['Allow'], }
以下,我要在子中重寫源碼中的dispatch()方法。由於dispatch執行的結果就是返回的頁面的內容,2處找這個方法先在1處尋找,找到後給瀏覽器返回ok,那麼此時不管什麼請求都是返回的ok,不符合咱們的須要
咱們重寫dispatch這個方法,那麼就至關因而須要給這個方法添加功能。函數中裝飾器能夠給另外的函數添加功能,那麼重寫方法時咱們能夠super執行父類中的方法並接收返回值,在執行父類中方法的先後作些其它的操做給它添加功能。
若是將super先後換成時間,那麼就能計算dispatch執行時間
FBV自己就是一個函數,因此和給普通的函數加裝飾器無差:
def wrapper(func): def inner(*args, **kwargs): start_time = time.time() ret = func(*args, **kwargs) end_time = time.time() print("used:", end_time-start_time) return ret return inner # FBV版添加班級 @wrapper def add_class(request): if request.method == "POST": class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/") return render(request, "add_class.html")
類中的方法與獨立函數不徹底相同,所以不能直接將函數裝飾器應用於類中的方法 ,咱們須要先將其轉換爲方法裝飾器。
Django中提供了method_decorator裝飾器用於將函數裝飾器轉換爲方法裝飾器。
# CBV版添加班級 from django.views import View from django.utils.decorators import method_decorator class AddClass(View): @method_decorator(wrapper) def get(self, request): return render(request, "add_class.html") def post(self, request): class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/")
# 使用CBV時要注意,請求過來後會先執行dispatch()這個方法,若是須要批量對具體的請求處理方法,如get,post等作一些操做的時候,這裏咱們能夠手動改寫dispatch方法,這個dispatch方法就和在FBV上加裝飾器的效果同樣。 class Login(View): def dispatch(self, request, *args, **kwargs): print('before') obj = super(Login,self).dispatch(request, *args, **kwargs) print('after') return obj def get(self,request): return render(request,'login.html') def post(self,request): print(request.POST.get('user')) return HttpResponse('Login.post')
咱們在視圖函數中給類中方法加裝飾器,先導入某個類。而後直接在get等方法前面@方式裝飾器(裝飾器函數名)。若是想要全部請求加上裝飾器,那麼重寫dispatch方法並執行父的方法,而後給dispatch方法添加這個裝飾器。
還能夠加多個,指定方法名字:
在類中方法添加裝飾器,能夠直接
@裝飾器名
def 方法名字(self):
使用和不使用method_decorator的區別以下,主要是不使用時參數第一個是本身寫的類對象,傳到裝飾器的第一個參數是方法中的self,第二個纔是 個人request對象;使用時那麼裝飾器中第一個參數就是request
所以裝飾器中要使用request對象,那麼須要判斷第幾個形參是它:
當get訪問一個網頁的時候,GET和POST返回的都是這裏類型的,
當get請求後面有拼接的內容的時候,
get就有值了
當訪問是這個路徑的時候,打印一下request.path_info 返回用戶訪問路徑,不包括ip和端口
打印body,由於get沒有請全體,是沒有內容的bytes類型。請求行,請求頭,請求體
post請求中打印請求體:print('request.body'),數據會進行url編碼,原始的數據編碼了的
當一個頁面被請求時,Django就會建立一個包含本次請求原信息的HttpRequest對象。
Django會將這個對象自動傳遞給響應的視圖函數,通常視圖函數約定俗成地使用 request 參數承接這個對象。
全部的屬性應該被認爲是隻讀的,除非另有說明。
0.HttpRequest.scheme
表示請求方案的字符串(一般爲http或https),即瀏覽器請求協議http https
print(request,type(request)) # <WSGIRequest: GET '/test/'> <class 'django.core.handlers.wsgi.WSGIRequest'>
屬性: django將請求報文中的請求行、頭部信息、內容主體封裝成 HttpRequest 類中的屬性。 除了特殊說明的以外,其餘均爲只讀的。 0.HttpRequest.scheme 表示請求方案的字符串(一般爲http或https) 1.HttpRequest.body 一個字符串,表明請求報文的主體。在處理非 HTTP 形式的報文時很是有用,例如:二進制圖片、XML,Json等。 可是,若是要處理表單數據的時候,推薦仍是使用 HttpRequest.POST 。 另外,咱們還能夠用 python 的類文件方法去操做它,詳情參考 HttpRequest.read() 。 2.HttpRequest.path 一個字符串,表示請求的路徑組件(不含域名)。 例如:"/music/bands/the_beatles/" 3.HttpRequest.method 一個字符串,表示請求使用的HTTP 方法。必須使用大寫。 例如:"GET"、"POST" 4.HttpRequest.encoding 一個字符串,表示提交的數據的編碼方式(若是爲 None 則表示使用 DEFAULT_CHARSET 的設置,默認爲 'utf-8')。 這個屬性是可寫的,你能夠修改它來修改訪問表單數據使用的編碼。 接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取數據)將使用新的 encoding 值。 若是你知道表單數據的編碼不是 DEFAULT_CHARSET ,則使用它。 5.HttpRequest.GET 一個相似於字典的對象,包含 HTTP GET 的全部參數。詳情請參考 QueryDict 對象。 6.HttpRequest.POST 一個相似於字典的對象,若是請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。 POST 請求能夠帶有空的 POST 字典 —— 若是經過 HTTP POST 方法發送一個表單,可是表單中沒有任何的數據,QueryDict 對象依然會被建立。 所以,不該該使用 if request.POST 來檢查使用的是不是POST 方法;應該使用 if request.method == "POST" 另外:若是使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。 7.HttpRequest.COOKIES 一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串。 8.HttpRequest.FILES 一個相似於字典的對象,包含全部的上傳文件信息。 FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。 注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會 包含數據。不然,FILES 將爲一個空的相似於字典的對象。 9.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 鍵。 10.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。 11.HttpRequest.session 一個既可讀又可寫的相似於字典的對象,表示當前的會話。只有當Django 啓用會話的支持時纔可用。 完整的細節參見會話的文檔。
{ 'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\Administrator\\AppData\\Roaming', 'COMMONPROGRAMFILES': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMPUTERNAME': 'PC-20190328RVNA', 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe', 'DJANGO_SETTINGS_MODULE': 'bookmanager.settings', 'FP_NO_HOST_CHECK': 'NO', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\Administrator', 'LOCALAPPDATA': 'C:\\Users\\Administrator\\AppData\\Local', 'LOGONSERVER': '\\\\PC-20190328RVNA', 'NUMBER_OF_PROCESSORS': '4', 'OS': 'Windows_NT', 'PATH': 'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\軟件安裝\\Git\\cmd;C:\\mysql\\mysql-5.6.44-winx64\\bin;C:\\python3\\Scripts\\;C:\\python3\\', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'x86', 'PROCESSOR_ARCHITEW6432': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3a09', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files (x86)', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\', 'PUBLIC': 'C:\\Users\\Public', 'PYCHARM_HOSTED': '1', 'PYCHARM_MATPLOTLIB_PORT': '50724', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'C:\\mcw\\bookmanager;C:\\軟件安裝\\PyCharm 2018.3.5\\helpers\\pycharm_matplotlib_backend', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\Windows', 'TEMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp', 'USERDOMAIN': 'PC-20190328RVNA', 'USERNAME': 'Administrator', 'USERPROFILE': 'C:\\Users\\Administrator', 'WINDIR': 'C:\\Windows', 'WINDOWS_TRACING_FLAGS': '3', 'WINDOWS_TRACING_LOGFILE': 'C:\\BVTBin\\Tests\\installpackage\\csilogfile.log', 'RUN_MAIN': 'true', 'SERVER_NAME': 'PC-20190328RVNA', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/test/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=e17Wb68amZdumsRa67LXuTzmdEjaA2lYLj0OkmjiiR2SKPRXBHoYcB3c929v8csg', 'wsgi.input': < _io.BufferedReader name = 776 > , 'wsgi.errors': < _io.TextIOWrapper name = '<stderr>' mode = 'w' encoding = 'UTF-8' > , 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': < class 'wsgiref.util.FileWrapper' > , 'CSRF_COOKIE': 'e17Wb68amZdumsRa67LXuTzmdEjaA2lYLj0OkmjiiR2SKPRXBHoYcB3c929v8csg' }
上傳文件示例
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")
1)post表單中寫一個類型是file的input標籤,起個name,給個button。
瀏覽器上傳一張圖片,查看文件是否獲取到,結果爲空
須要修改傳輸數據類型:
默認用的是下面這個:post請求中打印請求體:print('request.body'),數據會進行url編碼,指的就是這個編碼
而後上傳文件:文件在request的FILES屬性中
一個相似於字典的對象,包含全部的上傳文件信息。 FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。 注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會 包含數據。不然,FILES 將爲一個空的相似於字典的對象。
get獲取到這個文件對象。默認位置在項目根目錄,獲取到f1的值,值.name是文件名
全路徑:若是有拼接的內容也會獲取到。不包含IP端口,可是包含參數
1.HttpRequest.get_host() 根據從HTTP_X_FORWARDED_HOST(若是打開 USE_X_FORWARDED_HOST,默認爲False)和 HTTP_HOST 頭部信息返回請求的原始主機。 若是這兩個頭部沒有提供相應的值,則使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有詳細描述。 USE_X_FORWARDED_HOST:一個布爾值,用於指定是否優先使用 X-Forwarded-Host 首部,僅在代理設置了該首部的狀況下,才能夠被使用。 例如:"127.0.0.1:8000" 注意:當主機位於多個代理後面時,get_host() 方法將會失敗。除非使用中間件重寫代理的首部。 2.HttpRequest.get_full_path() 返回 path,若是能夠將加上查詢字符串。 例如:"/music/bands/the_beatles/?print=true" 3.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) 返回簽名過的Cookie 對應的值,若是簽名再也不合法則返回django.core.signing.BadSignature。 若是提供 default 參數,將不會引起異常並返回 default 的值。 可選參數salt 能夠用來對安全密鑰強力攻擊提供額外的保護。max_age 參數用於檢查Cookie 對應的時間戳以確保Cookie 的時間不會超過max_age 秒。 複製代碼 >>> request.get_signed_cookie('name') 'Tony' >>> request.get_signed_cookie('name', salt='name-salt') 'Tony' # 假設在設置cookie的時候使用的是相同的salt >>> request.get_signed_cookie('non-existing-cookie') ... KeyError: 'non-existing-cookie' # 沒有相應的鍵時觸發異常 >>> request.get_signed_cookie('non-existing-cookie', False) False >>> request.get_signed_cookie('cookie-that-was-tampered-with') ... BadSignature: ... >>> request.get_signed_cookie('name', max_age=60) ... SignatureExpired: Signature age 1677.3839159 > 60 seconds >>> request.get_signed_cookie('name', False, max_age=60) False 複製代碼 4.HttpRequest.is_secure() 若是請求時是安全的,則返回True;即請求通是過 HTTPS 發起的。 5.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') 裝飾你的視圖以讓響應可以正確地緩存。
注意:鍵值對的值是多個的時候,好比checkbox類型的input標籤,select標籤,須要用:
request.POST.getlist("hobby")
與由Django自動建立的HttpRequest對象相比,HttpResponse對象是咱們的職責範圍了。咱們寫的每一個視圖都須要實例化,填充和返回一個HttpResponse。
若是沒有返回報錯,須要返回一個HttpResponse對象
HttpResponse類位於django.http模塊中。
render參數,有request 模板 上下文就是咱們傳的變量(字典)
下面render_to_string方法會拿到模板和變量作字符串替換。返回的content就是渲染以後的html字符串。這個content內容又給了HttpResponse對象。也就是說render裏面返回的仍是HttpResponse對象,只是裏面調用其它的方法把這個模板渲染好了。這裏是Django的模板引擎,也能夠換成jinja2的。
再看看redirect,拿到的是兩個類:,返回的而是其中一個類的對象
下面這個是永久跳轉的類,
永久跳轉的類繼承的重定向基本的類,又是繼承的HttpResponse這個類:location就是咱們在開發這個工具中看到的重定向中的那個屬性。因此重定向也是繼承的HttpResponse。
它也是繼承的這個對象:
傳遞字符串
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是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)
定義一個字典返回給瀏覽器
顯示的是name和age連到一塊的:將字典迭代拿的裏面的key
可是我想要的是完整的字典,那麼我就要本身作json序列化了:
顯示的是完整的字典內容
那麼還可使用另外一個類作返回內容傳遞字典數據,直接將字典放到JsonResponse對象中
效果以下:跟本身作的json序列化比起來,小了點細了點。而且告訴瀏覽器當前發送數據內容的類型。若是是在使用ajax,那麼它遇到這個內容它本身會作反序列化。前端發送一個請求,回來以後它看到這個類型本身會將這個數據反序列化,變成前端使用的對象,而後點的方法取裏面的內容。
若是是本身作序列化的話那麼響應頭的內容類型以下。發送的是普通文本,它不會給你作任 何變化,你想用的話就須要本身作反序列化
咱們也能夠本身序列化發送,可是須要修改這個內容類型的屬性,這樣也能夠達到同樣的效果。用字典從新賦值的方式修改它的屬性值
HttpResponse默認返回的是text/html charset utf-8 JsonResponse默認返回的是 application/json 。
下面能夠找一下它的默認的:
這個settings點不進去,它是全局配置文件裏的:由下能夠看到HttpResponse返回的是默認類型
由下能夠看出沒有傳默認參數那麼使用的是text/html,
那麼把內容類型傳遞一個參數修改爲別的也能夠改變它的類型:
由下能夠看到JsonResponse默認的就是 application/json 。JsonReponse會給你作序列化,而且響應頭給你設置成application/json,有了這個以後,前端拿到數據就自動反序列化
那麼其它類型的好比列表傳輸呢?報錯: In order to allow non-dict objects to be serialized set the safe parameter to False.
那麼根據提示設置safe爲False前端就拿到數據了。這是由於JsonResponse默認只支持序列化字典類型的。若是是非字典類型的那麼就要加上safe=False
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數:
一個簡單的例子:
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))
參數能夠是:
默認返回一個臨時的重定向;傳遞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頁面。