1. 程式人生 > >python 視圖 (FBV、CBV ) 、Request 和Response對象 、路由系統

python 視圖 (FBV、CBV ) 、Request 和Response對象 、路由系統

機器 本質 path_info 解析過程 從數據 效果 blog html 可調用對象

一.FBV和CBV
1.基於函數的view,就叫FBV(Function Based View)
示例:
def add_book(request):
pub_obj=models.Publisher.objects.all() #從數據庫獲取全部出版社對象
if request.method==‘POST‘:
add_name=request.POST.get(‘book_name‘)
pub_id=request.POST.get(‘pub_id‘)
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect(‘/book/‘)
return render(request,‘add_book.html‘,{"pub_obj":pub_obj})
2.基於類的view,就叫CBV (Class Based View)
先在urls.py 中修改對應關系
如 : url(r‘^add_book‘,views.Addbook.as_view()),=======>url(r‘^add_book‘,view)
解析過程:
as_view是一個類方法 return view,
view 是一個函數 實例化一個對象; 封裝request屬性;return self.dispatch(self, request, *args, **kwargs)
dispatch是一個函數:
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed) 通過反射來操作對象屬性或方法
return handler(request, *args, **kwargs)
補充: 八種請求方法
http_method_names = [‘get‘, ‘post‘, ‘put‘, ‘patch‘, ‘delete‘, ‘head‘, ‘options‘, ‘trace‘]
views中寫類
from django.views import View
示例:
class Addbook(View):

def dispatch(self, request, *args, **kwargs):
# print("函數之前")
ret=super(Addbook, self).dispatch(request, *args, **kwargs)
# print("函數之後")
return ret

def get(self,request):
pub_obj = models.Publisher.objects.all()
return render(request,‘add_book.html‘,{"pub_obj":pub_obj})


def post(self,request):
add_name = request.POST.get(‘book_name‘)
pub_id=request.POST.get(‘pub_id‘)
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect(‘/book/‘)
二.加裝飾器
裝飾器
def wrapper(func):
def inner(*args,**kwargs):
start=time.time()
ret=func(*args,**kwargs)
print("執行時間為:{}".format(time.time()-start))
return ret
return inner
(一)FBV
@wrapper #加裝飾器
def add_book(request):
pub_obj=models.Publisher.objects.all() #從數據庫獲取全部出版社對象
if request.method==‘POST‘:
add_name=request.POST.get(‘book_name‘)
pub_id=request.POST.get(‘pub_id‘)
models.Book.objects.create(name=add_name,publisher_id=pub_id)
return redirect(‘/book/‘)
return render(request,‘add_book.html‘,{"pub_obj":pub_obj})
(二).CBV
首先導入:from django.utils.decorators import method_decorator
1.直接給類加裝飾器
@method_decorator(wrapper,name="post") #給post加裝飾器
@method_decorator(wrapper,name="get") #給get加裝飾器
class Addbook(View):
...
2.給dispatch加裝飾器(同時給get和post加裝飾器)
@method_decorator(wrapper) #同時給get和post加裝飾器
def dispatch(self, request, *args, **kwargs):
...
3.分別給get和post加裝飾器
a. @method_decorator(wrapper) #只給get方法加裝飾器
def get(self,request):
...
b. @method_decorator(wrapper) #只給post方法加裝飾器 可以同時存在
def post(self,request):
...
三.Request對象和Response對象
(一)Request 對象
當一個頁面被請求時,Django就會創建一個包含本次請求原信息的HttpRequest對象。
Django會將這個對象自動傳遞給響應的視圖函數,一般視圖函數約定俗成地使用 request 參數承接這個對象。
def test(request):
1.屬性
print(request,type(request)) #<WSGIRequest: GET ‘/test/‘> <class ‘django.core.handlers.wsgi.WSGIRequest‘>
print(request.method) #GET
print(request.GET) #<QueryDict: {}>
print(request.POST) #<QueryDict: {}>
print(request.path_info) #/test/JHHK (不包括域名,只有路徑)
print(request.body) #如果是get: b‘‘; 如果是post:b‘請求體‘
print(request.scheme) # 協議 http
print(request.encoding) #None表示提交的數據的編碼方式
# (如果為 None 則表示使用 DEFAULT_CHARSET 的設置,默認為 ‘utf-8‘)。
print(request.COOKIES) # 一個標準的Python 字典,包含所有的cookie。鍵和值都為字符串
print(request.FILES)
文件上傳 Request.FILES
views:
def upload(request):
if request.method==‘POST‘:
file_obj=request.FILES.get(‘upload‘)
print(file_obj.name)
with open(file_obj.name, ‘wb‘) as f:
for chunk in file_obj.chunks():
f.write(chunk)
return render(request,‘upload.html‘)
html:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="upload">
<button type="submit">提交</button>
</form>
# 註意: form中一定要寫 enctype="multipart/form-data"
補充:
一個類似於字典的對象,包含所有的上傳文件信息。
FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。
  註意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會
