目錄
- 一、web應用模式
- 二、API介面
- 三、介面測驗工具postman
- postman介紹
- postman下載與使用
- 四、如何在瀏覽器中測驗
- 五、restful規范(重要)
- 六、序列化反序列化
- 七、基于Django原生撰寫五個介面
- 八、drf介紹和快速使用
- 概念
- 特點(了解一下)
- 安裝
- 使用drf撰寫五個介面
- 九、drf之APIView原始碼分析
- 基于APIView寫五個介面
- CBV原始碼分析
- APIView執行流程-原始碼分析
一、web應用模式
- Django框架就是一種web框架,專門用來寫web專案,之前學的,寫的BBS專案,圖書管理系統,用的都是前后端混合開發
-后端人員,寫后端,也要寫【模板語法】---》xx.html的python代碼
-全堆疊開發-->前后端混合時代,比較多
- 從今天開始,學的是前后端分離
-后端人員,一點前端都不需要動,只需要寫介面即可
-全堆疊開發---》web后端,前端框架(vue,react)
在開發Web應用中,有兩種應用模式:
1.前后端不分離客戶端看到的內容和所有界面效果都是由服務端提供出來的


2.前后端分離【把前端的界面效果(html,css,js分離到另一個服務端,python服務端只需要回傳資料即可)】
前端形成一個獨立的網站,服務端構成一個獨立的網站


二、API介面
為了在團隊內部形成共識、防止個人習慣差異引起的混亂,我們需要找到一種大家都覺得很好的介面實作規范,而且這種規范能夠讓后端寫的介面,用途一目了然,減少雙方之間的合作成本【前后端合作】
API概念
API:應用程式介面(API:Application Program Interface)
應用程式介面(API:application programming interface)是一組定義、程式及協議的集合,通過 API 介面實作計算機軟體之間的相互通信,API 的一個主要功能是提供通用功能集,程式員通過使用 API 函式開發應用程式,從而可以避免撰寫無用程式,以減輕編程任務
簡單來說就是通過網路,規定了前后端資訊互動規定的URL鏈接,也就是前后端資訊互動的媒介
http://127.0.0.1/books/
點贊,點踩 就是API介面
-
URL:長得像回傳資料的URL鏈接
https://api.map.baidu.com/place/v2/search -
請求方式:
get、post、put、patch、delete
采用get方式請求上方介面 -
請求引數:
json或xml格式的key-value型別資料
ak:6E823f587c95f0148c19993539b99295
region:上海
query:肯德基
output:json
-早些年 前后端互動使用xml格式----》ajax:異步JavaScript和XML
-后來,隨著json格式的出現,成了主流,直到現在
-以后:一定會出現,比json更高效的互動格式,更安全
- 回應結果:json或xml格式的資料
- 上方請求引數的output引數值決定了回應資料的格式
- 資料
# xml格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=xml
'''中文會變成上面的樣式,上下兩個url是一樣的意思'''
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=上海&query=肯德基&output=xml
#json格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=json
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=上海&query=肯德基&output=json
'''下方是回傳的值'''
{
"status":0,
"message":"ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"location":{
"lat":31.415354,
"lng":121.357339
},
"address":"月羅路2380號",
"province":"上海市",
"city":"上海市",
"area":"寶山區",
"street_id":"339ed41ae1d6dc320a5cb37c",
"telephone":"(021)56761006",
"detail":1,
"uid":"339ed41ae1d6dc320a5cb37c"
}
...
]
}
三、介面測驗工具postman
postman介紹
作為后端,寫好了介面,我們自己要測驗通過,再給別人用,
而后端測驗人員需要測驗API介面的時候,總不可能在瀏覽器里面試用吧,所以有了專業的介面測驗工具Postman
-瀏覽器只能發送get請求,不能自動發送post,delete請求
-postman---》開源軟體,只是谷歌瀏覽器的插件,越做好好,后來可以按裝到作業系統上,再后來,收費
-postwoman
-很多很多其他的,不同公司用的也可能不一樣,你只需要明白一個點,這個工具只是用來發送http請求
postman下載與使用
1、官方下載
https://www.postman.com/downloads/?utm_source=postman-home----》Postman-win64-Setup.exe
2、安裝時,雙擊即可,馬上就會出現下圖界面

3、使用講解
打開一個新的測驗頁面后界面如下,回傳資料的視窗在沒有發送請求之前是空的,

