4.檢視
1.檢視引數
# urls.py
urlpatterns = [
path('login/', account.login, name="login"),
path('auth/', order.auth, name='auth'),
]
# views.py
from django.shortcuts import HttpResponse
def login(request):
return HttpResponse("login")
Request 是什麼?
requests是一個物件,存放了瀏覽器給咱們發過來的所有內容,所以含有:
- 請求相關所有的資料: 當前訪問的url、請求方式、...
- django額外新增的資料
1.1 request 方法
1.1.1 request.path_info
- 只能獲取到路由地址,無法獲取到引數
- 它保留了URL路徑中的任何編碼、特殊字元或斜槓等資訊。
http://localhost:8000/api/login/
def login(request):
print(request.path_info) # /api/login/
return HttpResponse("Hello, world. You're at the")
1.1.2 request.path
- 只能獲取到路由地址,無法獲取到引數
- 它包含在域名之後,在任何查詢引數之前
http://localhost:8000/api/login/
def login(request):
print(request.path) # /api/login/
return HttpResponse("Hello, world. You're at the")
1.1.3 request.GET
- 該屬性包含了請求中透過GET方法傳送的所有引數。
- 這些引數通常會附加在URL之後,以問號分隔。
- 您可以使用引數的名字作為鍵來訪問單個引數,例如
request.GET['page']
也可以直接.get()獲取
http://localhost:8000/api/login/?xxx=serein&age=999
def login(request):
print(request.GET) # <QueryDict: {'xxx': ['serein'], 'age': ['999']}>
print(request.GET.get('xxx')) # serein
print(request.GET['age']) # 999
return HttpResponse("Hello, world. You're at the")
1.1.4 request.POST
request.POST
:該屬性是一個類似字典的物件,包含了請求中透過POST方法傳送的所有引數。- 這些引數通常是透過HTML表單傳送的。
- 您可以使用引數的名字作為鍵來訪問單個引數,例如
request.POST['username']
,也可以直接.get()獲取
1.1.5 request.method
- 返回客戶端用於發起請求的HTTP方法,比如'GET','POST'等
http://localhost:8000/api/login/?xxx=serein&age=999
def login(request):
print(request.method) # GET
return HttpResponse("Hello, world. You're at the")
1.1.6 request.body
- 獲取POST請求的請求體
- 獲取到的資料是原始格式,資料格式什麼樣根據content-type決定
def login(request):
print(request.body) # GET
return HttpResponse("Hello, world. You're at the")
# b'{"code":"083Sjmll2yla694F3bll2DguCM2SjmlG","unionId":"oP6QCsyT_9bk1dfSaVf0GEV5Y-yE"}' b'v1=123&v2=456'
# 請求體+請求頭 資料格式 b'v1=123&v2=456' content-type格式:content-type:application/x-www-form-urlencoded
# 可以這麼取值
print(request.POST)
print(request.POST.get("v1"))
print(request.POST.get("v2"))
1.1.7 request.FILES
request.FILES
:該屬性是一個類似字典的物件,包含了請求中透過檔案上傳元件傳送的所有檔案。- 當表單中包含檔案上傳欄位時,透過
request.FILES
可以訪問上傳的檔案。 - 您可以使用檔案的名字作為鍵來訪問單個檔案,例如
request.FILES['file']
,也可以.get()獲取 - content-type格式, multipart/form-data
file_obj = request.FILES.get("avatar")
print(file_obj, type(file_obj))
# 165917-16953731571c11.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
# 獲取檔名
file_name = file_obj.name
print(file_name, type(file_name))
1.1.8 request.get_full_path()
- 即能獲取到路由地址又能獲取到完整的路由地址後面的引數
request.get_full_path()
:該方法返回請求URL的完整路徑,包括路徑部分和任何查詢引數。- 當您需要將完整URL作為字串使用時,這個方法非常有用。
def login(request):
print(request.get_full_path()) # 獲取到GET請求的完整路由地址和引數
# /app01/login/?username=111&password=111
return render(request, "login.html")
1.1.9 request.header
- 獲取請求的請求頭
1.1.10 request.COOKIES
- 請求頭有個特殊的cookie,
- 可以直接request.COOKIES獲取
1.1.11 request.resolver_match
- 獲取requests中其他值
2. 返回json資料
- 服務端返回json資料
- JsonResponse模組
- from django.http import JsonResponse
# 第一種方式:json模組序列化
def index(request):
data = {"username": "serein", 'password': '1234'}
# 先用json序列化
data = json.dumps(data)
# 三板斧物件
response = HttpResponse(data)
return response
# 第二種辦法
from django.http import JsonResponse
def index(request):
data = {"username": "serein", 'password': '1234'}
response = JsonResponse(data)
return response
3. FBV和CBV
3.1 FBV和CBV
- funtion 函式和路由之間的對映關係
- class 類和路由之間的對映關係
3.2 CBV格式
- 檢視層
# views.py
from django.shortcuts import render, HttpResponse
# 匯入view
from django.views import View
# 重寫類,繼承view
class LoginView(View):
# get請求
def get(self, request):
pass
return HttpResponse("111")
# post請求
def post(self, request):
return HttpResponse("111")
- 路由層
from django.urls import path
from apps.api.views import LoginView
urlpatterns = [
path('login/', LoginView.as_view())
3.3 CBV原始碼剖析
class View:
# http_method_names : 存放了我們常用的請求方式
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
# 繫結給類的函式,繫結方法
@classonlymethod
def as_view(cls, **initkwargs):
# **initkwargs : 可變長關鍵字引數
for key in initkwargs:
# print(f"key :>>>> {key}") # key :>>>> pattern_name
# 可變長關鍵字引數中的每一個鍵值對
# 我們自己寫檢視類中沒有定義過 http_method_names ,只能從父類 View 裡面找
if key in cls.http_method_names:
#
raise TypeError(
'The method name %s is not accepted as a keyword argument '
'to %s().' % (key, cls.__name__)
)
# hasattr : 獲取到當前物件中的屬性
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))
# 上面都沒有報錯,走到了 view 函式里面
def view(request, *args, **kwargs):
# 獲取到當前類的物件 這個 cls ---> Register
self = cls(**initkwargs)
# 獲取到了一個 當前的get方法
self.setup(request, *args, **kwargs)
# 必須接受一個位置引數叫request
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
# 觸發了 dispatch 方法 ---> 獲取到了get函式的返回值
# render
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
def setup(self, request, *args, **kwargs):
# self : 當前Register例項化出來的物件
# 有GET方法 並且 沒有 head屬性
if hasattr(self, 'get') and not hasattr(self, 'head'):
# self.head 變成了我自己寫的 GET 方法
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 走到了dispatch方法
def dispatch(self, request, *args, **kwargs):
# request.method.lower() :當前請求方法轉全小寫
if request.method.lower() in self.http_method_names:
# 獲取到了當前物件中的get方法的函式記憶體地址
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# get方法的函式記憶體地址呼叫
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 HttpResponseNotAllowed(self._allowed_methods())
def options(self, request, *args, **kwargs):
"""Handle responding to requests for the OPTIONS HTTP verb."""
response = HttpResponse()
response.headers['Allow'] = ', '.join(self._allowed_methods())
response.headers['Content-Length'] = '0'
return response
def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
- 當我們啟動Django專案時
- 會自動觸發路由中的方法,呼叫 as_view 方法並自執行
- 在執行後我們檢視 as_view 方法的原始碼 發現
- 在依次給我們的物件賦值後,最終返回了一個自執行的 dispatch 方法
- 於是我們又去檢視了 dispatch 方法
- 在 dispatch 內部 ,先是將請求方式轉換並進行校驗
- 然後開始校驗需要呼叫的方法的呼叫位置,校驗成功並拿到需要執行的方法執行
- 在自己寫的類中如果有相關的方法,會首先呼叫我們重寫的類方法,並返回執行結果
- 如果自己的類裡面沒有該方法 會去自己的父類中呼叫 父類的方法
- 如果父類 以及 基類 都找不到則報錯,丟擲異常
- 如果自己的類裡面沒有該方法 會去自己的父類中呼叫 父類的方法
3.3 給CBV和FBV加裝飾器
3.3.1 給FBV加裝飾器
- 只需要將自己定義的裝飾器放在指定的檢視函式上面用語法糖
def timer(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
print(f"總耗時 :>>>>> {time.time() - start_time} s ")
return res
return inner
@timer
def register(request):
time.sleep(2)
return HttpResponse("ok")
3.3.2 給CBV加裝飾器
from django.utils.decorators import method_decorator
class Login(View):
# 第一種方式
# @timer
# def get(self, request, *args, **kwargs):
# time.sleep(2)
# return HttpResponse("login")
# 第二種方式 : 藉助Django內建的公共函式 method_decorator
# @method_decorator(timer)
# def get(self, request, *args, **kwargs):
# time.sleep(2)
# return HttpResponse("login")
# 第三種方式:重寫 dispatch 方法做攔截
def get(self, request, *args, **kwargs):
time.sleep(2)
return HttpResponse("login")
def dispatch(self, request, *args, **kwargs):
start_time = time.time()
# 可以什麼都不寫
# obj = super().dispatch(request, *args, **kwargs)
# 可以放自己的類名和自己的物件 self
obj = super(Login, self).dispatch(request, *args, **kwargs)
print(f"總耗時 :>>>> {time.time() - start_time} s ")
return obj
# 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)