17

drf 路由生成

 3 years ago
source link: http://www.cnblogs.com/Yunya-Cnblogs/p/13906709.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言

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 ,这是因为我们的 APIlookup_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']

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK