drf 路由生成
前言
在drf
中,我們寫介面可以通過繼承modelViewSet
從而達到非常快速的功能實現,這十分的方便,但是modelViewSet
由於需要根據不同的參數來對應不同的處理,所以我們寫的url
最少都需要兩條,如下所示:
path('api/users/', views.UserAPI.as_view(actions={"get":"list","post":"create"})),
re_path('^api/users/(?P<uid>\d+)?',views.UserAPI.as_view(actions={"get":"retrieve","patch":"update","delete":"destroy"}))
有沒有什麼辦法能夠快速的生成兩條url
呢?其實是有的,但是在這之前我們也可以對他手動封裝一個組件,達到自動生成路由的功能。
手動封裝
下面是手動封裝url
的一個示例,首先url
本身就是一個列表,所以我們的組件最終可以返回一個可迭代對象就行,直接將生成的url
添加至已有的url
列表中。
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
from rest_framework.routers import SimpleRouter
class GenerateRouter:
def __init__(self):
self.urls = None
def register(self, prefix, viewset, basename=None):
# prefix 匹配規則,不用加 /
# viewset 繼承自ModelViewSet視圖類
# basename 別名
from django.urls import path, re_path
name = viewset.serializer_class.Meta.model.__name__.lower() # 獲取查詢的數據表名字
self.urls = (
re_path("^%s/$" % prefix, viewset.as_view(actions={"get": "list", "post": "create"}),
name=basename or name + "-list"), # 不需要參數,查全部和新增
re_path('^%s/(?P<%s>[^/.]+)/$' %(prefix,viewset.lookup_url_kwarg or "pk"), # 如果設置捕獲欄位,就用捕獲欄位,否則就用pk
viewset.as_view(
actions={"get": "retrieve", "patch": "update", "delete": "destroy", "put": "update"}),
name=basename or name + "-detail"),
)
router = GenerateRouter() # 實例化
router.register("api/users", views.UserAPI) # 註冊
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns.extend(router.urls) # 添加
它生成的路由是這樣子的:
^api/users/$ [name='user-list']
^api/users/(?P<uid>[^/.]+)/$ [name='user-detail']
router組件
簡單路由
在drf
中也提供了這樣的組件,它可以幫助我們快速的生成路由。比我們上面自己封裝的要強大一些,但是本質上都是一樣的。
下面是簡單使用,首先我們需要進行導入。
from rest_framework.routers import SimpleRouter
其次是對其進行實例化後註冊一個路由資訊。
def register(self, prefix, viewset, basename=None)
# prefix 匹配規則,不用加 /
# viewset 繼承自ModelViewSet視圖類
# basename 別名
from django.contrib import admin
from django.urls import path
from app01 import views
from rest_framework.routers import SimpleRouter # 第一步導入
router = SimpleRouter() # 第二步實例化
router.register("api/users", views.UserAPI) # 第三步註冊路由
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns.extend(router.urls) # 第四步添加
它會自動生成兩條url
,這與我們上面的手動封裝是一樣的原理:
^api/users/$ [name='user-list']
^api/users/(?P<uid>[^/.]+)/$ [name='user-detail']
至於這裡為什麼是uid
,這是因為我們的API
中lookup_url_kwarg
設置的就是uid
。
可以看以下上面手動封裝中,也是這麼做的。
class UserAPI(ModelViewSet):
queryset = models.User.objects # 傳入對象即可
serializer_class = ser.UserModelSerializers # 序列化類
lookup_field = "pk"
lookup_url_kwarg = "uid" # 由於捕獲的是uid,需要聲明
默認路由
簡單的SimpleRouter()
其實就足夠我們用了,但是drf
也提供了更高級的默認路由,它會生成六條url
,但是基本沒啥用。
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
from rest_framework.routers import SimpleRouter
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("api/users", views.UserAPI)
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns.extend(router.urls)
以下是生成的路由資訊。
^api/users/$ [name='user-list']
^api/users\.(?P<format>[a-z0-9]+)/?$ [name='user-list']
^api/users/(?P<uid>[^/.]+)/$ [name='user-detail']
^api/users/(?P<uid>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='user-detail']
^$ [name='api-root']
^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']
action裝飾器
action
幹什麼用?是為了給繼承自ModelViewSet
的視圖類中定義的函數也添加路由。
from . import models
from . import ser
from rest_framework.decorators import action # 導入裝飾器
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
class UserAPI(ModelViewSet):
queryset = models.User.objects.all() # 傳入對象即可
serializer_class = ser.UserModelSerializers # 序列化類
lookup_field = "pk"
lookup_url_kwarg = "uid" # 由於捕獲的是uid,需要聲明
@action(methods=['GET','POST'],detail=True)
def customize(self,request,uid):
book=self.get_queryset()[:2] # 從0開始截取一條
serializer=self.get_serializer(book,many=True) # 只要是返回queryset對象,就需要many=True
return Response(serializer.data)
# action的執行會覆蓋掉本身的get、post、patch等所執行的方法,如list,update,create等默認行為。
# methods代表請求方式,當有該種請求到來時,則執行該方法
# detail代表是否需要捕獲參數,True則是捕獲。捕獲參數名字就是lookup_url_kwarg
生成的路由資訊如下:
^api/users/(?P<uid>[^/.]+)/customize/$ [name='user-customize']
^api/users/(?P<uid>[^/.]+)/customize\.(?P<format>[a-z0-9]+)/?$ [name='user-customize']