眾所周知,Django采用的是MTV框架模式,本文介紹的就是其中的V(View視圖),用戶在訪問某個url后,在回傳回應之前,通常需要進行一些業務邏輯上的處理,然后再將處理后的資料回傳給客戶端,在Django中,View視圖就是專門用來做這部分負責業務邏輯的功能的,同時,視圖也是Model模型與Template模板之間的橋梁,因為通常是通過模型從資料庫中獲取資料,經過視圖處理后再渲染到模板中,Django中視圖主要是以視圖函式和類視圖的方式來處理資料并回傳回應,本文也主要是介紹這兩種方式,
一、視圖函式
視圖函式通常寫在app的views.py檔案中,定義視圖函式時需要注意以下幾點:
- 函式的第一個引數必須是
request,這是一個WSGIRequest物件(參考本文后面關于此物件的介紹),Django會將用戶請求的相關資訊都封裝在這個物件中,我們可以直接從這個物件中獲取相關請求資訊, - 函式的回傳值必須是
HttpResponseBase物件或其子類物件,通常是HttpResponse物件,或通過render和redirect封裝一個HTML檔案后的物件,它們都是HttpResponseBase的子類物件, - 在
urlpatterns中配置url映射關系時,直接配置對應函式名即可,
1、創建一個普通的視圖函式
視圖函式的定義,除了第一個引數必須是request之外,如果url中定義了引數,那么在視圖函式中按順序定義同名的引數即可,
視圖函式的回傳值通常是一個HttpResponse物件(一個普通的回應物件),或者通過render和redirect方法回傳一個HTML模板,當然,如果想要給HTML模板中傳遞背景關系引數變數,可以使用render方法的context引數指定一個字典即可,
"""urls.py:配置url映射關系"""
from django.urls import path
from .views import book, book_list
# 直接使用視圖函式名稱來進行映射即可
urlpatterns = [
path('book/<book_id>/', book),
path('book/list/', book_list)
]
"""views.py:定義視圖函式"""
from django.http import HttpResponse
from django.shortcuts import render
# 如訪問“/book/”或“/book/3/”就會執行此視圖函式的內容
def book(request, book_id=1):
text = '您正在閱讀的圖書id是:{}'.format(book_id)
# 回傳一個普通的回應物件
return HttpResponse(text)
def book_list(request):
# 通過render函式回傳一個HTML模板,render的第一個引數也必須是request
return render(request, 'book_list.html')
2、WSGIRequest物件 - request引數
Django在接收到HTTP請求之后,會將HTTP請求攜帶的引數以及報文資訊封裝在一個WSGIRequest物件中,然后傳遞給視圖函式,也就是視圖函式的第一個引數request,對原始碼感興趣的話,可以列印下這個物件,WSGIRequest物件繼承自HttpRequest,原始碼位置在django.core.handlers.wsgi,
常用的屬性:
path:請求服務器的完整路徑,但不包含域名和引數,如http://127.0.0.1:8000/login/,path的值就是/login/,method:當前請求的HTTP方法,如GET、POST等,GET:一個django.http.request.QueryDict物件,操作方式類似字典,存盤了url中所有以?xxx=xxx格式上傳的引數,POST:一個django.http.request.QueryDict物件,操作方式類似字典,存盤了url中所有以POST方式上傳的引數,FILES:一個django.http.request.QueryDict物件,操作方式類似字典,存盤了所有上傳的檔案資訊,COOKIES:一個標準的Python字典,包含所有的cookie,鍵值對都是字串型別,session:一個類似字典的物件,用來操作服務器的session,META:一個標準的Python字典,存盤了客戶端發送上來的所有header資訊,字典中常用的項有:CONTENT_LENGTH:請求的正文的長度(字串型別),CONTENT_TYPE:請求的正文的MIME型別,HTTP_ACCEPT:回應可接收的Content-Type,HTTP_ACCEPT_ENCODING:回應可接收的編碼,HTTP_ACCEPT_LANGUAGE:回應可接收的語言,HTTP_POST:客戶端發送的HOST值,HTTP_REFERER:訪問當前頁面之前的上一個訪問頁面的url,QUERY_STRING:單個字串形式的查詢字串(未決議過的形式),REMOTE_ADDR:客戶端的IP地址,如果服務器使用了ngix做反向代理或者負載均衡,那么這個值回傳的就是127.0.0.1,此時可以使用HTTP_X_FORWARDED_FOR來獲取,如:
addr = request.META.get('HTTP_X_FORWARDED_FOR') if not addr: addr = request.META.get('REMOTE_ADDR')REMOTE_HOST:客戶端的主機名,REQUEST_METHOD:請求方法,SERVER_NAME:服務器域名,SERVER_PORT:服務器埠號(字串型別),
常用的方法:
is_secure:是否是采用的https協議,is_ajax:是否是采用ajax發送的請求,原理是判斷請求頭中是否存在X-Requested-With:XMLHttpRequest,get_host:服務器的域名,如果訪問時有加上埠號,則會回傳域名和埠號,get_full_path:回傳完整路徑,包含查詢字串,但不包含域名,get_raw_uri:獲取請求的完整url,
3、HttpResponse物件
視圖函式中如果不想直接回傳一個HTML模板,而是回傳一個普通的回應物件,或者想自己在回應物件中定義一些資料,就可以使用HttpResponse物件,
常用的屬性:
content:回傳的內容,status_code:回傳的HTTP回應狀態碼,content_type:回傳的資料的MIME型別,默認為text/html,瀏覽器會根據這個屬性來決定怎么顯示資料,如text/html則會決議這個字串,text/plain則會顯示為一個純文本,常用的Content-Type有:text/html:默認的型別,HTML檔案,text/plain:純文本,如果出現中文亂碼,可以在后面指定編碼方式,如text/plain;charset=utf-8,text/css:css檔案,text/javascript:js檔案,multipart/form-data:檔案提交,application/json:json傳輸,application/xml:xml檔案,
- 設定請求頭:可以使用字典的方式,如
HttpResponse()['X-Access-Token']='xxx',
常用的方法:
set_cookie:設定cookie資訊,delete_cookie:洗掉cookie資訊,write:HttpResponse可以當作一個類似檔案的物件,用此方法來寫入資料到資料體content中,
JsonResponse物件
這個物件在from django.http import JsonResponse中,用來回傳json物件,默認只能傳遞一個字典物件,如果傳遞的是非字典物件,則需要指定一個引數safe=False,
4、render/render_to_string/redirect
render:用來回傳一個HTML模板,可以通過from django.shortcuts import render直接匯入,第一個引數必須是request(即視圖函式的第一個引數request),第二個引數是模板路徑字串,如果要給模板傳遞背景關系變數引數,可以通過字典的方式傳遞給context引數,
render_to_string:是用來將一個HTML模板轉換為字串,在from django.template.loader import render_to_string中,因為回傳值是字串,所以是不能直接回傳的,而是需要傳入HttpResponse再回傳,但是瀏覽器中呈現的依然是原先HTML模板中的內容,
redirect:是用于url的重定向,可以通過from django.shortcuts import redirect直接匯入,redirect(to, *args, permanent=False, **kwargs)通常只需要傳入對應的url即可,也就是只需要指定to引數,permanent表示是否需要永久性重定向,默認為False,
from django.shortcuts import render
from django.http import HttpResponse
from django.template.loader import render_to_string
def index1(request):
# 先將模板轉為一個字串,到瀏覽器后又會反轉回來
# html_str = render_to_string('index.html')
# return HttpResponse(html_str)
# 直接傳入一個模板
return render(request, 'index.html')
def index2(request):
username = request.GET.get('username')
if username:
return HttpResponse('這是首頁!')
else:
return redirect('/login/')
5、限制請求方式
想要給視圖函式指定或限制請求方式,可以使用django.views.decorators.http中的裝飾器來實作,
常用的裝飾器:
require_http_methods:此裝飾器可以傳入一個請求method的串列,表示此視圖或url只能使用指定的請求method來訪問,require_GET:指定此視圖或url只能使用GET請求,相當于@require_http_methods(['GET']),require_POST:指定此視圖或url只能使用POST請求,相當于@require_http_methods(['POST']),require_safe:指定此視圖或url只能使用GET或HEAD請求,相當于@require_http_methods(['POST', 'HEAD']),
# 指定此視圖只能使用GET或POST請求
@require_http_methods(['GET', 'POST'])
def add_article(request):
# 獲取并判斷此次請求對應的請求method
if request.method == 'GET':
return render(request, 'add_article.html')
else:
# 如果是POST請求,則添加一條資料到Article模型(表)中
title = request.POST.get('title')
content = request.POST.get('content')
# create方法:添加一條資料并保存到資料庫
Article.objects.create(title=title, content=content)
return HttpResponse('success!')
二、類視圖
視圖的邏輯處理除了可以定義在函式中,還可以定義在類中,即類視圖,常用的類視圖有三種:View、TemplateView和ListView,
1、View類視圖
View類視圖是一個通用的類視圖,定義的類需要繼承自from django.views.generic import View,定義此類視圖時需要注意以下幾點:
- 如果想要指定允許的某種或多種請求方式,如
GET等,則定義對應名稱的方法即可,沒有定義的方法則表示不允許這種請求方式,如def get(self, request):...,定義方式和視圖函式是一樣的,比如有一個固定的request引數,回傳值必須是HttpResponseBase物件或其子類物件, - 在配置url映射時需要使用類的
as_view()方法,如path('detail/<book_id>/', BookDetailView.as_view()),當然,如果url中有指定引數,直接在類視圖中的對應方法中按順序添加同名的引數即可,也是和視圖函式的定義一樣的, - 如果用戶訪問了不支持的或沒有定義的請求方法,那么默認會先去查找并執行類中的
http_method_not_allowed(self, request, *args, **kwargs)方法,如果此方法沒有定義,則回傳一個405的錯誤,
from django.views.generic import View
class BookDetailView(View):
# 如訪問的url為:detail/<book_id>/
def get(self, request, book_id):
return HttpResponse('success!')
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse('不支持GET以外的請求方法!')
2、TemplateView類視圖
如果一個url訪問時并不需要專門的視圖來進行處理,而是想直接回傳一個固定寫好的HTML檔案,那么就可以使用TemplateView,也在from django.views.generic import TemplateView中,直接在配置url映射關系時使用它的as_view方法并指定template_name引數即可,
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path('about/', TemplateView.as_view(template_name='about.html'))
]
雖然不用定義專門的視圖來處理,但如果需要傳遞一些引數到模板中,那么就需要定義一個TemplateView的子類并重寫get_context_data方法,示例如下:
from django.views.generic import TemplateView
class AboutView(TemplateView):
# 指定HTML模板路徑
template_name = 'about.html'
# 定義get_context_data方法,并回傳一個字典,這個字典會用作模板的背景關系物件
def get_context_data(self, **kwargs):
context = {'username': 'zhangsan'}
return context
# url映射時就不需要再傳遞模板路徑了
# urlpatterns = [
# path('about/', AboutView.as_view())
# ]
3、ListView
如果頁面中需要用到分頁的功能,那么就可以考慮使用ListView視圖了,它是專門用作分頁功能的視圖的,相比于普通的視圖實作,它會非常的方便快捷,也是在from django.views.generic import ListView中,使用時需要定義一個它的子類并配置相關屬性即可,
常用的屬性和方法有:
model:頁面中分頁資料需要用到的ORM模型類,template_name:指定回傳的HTML模板,paginate_by:指定這個頁面中展示的資料條數,context_object_name:指定這個模板中分頁資料需要用到的背景關系引數名稱,ordering:指定資料的排列方式,page_kwarg:訪問分頁中第幾頁時用到的查詢字串引數,默認為page,get_context_data():獲取背景關系中的資料,如果需要額外添加資料到背景關系中,可以重寫這個方法,因為ListView中此方法本身就實作了許多功能,所以定義此視圖時通常需要先使用super獲取父類的結果,再在此結果中添加自己額外的背景關系資料,get_queryset():指定分頁界面中展示所需的資料,默認為ORM模型類對應的全部資料,相當于xxx.objects.all(),如果不想回傳所有資料,也可以使用filter等方法回傳一個QuerySet物件,如xxx.objects.filter(id__lte=50)只回傳id大于等于50的資料,
示例:訪問/article/list/時就會默認顯示前paginate_by條資料,訪問/article/list/?p=3時就顯示第paginate_by乘以3組資料,url中的p是由page_kwargs指定的,也可以不改,就使用默認的page,
"""views.py視圖檔案代碼片段"""
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article # ORM模型類
template_name = 'article_list.html' # 回應的HTML模板
context_object_name = 'articles' # 模板中分頁資料用到的背景關系引數名稱
paginate_by = 10 # 每頁顯示的資料條數
ordering = 'create_time' # 指定排序欄位
page_kwargs = 'p' # 訪問指定頁數時的查詢字串引數名稱
"""urls.py映射檔案代碼片段"""
from django.urls import path
from .views import ArticleListView
urlpatterns = [
path('article/list/', ArticleListView.as_view())
]
<!-- article_list.html代碼片段 -->
<ul>
<!-- 此處的articles就是視圖中context_object_name屬性指定的值 -->
{% for article in articles %}
<li>{{ article.title }}</li>
{% endfor %}
</ul>
Paginator類和Page類
在ListView視圖中默認回傳的背景關系引數中有兩個常用的物件paginator和page_obj,對應于django.core.paginator.Paginator類和django.core.paginator.Page類,在HTML模板中會經常用到這兩個物件的屬性和方法,
Paginator常用屬性和方法:
count:總的資料條數,num_pages:總共有多少頁,page_range:比如總共有10頁,那么回傳的就是range(1, 11),
Page常用屬性和方法:
has_next:是否還有下一頁,has_previous:是否還有上一頁,next_page_number:下一頁的頁碼,previous_page_number:上一頁的頁碼,number:當前頁的頁碼,start_index:當前頁的第一條資料的索引值,end_index:當前頁的最后一條資料的索引值,
4、在類視圖中使用裝飾器
在Django中如果想要給類方法添加裝飾器,Django提供了一更加安全的使用方式,即使用from django.utls.decorators import method_decorator裝飾器,使用時將自定義的裝飾器函式傳入,再去裝飾對應的類或者方法即可,
訪問url時,在進入對應類視圖的方法之前,其實會先執行類視圖的dispatch方法,所以如果想給類視圖使用裝飾器的話,可以直接裝飾dispatch方法,裝飾的方式也有兩種,一種方式是直接在這個方法上使用對應的裝飾器,另一種方式則在類定義上使用對應的裝飾器,推薦使用后者,具體見示例代碼,
from django.views.generic import View
from django.utls.decorators import method_decorator
# my_decorator為自定義的裝飾器,將它放入method_decorator會更加安全
# 方式一:推薦采用這種直接裝飾類的方式,傳入自定義的裝飾器和要裝飾的方法即可
@method_decorator(my_decorator, name='dispatch')
class BookDetailView(View):
def get(self, request, book_id):
return HttpResponse('success!')
# 方式二:通過重寫dispatch的方式
@method_decorator(my_decorator)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
注:本文為學習筆記,發現錯誤歡迎指出,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/176525.html
標籤:其他
上一篇:Django筆記:下載csv檔案
下一篇:Django筆記:下載csv檔案
