drf(路由)
一 自动生成路由
基本使用
# 视图类,继承了ViewSetMixein,路由 # path('books/', views.BookViewSet.as_view(actions={'get': 'list', 'post': 'create'})), # path('book/<int:pk>/', # views.BookViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), # 继承自视图类,ModelViewSet的路由写法(自动生成路由) # 第一步:导入routers模块 from rest_framework import routers # 第二步:有两个类,实例化得到对象 # routers.DefaultRouter 会产生六条路由,有两条跟SimpleRouter一样,其余四条用处不大 # routers.SimpleRouter router = routers.SimpleRouter() # 第三步:注册 # router.register('前缀', '继承自ModelViewSet视图类', '别名') router.register('books', views.BookViewSet) # 第四步:自动生成路由,并加入路由中 print(router.urls) # [<URLPattern '^books/$' [name='book-list']>, <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='book-detail']>] urlpatterns = [ path('admin/', admin.site.urls), # routers产生的路由跟自己写的一样 # path('books/', views.BookViewSet.as_view(actions={'get': 'list', 'post': 'create'})), # path('book/<int:pk>/', # views.BookViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), ] # 两个列表相加 urlpatterns += router.urls # views.py from rest_framework.viewsets import ModelViewSet from app01 import models from app01.ser import BookSerializer class BookViewSet(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookSerializer
使用SimpleRouter()实例化的路由格式
# 项目中打印 # print(router.urls) ''' [ <RegexURLPattern book-list ^books/$>, <RegexURLPattern book-detail ^books/(?P<pk>[^/.]+)/$> ] ''' # 浏览器中打印 ''' # 解析: [^/.]+ [^/.]+ 中^表示取反 意思就是匹配任意其它内容, /就不匹配. +号表示且匹配1个或者多个 ^app01/ ^books/$ [name='book-list'] ^app01/ ^books/(?P<pk>[^/.]+)/$ [name='book-detail'] '''
使用DefaultRouter()类实例化的路由格式
# 项目中打印 ''' [ <RegexURLPattern book-list ^books/$>, <RegexURLPattern book-list ^books\.(?P<format>[a-z0-9]+)/?$>, <RegexURLPattern book-detail ^books/(?P<pk>[^/.]+)/$>, <RegexURLPattern book-detail ^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$>, <RegexURLPattern api-root ^$>, <RegexURLPattern api-root ^\.(?P<format>[a-z0-9]+)/?$> ] ''' # 浏览器中打印 ''' ^app01/ ^books/$ [name='book-list'] ^app01/ ^books\.(?P<format>[a-z0-9]+)/?$ [name='book-list'] ^app01/ ^books/(?P<pk>[^/.]+)/$ [name='book-detail'] ^app01/ ^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail'] ^app01/ ^$ [name='api-root'] ^app01/ ^\.(?P<format>[a-z0-9]+)/?$ [name='api-root'] '''
总结
1. 使用范围: 只有继承了 ViewSetMixin 类的视图, 才可以使用路由组件快速生成路由 2. 快速生成路由的2种路由类: SimpleRouter, DefaultRouter 3. 路由中使用: from django.conf.urls import include from rest_framework.routes import SimpleRouter router = SimpleRouter() router.register('路由前缀', 继承了ViewSetMixin类的视图, 用于反向解析的别名) urlpatterns = [ url('', include(router.urls)), # 添加路由的第二种方式 ] urlpatterns += router # 添加路由的第一种方式
二. 视图中action装饰器
# action是用来给继承自ModelViewSet的视图类中自定义的函数也添加路由 from rest_framework.decorators import action class BookViewSet(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookSerializer # methods第一个参数,传一个列表,列表中放请求方式 # detail=False 生成的路由是^books/get_1/$ [name='book-get-1'] # detail=True 自定义函数需要加pk,生成的路由是^books/(?P<pk>[^/.]+)/get_1/$ [name='book-get-1'] # http://127.0.0.1:8000/books/1/get_1/ @action(methods=['get', 'post'], detail=True) def get_1(self, request, pk): query_book = self.get_queryset()[0:1] # 顾头不顾尾,取一条 book_ser = self.get_serializer(query_book, many=True) # 传的列表,所以要加many=True return Response(book_ser.data) # 装饰器,放在被装饰器函数上方,method:请求方式,detail:是否带pk
源码
''' 提示: action是一个装饰器 导入方式: from rest_framework.decorators import action 作用: 给继承自ModelViewSet的视图类中定义的函数也添加路由 def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs): """ methods: 第一个参数,传一个列表,列表中放请求方式 提示: 由下面的源码得知如果没有指定参数, 默认是get方法. 且方法可以大写, 可以小写. 大写的话就会将大写的字符串转换成小写 methods = ['get'] if (methods is None) else methods methods = [method.lower() for method in methods] detail: 指定布尔值. 控制路由匹配的形式. True可以匹配单条数据, False可以匹配多条数据 True时匹配规则: ^app02/ ^books/(?P<pk>[^/.]+)/get_two/$ [name='book-get-two'] False时匹配规则: ^app02/ ^books/get_two/$ [name='book-get-two'] """ '''
总结
# 为什么使用action装饰器? 因为快速生成路由组件无法手动添加路由 和 无法修改视图类中方法名, 通过action就可以快速实现. # 使用流程 1. 导入: from rest_framework.decorators import action 2. 在视图中为视图中的方法添加装饰器 class BookView(ViewSet): @action(method=["post", ], detail=True) def login(): ... 参数介绍: method: 不指定, 默认就是get方法. 如果指定大写, 默认就会转成小写. detail: 不指定, 会抛出异常. 指定True, False表示的路由不一样. 看3 3. 路由中就会新增一个路由 detail=True时: url(r'^books/(?P<pk>)/login/$') detail=False时: url(r'^books/login/$')
三. 补充: 路由生成的二种方法
urlpatterns = [ # 1. 生成的路由第一种添加方法 url(r'', include(router.urls)) ] # 2. 生成的路由第二种添加方法 urlpatterns += router.urls
四. 补充: 关于路由组件的使用
路由组自动生成的原理: 自动生成路由, 自动配置actions参数.
也就是说只要是继承了ViewSetMixin的视图类, 都可以配置路由组件.