一個視圖函數,簡稱視圖,是一個簡單的Python函數,它接受Web請求并且返回Web響應。響應可以是一張網頁的HTML內容,一個重定向,一個 404 錯誤,一個 XML 文檔,或者一張圖片. . . 是任何東西都可以。無論視圖本身包含什么邏輯,都要返回響應。
應用程序目錄中的名為views.py的文件中。
前面我們學習中視圖都是通過定義函數來實現的,例如:
# views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username and pwd:
res['user'] = username
return JsonResponse(res, json_dumps_params={"ensure_ascii": False})
res['msg'] = '用戶名或密碼錯誤'
return JsonResponse(res, json_dumps_params={"ensure_ascii": False})
# *************************
# urls.py
from .views import login
urlpatterns = [
path('login/', login, name='login')
]
http請求中產生兩個核心對象:
1)HTTP 請求--->HttpRequest 對象,用戶請求相關的所有信息(對象);
HTTP 協議以【請求 - 回復 】的方式工作。客戶發送請求時,可以在請求中附加數據。服務器通過解析請求,就可以獲得客戶傳來的數據,并根據 URL 來提供特定的服務。
一個請求的大概流程:
HTTP請求流程
通過 TCP 三次握手進行連接,然后開始傳數據,客戶端發送請求給服務器,服務器作出相應的相應返回給客戶端。
2)HTTP 響應--->HttpResponse 對象,響應字符串。
如:
# views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("你好")
# 在urls.py中修改配置
from . import views
path('', views1.index, name='index'),
上面我們用到的request,就是HttpRequest對象。HttpResponse("你好"),就是HttpResponse對象,它向http請求響應了一段字符串。
視圖函數,就是圍繞著HttpRequest和HttpResponse這兩個對象進行的。
Django在接收到http請求之后,Django會將http協議請求報文中的請求行、首部信息、內容主體封裝到一個HttpRequest對象,并且將HttpRequest對象當作參數傳給視圖函數的第一個參數request。在視圖函數中,通過訪問該對象的屬性便可以提取http請求數據。
HttpRequest對象上大部分的屬性都是只讀的。因為這些屬性是從客戶端上傳上來的,沒必要做任何的修改。以下將對一些常用的屬性進行講解:
request.scheme:網絡請求的協議,一般是http和https。
request.path:當前請求 URL 路徑,但不包含協議和域名以及參數。比如https://www.qmpython.com/articles/detail-45.html,那么 path就是/articles/detail-45.html。
request.method:代表當前請求的http方法。一般是GET還是POST。
request.GET:一個類似于字典的django.http.request.QueryDict對象,可以通過訪問字典的方式訪問里面的值,里面的值是通過GET請求傳遞進來的參數(以?xxx=xxx的方式)。
# 當請求url為:http://www.qmpython.com:8004/user/index/3.html?a=1&b=2
print(request.GET) # 輸出:<QueryDict: {'a': ['1'], 'b': ['2']}>
print(request.GET.get('a')) # 輸出:1
print(request.GET.get('b')) # 輸出:2
# 針對像這種,http://www.qmpython.com:8004/user/index/3.html?a=1&b=2&c=3&c=4&c=5,存在同個參數多個值的情況
print(request.GET) # <QueryDict: {'a': ['1'], 'b': ['2'], 'c': ['3', '4', '5']}>
print(request.GET.get('a')) # 1
print(request.GET.get('b')) # 2
print(request.GET.getlist('c')) # ['3', '4', '5']
request.POST:一個類似于字典的django.http.request.QueryDict對象,封裝了POST請求所包含的表單數據。注意,這個POST里面不包含上傳的文件信息。
例如模板文件login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注冊頁面</title>
</head>
<body>
<h2>注冊界面</h2>
<form action="" method="post">
{% csrf_token %} <!-- 必須加上這一行,后續會詳細介紹 -->
用戶名:<input type="text" name="username" placeholder="請輸入賬號"/><br/>
密 碼:<input type="password" name="password"/><br/>
愛好:
<input type="checkbox" name="hobbies" value="music">音樂
<input type="checkbox" name="hobbies" value="read">閱讀
<input type="checkbox" name="hobbies" value="dancing">跳舞
<br/>
<input type="submit" value="注冊"/>
</form>
</body>
</html>
視圖函數views.py:
def index(request, id):
if request.method == 'GET':
print(request.GET) # <QueryDict: {'a': ['1'], 'b': ['2'], 'c': ['3', '4', '5']}>
print(request.GET.get('a')) # 1
print(request.GET.get('b')) # 2
print(request.GET.getlist('c')) # ['3', '4', '5']
return render(request, 'user/index.html')
elif request.method == 'POST':
print(request.POST)
# <QueryDict: {'csrfmiddlewaretoken': ['J390sN2dzBcW5lCg37ywxhrIVi3MXepLy1Qal7tYA8zYhVH9TJAdMfEV0SCgXqcM'],
# 'username': ['qmpython'], 'password': ['1234'], 'hobbies': ['music', 'dancing']}>
print(request.POST.get('username')) # qmpython
print(request.POST.get('password')) # 1234
print(request.POST.getlist('hobbies')) # ['music', 'dancing']
return HttpResponse('注冊信息提交成功')
request.body:http請求中傳遞的原始數據,是一個byte類型的string。
當瀏覽器基于http協議的POST方法提交數據時,數據會被放到請求體中發送給Django,Django會將接收到的請求體數據存放于HttpRequest.body屬性中,因為該屬性的值為Bytes類型,所以通常情況下直接處理Bytes并從中提取有用數據的操作是復雜而繁瑣的,好在Django會對它做進一步的處理與封裝以便我們更為方便地提取數據,比如對于form表單來說,提交數據的常用方法為GET與POST。
1)如果表單屬性method='GET',那么在提交表單時,表單內數據不會存放于請求體body中,而是會將表單數據按照k1=v1&k2=v2&k3=v3的格式放到url中,然后發送給Django,Django會將這些數據封裝到request.GET中,注意此時的request.body為空,無用!模板文件中:
<!-- 如將之前的表單提交改成get方法 -->
<form action="" method="get">
...
</form>
<!--
輸入地址:http://www.qmpython.com:8004/user/index/3.html?a=1&b=6
填寫完用戶名和密碼,提交之后,表單數據按照k1=v1&k2=v2形式放到url后:
http://www.qmpython.com:8004/user/index/3.html?csrfmiddlewaretoken=ZpICWaQOnRqYfgQGbkgELZYyt6S4hajzSnEqYhv0qomjTmOChQFG4LMeXNDd54i0&username=qmpython&password=123456&hobbies=read&hobbies=dancing
原來的參數a,b被覆蓋了!
-->
視圖views.py中:
print(request.body) # b'' # get方式請求,請求數據不會放到body中
print(request.GET)
# <QueryDict: {'csrfmiddlewaretoken': ['ZpICWaQOnRqYfgQGbkgELZYyt6S4hajzSnEqYhv0qomjTmOChQFG4LMeXNDd54i0'], 'username': ['qmpython'], 'password': ['123456'], 'hobbies': ['read', 'dancing']}>
2)如果表單屬性method='POST',那么在提交表單時,表單內的所有數據都會存放于請求體中,在發送給Django后會封裝到request.body里,此時Django為了方便我們提取數據,會request.body的數據進行進一步的處理,具體如何處理呢,需要從form表單提交數據的編碼格式說起:form表單對提交的表單數據有兩種常用的編碼格式,可以通過屬性enctype進行設置,如下
如果form表單提交數據是按照第一種方式,那么request.body中數據的格式類似于GET方法的數據格式,如k1=v1&k2=v2,此時Django會將request.body中的數據提取出來封裝到request.POST中方便我們提取。
<!-- 如將之前的表單提交改成get方法 -->
<form action="" method="post">
...
</form>
視圖中:
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
print(request.body) #b'csrfmiddlewaretoken=JbgAeQk8IMiCvn6uxBuM6mMix9l1U4Lpy9XK7aLTJjFEHXbnndwtlkZvCJUvUgyq&username=admin&password=123456'
print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['JbgAeQk8IMiCvn6uxBuM6mMix9l1U4Lpy9XK7aLTJjFEHXbnndwtlkZvCJUvUgyq'], 'username': ['admin'], 'password': ['123456']}>
return HttpResponse('登錄成功')
request.FILES:也是一個類似于字典的django.http.request.QueryDict對象。這個屬性中包含了所有上傳的文件。如果使用form表單POST上傳文件的話,文件數據將包含在request.Files屬性中。只有在請求的方法為POST 且提交的form表單帶有enctype="multipart/form-data"的情況下才會包含數據,否則,FILES將為一個空的類似于字典的對象。
該屬性值為一個類似于字典的對象,可以包含多組key:value(對應多個上傳的文件),其中每個key為<input type="file" name="" />中name屬性的值,而value則為對應的文件數據。
<form action="" method="post" enctype="multipart/form-data">
頭像:<input type="file" name="head_img">
</form>
#views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
#print(request.body)
print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['yIpuMsAdApp1mPt9tqEHJxXUkLxmS7t3CebPbZhWz6TIaKoDJTMTHG9oBkugHxnt'], 'username': ['admin'], 'password': ['123456']}>
print(request.POST.get('username')) # admin
print(request.FILES) # <MultiValueDict: {'head_img': [<InMemoryUploadedFile: DSP_IP.jpg (image/jpeg)>]}>
print(request.FILES.get('head_img')) # DSP_IP.jpg
# 然后可以使用文件寫入模塊write
return HttpResponse('登錄成功')
request.COOKIES:一個標準的Python字典,包含所有的cookie信息,鍵值對都是字符串類型。
request.session:返回一個QueryDict的類字典類型的集合,用來操作服務器的session,這個屬性要有效,必須添加SessionMiddleware這個中間件。
MIDDLEWARE = [
...
'django.contrib.sessions.middleware.SessionMiddleware',
...
]
request.user:user 只有當Django啟用 AuthenticationMiddleware 中間件時才可用。它的值是一個 setting.py 里面AUTH_USER_MODEL 字段所定義的類的對象,表示當前登錄的用戶。如果用戶當前沒有登錄,user 將設為 django.contrib.auth.models.AnonymousUser 的一個實例。可以通過 is_authenticated() 區分它們。
MIDDLEWARE = [
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
]
request.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 鍵。
超實用例子:
如果服務器使用了nginx做反向代理或者負載均衡,那么這個值返回的是127.0.0.1 ,這時候可以使用HTTP_X_FORWARDED_FOR來獲取,所以獲取 ip 地址的代碼片段如下:
#獲取IP
if 'HTTP_X_FORWARDED_FOR' in request.META:
ip = request.META['HTTP_X_FORWARDED_FOR']
else:
ip = request.META['REMOTE_ADDR']
request.is_secure():是否是采用https協議。
request.is_ajax():是否采用ajax發送的請求。原理就是判斷請求頭中是否存在X-Requested-With:XMLHttpRequest。
request.get_host():服務器的域名。如果在訪問的時候還有端口號,那么會加上端口號。比如www.qmpython.com:9000。
request.get_full_path():獲取url地址的完整path。如果有查詢字符串,還會加上查詢字符串。比如/music/bands/?print=True。
request.get_raw_uri():獲取請求的完整url。
# 如果請求地址是:http://www.qmpython.com:8004/user/index/3.html?a=1&b=6
print(request.path) # /user/index/3.html
print(request.get_full_path()) # /user/index/3.html?a=1&b=6
print(request.get_raw_uri()) # http://www.qmpython.com:8004/user/index/3.html?a=1&b=6
Django服務器接收到客戶端發送過來的請求后,會將提交上來的這些數據封裝成一個HttpRequest對象傳給視圖函數。那么視圖函數在處理完相關的邏輯后,也需要返回一個響應給瀏覽器。而這個響應,我們必須返回HttpResponseBase或者他的子類的對象。相應對象主要有三種形式:HttpResponse,render,redirect。而HttpResponse則是HttpResponseBase用得最多的子類。那么接下來就來介紹一下HttpResponse及其子類。
content:代表要發送給客戶端的內容。
status_code:返回的 HTTP 響應狀態碼。
content_type:返回的數據的 MIME 類型,返回的數據的 MIME 類型,默認為text/html;charset=utf-8。瀏覽器會根據這個屬性,來顯示數據。如果是text/html,那么就會解析這個字符串,如果text/plain,那么就會顯示一個純文本。常用的Content-Type如下:
設置請求頭:response['X-Access-Token']='xxxx'。
charset:響應體的編碼,如果沒有指定,則會使用content_type中設置的charset。
render:將指定頁面渲染后返回給瀏覽器。
render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,并返回一個渲染后的HttpResponse對象。
def index(request):
articles = Article.objects.all().order_by('-id')
print(request.body)
context = {
'articles':articles,
}
return render(request, 'index.html',context)
參數:request:用于生成響應的請求對象。template_name:要使用的模板的完整名稱,可選的參數context:添加到模板上下文的一個字典。默認是一個空字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。content_type:生成的文檔要使用的MIME類型。默認為DEFAULT_CONTENT_TYPE 設置的值。status:響應的狀態碼。默認為 200。
render方法主要是將從服務器提取的數據,填充到模板中,然后將渲染后的 html靜態文件返回給瀏覽器。這里一定要注意:render渲染的是模板。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>博客首頁</title>
</head>
<body>
<div style="margin: 0 auto">
<ul>
<h3>最新文章</h3>
{% for article in articles %}
<li>{{ x.article }}</li>
{% endfor %}
</ul>
</div>
</body>
</html>
上面 {}之間包括的就是我們要從數據庫取出的數據,進行填充。對于這樣一個沒有填充數據的html文件,瀏覽器是不能進行渲染的,所以,對于上述{}之間的內容先要被render進行渲染之后,才能發送給瀏覽器。
redirect:多用于頁面跳轉。
redirect的參數可以是:一個模型:將調用模型的get_absolute_url() 函數。
from django.shortcuts import redirect
def my_view(request):
...
# 傳遞一個對象,將調用get_absolute_url() 方法來獲取重定向的URL
object = MyModel.objects.get(...)
return redirect(object)
一個視圖,可以帶有參數:將使用urlresolvers.reverse 來反向解析名稱。
def my_view(request):
...
return redirect('some-view-name', foo='bar')
一個絕對的或相對的URL,將原封不動的作為重定向的位置。
def my_view(request):
...
return redirect('/some/url/')
# return redirect('https://www.django.cn/')
默認返回一個臨時的重定向;傳遞permanent=True 可以返回一個永久的重定向。
重定向分為永久性重定向和暫時性重定向,在頁面上體現的操作就是瀏覽器會從一個頁面自動跳轉到另外一個頁面。比如用戶訪問了一個需要權限的頁面,但是該用戶當前并沒有登錄,因此我們應該給他重定向到登錄頁面。
在Django中,重定向是使用redirect(to, *args, permanent=False, **kwargs)來實現的。to是一個url,permanent代表的是這個重定向是否是一個永久的重定向,默認是False。關于重定向的使用。請看以下例子:
from django.shortcuts import reverse,redirect
def profile(request):
if request.GET.get("username"):
return HttpResponse("%s,歡迎來到個人中心頁面!")
else:
return redirect(reverse("user:login"))
render和redirect兩者區別: 第一,假如render返回一個登陸成功后的頁面,刷新該頁面將回復到跳轉前頁面。而 redirect 則不會 第二,如果頁面需要模板語言渲染,需要的將數據庫的數據加載到html,那么render方法則不會顯示這一部分,render返回一個登陸成功頁面,不會經過url路由分發系統,也就是說,不會執行跳轉后url的視圖函數。這樣,返回的頁面渲染不成功;而redirect是跳轉到指定頁面,當登陸成功后,會在url路由系統進行匹配,如果有存在的映射函數,就會執行對應的映射函數。
set_cookie:用來設置cookie信息。后面講到授權的時候會著重講到。
delete_cookie:用來刪除cookie信息。
write:HttpResponse是一個類似于文件的對象,可以用來寫入數據到數據體(content)中。
GET請求:一般用來向服務器獲取數據,但不會向服務器提交數據,不會對服務器的狀態進行更改。比如向服務器獲取某篇文章的詳情。
POST請求:一般是用來向服務器提交數據,會對服務器的狀態進行更改。比如提交一篇文章給服務器。
Django內置的視圖裝飾器可以給視圖提供一些限制。比如這個視圖只能通過GET的method訪問等。以下將介紹一些常用的內置視圖裝飾器。
1)django.http.decorators.http.require_http_methods:這個裝飾器需要傳遞一個允許訪問的方法的列表。比如只能通過GET的方式訪問。那么示例代碼如下:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET"])
def my_view(request):
pass
2)django.views.decorators.http.require_GET:這個裝飾器相當于是require_http_methods(['GET'])的簡寫形式,只允許使用GET的method來訪問視圖。示例代碼如下:
from django.views.decorators.http import require_GET
@require_GET
def my_view(request):
pass
3)django.views.decorators.http.require_POST:這個裝飾器相當于是require_http_methods(['POST'])的簡寫形式,只允許使用POST的method來訪問視圖。示例代碼如下:
from django.views.decorators.http import require_POST
@require_POST
def my_view(request):
pass
4)django.views.decorators.http.require_safe:這個裝飾器相當于是require_http_methods(['GET','HEAD'])的簡寫形式,只允許使用相對安全的方式來訪問視圖。因為GET和HEAD不會對服務器產生增刪改的行為。因此是一種相對安全的請求方式。示例代碼如下:
from django.views.decorators.http import require_safe
@require_safe
def my_view(request):
pass
公眾號: Python野路子
野路子學習整理和分享Python入門和Python Web開發以及Python爬蟲相關知識。歡迎互相學習交流,共同進步~~
日,國家大學生就業服務平臺——24365校園招聘服務再推出“2023屆全國高校畢業研究生專場網上招聘月”、“‘一帶一路’區域面向高校畢業生網上招聘會”、“重點領域企業面向2023屆高校畢業生網絡招聘會”等活動。更多信息,跟教育小微一起來看——
2023屆全國高校畢業研究生專場網上招聘月
2022年12月26日至2023年1月26日,教育部高校學生司、教育部學生服務與素質發展中心舉辦“2023屆全國高校畢業研究生專場網上招聘月”活動,為首批2023屆研究生畢業生提供就業服務。
本次招聘會以線上方式開展,截至目前,約500家單位報名參會,招聘近1萬人。
參會鏈接:
https://www.ncss.cn/student/jobfair/fairdetails.html?fairId=5QWAG31Fmnq9Neqv2ScxeK
掃碼參會
“一帶一路”區域面向高校畢業生網上招聘會
2022年12月23日至2023年1月23日,教育部學生服務與素質發展中心舉辦“‘一帶一路’區域面向高校畢業生網上招聘會”,助推國家“一帶一路”經濟發展戰略,引導和鼓勵高校畢業生奔赴國家經濟主戰場就業創業,為區域內用人單位提供高質量人才服務。
本次招聘會以線上方式開展,截至目前,200余家單位報名參會,招聘1.6萬余人。
參會鏈接:
https://www.ncss.cn/student/jobfair/fairdetails.html?fairId=2Rs2tewZXV7AwYuVkBr4qp
掃碼參會
重點領域企業面向2023屆高校畢業生網絡招聘會
為推動高校畢業生服務國家戰略,引導畢業生到國家重點領域和新興領域就業,教育部高校學生司、教育部學生服務與素質發展中心于2022年12月20日至2023年1月20日舉辦“重點領域企業面向2023屆高校畢業生網絡招聘會”。
本次招聘會以線上方式開展,截至目前,招聘近1萬人。
參會鏈接:
https://www.ncss.cn/student/jobfair/fairdetails.html?fairId=3EW6uMKwKCMYmDGy6RxJmV
掃碼參會
來源 | 國家大學生就業服務平臺——24365校園招聘服務網站
來源:微言教育
載自教育部政務新媒體“微言教育”(微信號:jybxwb)
近日,國家大學生就業服務平臺——24365校園招聘服務再推出“2023屆全國高校畢業研究生專場網上招聘月”、“‘一帶一路’區域面向高校畢業生網上招聘會”、“重點領域企業面向2023屆高校畢業生網絡招聘會”等活動。更多信息,一起來看——
2023屆全國高校畢業研究生專場網上招聘月
2022年12月26日至2023年1月26日,教育部高校學生司、教育部學生服務與素質發展中心舉辦“2023屆全國高校畢業研究生專場網上招聘月”活動,為首批2023屆研究生畢業生提供就業服務。
本次招聘會以線上方式開展,截至目前,約500家單位報名參會,招聘近1萬人。
參會鏈接:
https://www.ncss.cn/student/jobfair/fairdetails.html?fairId=5QWAG31Fmnq9Neqv2ScxeK
掃碼參會
*請認真填寫需求信息,我們會在24小時內與您取得聯系。