包含數據。否則,FILES 將為一個空的類似於字典的對象。
POST 請求中用到
file_obj = request.FILES.get(‘file_name‘)
2.方法
(1)print(request.get_host()) # 127.0.0.1:8000
根據從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)print(request.get_full_path()) # /test/123456789?asdafd=2143242&sdsdsf=sdsdfdsf(路徑+?+查詢內容)
返回 path,如果可以將加上查詢字符串。
  例如:"/music/bands/the_beatles/?print=true"
(3) print(request.is_secure()) #False
如果請求時是安全的,則返回True;即請求通是過 HTTPS 發起的。
(4)print(request.is_ajax()) #False
  如果請求是通過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是否是字符串‘XMLHttpRequest‘。
   大部分現代的 JavaScript 庫都會發送這個頭部。如果你編寫自己的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 可以工作。
   如果一個響應需要根據請求是否是通過AJAX 發起的,並且你正在使用某種形式的緩存例如Django 的 cache middleware,
你應該使用 vary_on_headers(‘HTTP_X_REQUESTED_WITH‘) 裝飾你的視圖以讓響應能夠正確地緩存
(5)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
(二)Response對象( HttpResponse , JsonResponse )
與由Django自動創建的HttpRequest對象相比,HttpResponse對象是我們的職責範圍了。我們寫的每個視圖都需要實例化,
填充和返回一個HttpResponse。
1.HttpResponse對象 HttpResponse類位於django.http模塊中。
屬性:
(1) print(HttpResponse.content) #<property object at 0x000001C0A0182638>響應內容
(2)print(HttpResponse.charset) #<property object at 0x000001C0A01648B8>響應內容編碼
(3)print(HttpResponse.status_code) #200響應內容的編碼
使用:
(1).傳遞字符串
from django.http import HttpResponse
response = HttpResponse("Here‘s the text of the Web page.")
(2).設置或刪除響應頭信息
response = HttpResponse()
response[‘Content-Type‘] = ‘text/html; charset=UTF-8‘
del response[‘Content-Type‘]
2.JsonResponse JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。
(1)from django.http import JsonResponse 導入
response = JsonResponse({‘foo‘: ‘bar‘})
print(response.content) # b‘{"foo": "bar"}‘
print(response.charset) # utf-8
print(esponse.status_code) #200
註意:
默認只能傳遞字典類型,如果要傳遞非字典類型需要設置一下safe關鍵字參數。
response = JsonResponse([1, 2, 3], safe=False)
四.Django shortcut functions
(一).render()
參數:
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‘})
原版:
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象
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 可以返回一個永久的重定向。
使用:
(1)傳遞一個具體的ORM對象(了解即可)
from django.shortcuts import redirect
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object)
(2)傳遞一個視圖的名稱
def my_view(request):
...
return redirect(‘some-view-name‘, foo=‘bar‘)
(3)傳遞要重定向到的一個具體的網址
def my_view(request):
...
return redirect(‘/some/url/‘)
(4)一個完整的網址
def my_view(request):
...
return redirect(‘http://example.com/‘)
補充:
臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來說是沒什麽區別的,它主要面向的是搜索引擎的機器人。

五.路由系統
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表。
(一).URLconf配置基本語法
from django.conf.urls import url
urlpatterns = [
url(正則表達式, views視圖,參數,別名),
]
(二)參數說明:
正則表達式:一個正則表達式字符串
views視圖:一個可調用對象,通常為一個視圖函數
參數:可選的要傳遞給視圖函數的默認參數(字典形式)
別名:一個可選的name參數
註意:
Django 2.0版本中的路由系統是下面的寫法
from django.urls import path,re_path
urlpatterns = [
path(‘articles/2003/‘, views.special_case_2003),
path(‘articles/<int:year>/‘, views.year_archive),
path(‘articles/<int:year>/<int:month>/‘, views.month_archive),
path(‘articles/<int:year>/<int:month>/<slug:slug>/‘, views.article_detail),
]
(三)正則詳解
1.基本配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r‘^articles/2003/$‘, views.special_case_2003),
url(r‘^articles/([0-9]{4})/$‘, views.year_archive),
url(r‘^articles/([0-9]{4})/([0-9]{2})/$‘, views.month_archive),
url(r‘^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$‘, views.article_detail),
]
2.註意事項
(1)urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則不再繼續。
(2)若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號(分組匹配)
(3)不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
(4)每個正則表達式前面的‘r‘ 是可選的但是建議加上.
3.補充說明
(1)是否開啟URL訪問地址後面不為/跳轉至帶有/的路徑的配置項
APPEND_SLASH=True
(2)Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數為 APPEND_SLASH = True。
其作用就是自動在網址結尾加‘/‘。