點擊界面中間的Body,可以選擇發送請求的方式,需要注意在使用form-data請求方式,即用form表單傳輸檔案的時候,需要手動選擇傳輸的資料型別


這里回傳的結果

四、如何在瀏覽器中測驗
我們需要再settings.py檔案中注冊rest_framework才能在瀏覽器中進行介面測驗
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'rest_framework',
]
五、restful規范(重要)
概念
REST全稱是Representational State Transfer,中文意思是表述(編者注:通常譯為表征性狀態轉移), 它首次出現在2000年Roy Fielding的博士論文中
RESTful是一種定義Web API介面的設計風格,尤其適用于前后端分離的應用模式中
這種風格的理念認為后端開發任務就是提供資料的,對外提供的是資料資源的訪問介面,所以在定義介面時,客戶端訪問的URL路徑就表示這種要操作的資料資源
事實上,我們可以使用任何一個框架都可以實作符合restful規范的API介面
十條規范
-1 資料的安全保障,通常使用https(http+ssl/tsl)協議
-url鏈接一般都采用https協議進行傳輸
-采用https協議,可以提高資料互動程序中的安全性
-2 介面中帶api標識
-https://api.lqz.com/books(可以寫在域名中)
-https://www.lqz.com/api/books(也可以寫在路由中) 咱們用這個
-3 多版本共存,路徑中帶版本資訊
-https://api.lqz.com/v1/login
-https://api.lqz.com/v2/login
-https://www.lqz.com/api/v1/login
-https://www.lqz.com/api/v2/login
-4 資料即是資源,均使用名詞,盡量不出現動詞(最核心的)
-介面一般都是用于完成前后臺資料的互動,互動的資料我們稱之為資源
-介面形式如下
https://api.baidu.com/users
https://api.baidu.com/books
-特殊的介面可以出現動詞,因為這些介面一般沒有一個明確的資源,或是動詞就是介面的核心含義、 https://api.baidu.com/login
-5 資源操作由請求方式決定(method)
-操作資源一般都會涉及到增刪改查,我們提供請求方式來標識增刪改查動作
https://api.baidu.com/books - get請求:獲取所有書(獲取所有)
https://api.baidu.com/books/1 - get請求:獲取主鍵為1的書(獲取一條)
https://api.baidu.com/books - post請求:新增一本書書(新增一條)
https://api.baidu.com/books/1 - put請求:修改主鍵為1的書(整體修改一條)
https://api.baidu.com/books/1 - patch請求:修改主鍵為1的書(區域修改一條)
'ps:patch用的不多,一般用put即可'
https://api.baidu.com/books/1 - delete請求:洗掉主鍵為1的書(洗掉一條)
-6 在請求地址中帶過濾條件
https://api.example.com/v1/zoos?limit=10:指定回傳記錄的數量
https://api.example.com/v1/zoos?offset=10:指定回傳記錄的開始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄數
https://api.example.com/v1/zoos?sortby=name&order=asc:指定回傳結果按照哪個屬性排序,以及排序順序
https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條件
-7 回應中狀態碼:兩套
-http回應狀態碼:1xx:請求正在處理,2xx:成功回應,3xx:重定向,4xx:客戶端錯誤,5xx:服務端錯誤
'常見的需要記住'
回應狀態碼2XX 200:常規請求 201:創建成功
回應狀態碼3XX 301:永久重定向 302:暫時重定向
回應狀態碼4XX 403:請求無權限 404:請求路徑不存在 405:請求方法不存在
回應狀態碼5XX 500:服務器例外
-https://blog.csdn.net/li_chunlong/article/details/120787872
-公司內部規定的回應狀態碼,放在回應體中
{code:0} 咱們后期一般使用100 101 102這種
-8 回傳資料中帶錯誤資訊
{
code:0
msg: "ok/用戶名錯誤"
}
-9 回傳的結果應該符合以下規范---》好多公司不遵循這個
GET 獲取所有資料:回傳資源物件的串列(陣列)[{name:紅樓夢,price:99},{name:紅樓夢,price:99},{name:紅樓夢,price:99}]
GET 單個物件:回傳單個資源物件:{name:紅樓夢,price:99}
POST 新增物件:回傳新生成的資源物件:{name:西游記,price:99}
PUT 修改物件:回傳完整的資源物件 :{name:西游記,price:100}
DELETE 洗掉:回傳一個空檔案
-10 回應資料中帶連接
# Hypermedia API,RESTful API最好做到Hypermedia,即回傳結果中提供鏈接,連向其他API方法,使得用戶不查檔案,也知道下一步應該做什么
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"img": "https://image.baidu.com/kfc/001.png"
}
...
]
}
比較好的介面回傳
# 回應資料要有狀態碼、狀態資訊以及資料本身
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(羅餐廳)",
"location":{
"lat":31.415354,
"lng":121.357339
},
"address":"月羅路2380號",
"province":"上海市",
"city":"上海市",
"area":"寶山區",
"street_id":"339ed41ae1d6dc320a5cb37c",
"telephone":"(021)56761006",
"detail":1,
"uid":"339ed41ae1d6dc320a5cb37c"
}
...
]
}
六、序列化反序列化
api介面開發,最核心最常見的一個程序就是序列化,所謂序列化就是把【資料轉換格式】,序列化可以分兩個階段:
序列化: 把我們識別的資料轉換成指定的格式提供給別人
-字典,串列------》json格式存到檔案中了
-例如:我們在django中獲取到的資料默認是模型物件,但是模型物件資料無法直接提供給前端或別的平臺使用,所以我們需要把資料進行序列化,變成字串或者json資料,提供給別人
-read
反序列化:把別人提供的資料轉換/還原成我們需要的格式
-例如:前端js提供過來的json資料,對于python而言就是字串,我們需要進行反序列化換成模型類物件,這樣我們才能把資料保存到資料庫中,
-write
七、基于Django原生撰寫五個介面
# 以后寫的介面,基本上都是五個介面及其變形
-查詢所有
-查詢單個
-新增一個
-修改一個
-洗掉一個
# 基于books單表為例,寫五個介面
-創建book表
-表遷移
-錄入假資料:直接錄,后臺管理錄
-寫查詢所有介面----》遵循restful規范,使用cbv
-新增一條資料-----》
-查詢一條
-修改一條:put提交的資料,不能從request.POST中取
-洗掉一條
models.py
form django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/books/', views.BookView.as_view()),
path('api/v1/books/<int:pk>/', views.BookDetailView.as_view()),
]
views.py
from django.shortcuts import render,HttpResponse,redirect
from django.http import JsonResponse
from .models import Book # 相對匯入
from django.views import View
import json
class BookView(View):
# 查詢所有
def get(self, request):
# 查詢出所有的圖書,queryset物件,不能直接給前端
books = Book.objects.all()
# 轉成json格式,給前端
# 把quer物件轉成串列,然后再使用JsonResponse
book_list = []
for book in books:
book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
# 擴展做了解
# return HtpResponse(json.dumps(book_list, ensure_ascii=False)) # 指定ensure_ascii為false,前端就顯示中文了
return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii': False}) # JsonRsponse只能放字典或串列
# 薪增一個(只能使用urlencoded或form-data編碼,使用json形式編碼不行,因為json格式編碼提交的資料,不能從request.POST中取,從body中)
def post(self, request):
# 取出前端傳入的資料
name = request.POST.get('name')
price = reqeust.POST.get('price')
publish = request.POST.get('publish')
# 存到資料庫中
book = Book.objects.create(name=name, price=price, publish=publish)
# 回傳新增的物件字典
return JsonResponse({'name': book.name, 'price': book.price, 'publish': book.publish})
class BookDetailView(View):
def get(self, request, pk):
book = Book.objectsfilter(pk=pk).first()
# book模型物件轉成字典,使用JsonResponse回傳
return JsonResponse({'id': book.id, 'name': book.name, 'price': book.price, 'publish': book.publish})
def put(self, request, pk): # request.POST只能取post提交的urlencoded或form-data編碼資料,put提交的取不到
# 查到要改的
book = Book.objects.filter(pk=pk).first()
# 取出前端傳入的資料,修改完,保存----》存在問題,因為put提交的取不到
# book.name = request.POST.get('name')
# book.price = request.POST.get('price')
# book.publish = request.POST.get('publish')
# book.save()
# 前端使用json格式提交,自己保存
print(request.body)
book_dict=json.loads(request.body)
book.name = book_dict.get('name')
book.price = book_dict.get('price')
book_publish = book_dict.get('publish')
book.save()
return JsonResponse({'id': book.id, 'name': book.name, 'price': book.price, 'publish': book.publish})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return JsonResponse(data=https://www.cnblogs.com/wurenyao/archive/2023/05/17/{})
八、drf介紹和快速使用
概念
核心思想: 縮減撰寫api介面的代碼
Django REST framework是一個建立在Django基礎之上的Web 應用開發框架,可以快速的開發REST API介面應用,在REST framework中,提供了序列化器Serialzier的定義,可以幫助我們簡化序列化與反序列化的程序,不僅如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的撰寫作業,REST framework還提供了認證、權限、限流、過濾、分頁、介面檔案等功能支持,REST framework提供了一個API 的Web可視化界面來方便查看測驗介面,
官方檔案:https://www.django-rest-framework.org/
github: https://github.com/encode/django-rest-framework/tree/master
特點(了解一下)
- 提供了定義序列化器Serializer的方法,可以快速根據 Django ORM 或者其它庫自動序列化/反序列化;
- 提供了豐富的類視圖、Mixin擴展類,簡化視圖的撰寫;
- 豐富的定制層級:函式視圖、類視圖、視圖集合到自動生成 API,滿足各種需要;
- 多種身份認證和權限認證方式的支持;[jwt]
- 內置了限流系統;
- 直觀的 API web 界面;
- 可擴展性,插件豐富
安裝
# djangorestframework: drf 幫助我們快速的實作符合restful規范的介面
# django 最新 4.x ,一般都會用最新版的上一版3.x
# drf最新支持到djagno 3.x ,最新不支持2.x
# 安裝drf
pip3 install djangorestframework -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/
# 由于你是django2.x 它發現它不支持,它會自動寫在dajgno,安裝最新的django 4.x
使用drf撰寫五個介面
注意:url的末尾必須要寫斜杠符號,不然會報錯
urls.py
from app01.views import BookView
from rest_framework.routers import SimpleRouter
router = SimpleRouter
router = SimpleRouter()
router.register('books', BookView, 'books')
urlpatterns = [
path('admin/', admin.site.urls),
]
# 兩個串列相加 [1,2,4] + [6,7,8]=
urlpatterns += router.urls
views.py
form .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
serializer.py
from rest_framework import serializers
form .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
九、drf之APIView原始碼分析
基于APIView寫五個介面
urls.py
urlpatterns = [
path('books/', BookView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
]
views.py
form rest_framework.views import APIView # APIView繼承了Django原來的View
from .serializer import BookSerializer
from rest_framework.response import Response
class BookView(APIView):
# 查詢所有
def get(self, request):
book_list = Book.objects.all()
# drf提供了序列化類
ser = BookSerializer(instance=book_list, many=True) # 序列化
return Response({'code': 100, 'msg': '成功', 'result': ser.data})
def post(self, request):
ser = BookSerializer(data=https://www.cnblogs.com/wurenyao/archive/2023/05/17/request.data) # 反序列化
if ser.is_valid(): # 資料校驗---》有些不合法禁止
ser.save() # 保存到資料庫中
return Response({'code': 100, 'msg': '成功'})
class BookDetailView(APIView):
# # 查詢單條
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book,many=False) # 序列化
return Response({'code': 100, 'msg': '成功', 'result': ser.data})
# 修改一條
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book,data=https://www.cnblogs.com/wurenyao/archive/2023/05/17/request.data) # 反序列化
if ser.is_valid(): # 資料校驗---》有些不合法禁止
ser.save() # 保存到資料庫中
return Response({'code': 100, 'msg': '成功'})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '洗掉成功'})
serializer.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
CBV原始碼分析
# cbv寫法:
1 視圖中寫視圖類,繼承View,寫跟請求方式同名的方法
class BookView(View):
def get(self,request):
return 四件套
2 在路徑用寫
path('books/', BookView.as_view())
# 如上寫法,為什么能夠執行
# 前置條件:前端請求,一旦路徑匹配成功,就會執行 BookView.as_view()(request傳入,)
# 入口在 BookView.as_view()--->執行結果---》View中有個as_view類的系結方法
@classmethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
res=self.dispatch(request, *args, **kwargs)
return res
return view
# 執行結果是view 的記憶體地址: 請求來了,執行view(request)
path('books/', view)
# 執行 View類中的as_view方法中的內層的view函式,路由匹配成功,本質是在執行
self.dispatch(request, *args, **kwargs)
# self是誰的物件?BookView的物件
# 去BookView中dispatch,找不到,去父類,View中找到了
# View這個類的dispatch
def dispatch(self, request, *args, **kwargs):
# request.method.lower() 如果是get請求, ‘get’ 在這個串列里面
if request.method.lower() in self.http_method_names:
# handler=getattr(BookView的物件,'get')
# handler就是BookView類中的get方法
handler = getattr(self, request.method.lower())
else:
handler = self.http_method_not_allowed
# 執行 BookView類中的get方法 (request)
return handler(request, *args, **kwargs)
# 最終本質跟寫fbv的執行流程一樣
# 最終結論:什么請求方式,就會執行視圖類中的什么方法
-本身請求來了,匹配成功,會執行view(request)
def view(request, *args, **kwargs):
return self.dispatch(request, *args, **kwargs)
-self.dispatch View類的方法
def dispatch(self, request, *args, **kwargs):
# request.method請求方式轉成小寫,必須在串列中才能往下走
if request.method.lower() in self.http_method_names:
# 反射,去self【視圖類的物件:BookView】,去通過get字串,反射出屬性或方法
# BookView的get方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# BookView的get方法,加括號,傳入request
return hander(request, *args, **kwargs)
APIView執行流程-原始碼分析
urls.py
path('books/', views.BookView.as_view()),---》請求來了,執行views.BookView.as_view()()--->現在as_view是APIView的as_view(因為我們把父類從View換成了APIView)
我們點進原始碼查看可以發現APIView其實繼承了View
class APIView(View):
往下查找as_view()的代碼
# APIView的as_view方法:view還是原來的view,但是以后再也沒有csrf認證了
@classmethod
def as_view(cls, **initkwargs):
# 呼叫父類的as_view,父類是Django原生view
# 把Django原生view的as_view方法中的閉包函式view拿出來了
view = super().as_view(**initkwargs)
# csrf_exempt 排除所有csrf的認證
# 相當于再所有的方法上面加了這個裝飾器
return csrf_exempt(view)
'從他內部的view我們可以看到他是用派生方法呼叫父類View中的as_view因此我們說view還是原來的view,但是回傳的結果是csrf_exempt(view),回顧裝飾器的知識,我們可以知道雖然把裝飾器寫成了語法糖,但是在運行的時候其實就是把被裝飾的函式名稱傳進來當引數運行,因此這里就是取消了csrf認證的作用'
# 路由匹配成功,執行的其實就是csrf_exempt(view)(request)--->而這個view就是View的as_view中的閉包函式view---》然后執行self.dispatch--->self是視圖類的物件---》BookView產生的物件---》這時候會執行self.dispatch,根據名稱的查找順序他會查找到APIView的dispatch:
def dispatch(self, request, *args, **kwargs):
# 這里的引數中的request是Django原生request,老的request
# 把老的request包裝成了新的request,這個是drf提供的Request類的物件
request = self.initialize_request(request, *args, **kwargs):
# 到此以后,這個request就是新的了,老的request在request._request這是老的
# 把新的request放到了self物件【BookView的物件】
self.request = reqeust
try:
# 執行了三大認證【認證、頻率、權限】,使用新的request,之后會將
self.initial(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
# 把新的request傳入了,視圖類的方法中get的request也是新的
response = handler(request, *atgs, **kwargs)
except Exception as exc:
# 在執行3大認證和視圖類中方法的程序中,如果出了例外,都能捕獲到---》全域例外捕獲
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
'上方的request呼叫了initialize_request方法,這個方法的回傳結果產生了一個Request生成的物件,它的原始碼如下:'
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
reqeust,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
'接著我們點進這個Request類的原始碼,我們會發現老的request變成了_request屬性'
def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None):
self.request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = https://www.cnblogs.com/wurenyao/archive/2023/05/17/Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
# 總結:APIView的執行流程
1.去除了所以的csrf
2.包裝了新的request,以后在視圖類中用的request Request類的物件,不是原生的了
-原生的在:新的request._request
3.在執行視圖類的方法之前,執行了三大認證
4.如果三大認證或視圖函式方法執行程序中出了錯,會有例外捕獲---》全域例外捕獲
5.以后視圖類方法中的request都是新的
# 補充:裝飾器的基本原理
def auth() # 裝飾器
def add() # 函式
# 使用auth裝飾add函式
@auth # 本質是 add=auth(add)
def add()
# 以后再使用add,其實就是在使用 auth(add) 的回傳結果
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552668.html
標籤:其他
上一篇:Django authenticate() 函式查找不到與提交的用戶名和密碼匹配的用戶,則會回傳 None。
下一篇:返回列表