示例:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r‘^blog/$‘, views.blog),
]
效果 : 訪問 http://www.example.com/blog 時,默認將網址自動轉換為 http://www.example/com/blog/ 。
如果在settings.py中設置了 APPEND_SLASH=False,此時我們再請求 http://www.example.com/blog 時就會提示找不到頁面
(四)分組命名匹配
使用簡單的正則表達式分組匹配(通過圓括號)來捕獲URL中的值並以位置參數形式傳遞給視圖
同樣還可以使用分組命名匹配的正則表達式組來捕獲URL中的值並以關鍵字參數形式傳遞給視圖
在Python的正則表達式中,分組命名正則表達式組的語法是(?P<name>pattern),其中name是組的名稱,pattern是要匹配的模式。
通過(?P<name>pattern)捕獲的值作為關鍵字參數而不是位置參數傳遞給視圖函數
1.URLconf匹配的位置
URLconf 在請求的URL 上查找,將它當做一個普通的Python 字符串。不包括GET和POST參數以及域名。
例如,http://www.example.com/myapp/ 請求中,URLconf 將查找 /myapp/ 。
在http://www.example.com/myapp/?page=3 請求中,URLconf 仍將查找 /myapp/ 。
URLconf 不檢查請求的方法。換句話講,所有的請求方法 —— 同一個URL的POST、GET、HEAD等等 —— 都將路由到相同的函數。
2.捕獲的參數永遠都是字符串
每個在URLconf中捕獲的參數都作為一個普通的Python字符串傳遞給視圖,無論正則表達式使用的是什麽匹配方式
url(r‘^articles/(?P<year>[0-9]{4})/$‘, views.year_archive),
傳遞到視圖函數views.year_archive() 中的year參數永遠是一個字符串類型
3.視圖函數中指定默認值
# urls.py中
from django.conf.urls import url
from . import views
urlpatterns = [
url(r‘^page/$‘, views.page), 先匹配上它,沒有獲取到值,使用默認值
url(r‘^page/(?P<num>[0-9]{4})/$‘, views.page)
]
# views.py中,
可以為num指定默認值
def page(request,num=1):
print(num)
return HttpResponse(‘ok‘)
在上面的例子中,兩個URL模式指向相同的view - views.page - 但是第一個模式並沒有從URL中捕獲任何東西。
如果第一個模式匹配上了,page()函數將使用其默認參數num=“1”,如果第二個模式匹配,page()將使用正則表達式捕獲到的num值。
4.include其他的URLconfs
from django.conf.urls import include, url
urlpatterns = [
url(r‘^admin/‘, admin.site.urls),
url(r‘^blog/‘, include(‘blog.urls‘)), # 可以包含其他的URLconfs文件
]
(五)傳遞額外的參數給視圖函數
URLconfs 具有一個鉤子,讓你傳遞一個Python 字典作為額外的參數傳遞給視圖函數。
django.conf.urls.url() 可以接收一個可選的第三個參數,它是一個字典,表示想要傳遞給視圖函數的額外關鍵字參數。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r‘^blog/(?P<year>[0-9]{4})/$‘, views.year_archive, {‘foo‘: ‘bar‘}),
]
在這個例子中,對於/blog/2005/請求,Django 將調用views.year_archive(request, year=‘2005‘, foo=‘bar‘)。
當傳遞額外參數的字典中的參數和URL中捕獲值的命名關鍵字參數同名時,函數調用時將使用的是字典中的參數,而不是URL中捕獲的參數。
示例:
url(r‘^book/([0-9]{4})/([0-9]{2})/$‘, views.book,{‘foo‘:‘bar‘})
def book(request,*args,**kwargs):
#http://127.0.0.1:8000/book/2018/09/
# print(args) #(‘2018‘, ‘09‘)
# print(kwargs) # {‘foo‘: ‘bar‘} 額外加參數
return HttpResponse(‘ok‘)

python 視圖 (FBV、CBV ) 、Request 和Response對象 、路由系統