对于上次学到的视图集来说,虽然我们在编写视图逻辑代码时通过继承ModelViewSet后只需提供序列化器和模型对象查询集即可省去增删改查(查询所有数据)这五个常用的接口大量的代码。但是我们在编写路由时,又有些许的麻烦,所有drf为我们提供了routers路由集,为我们在编写视图代码继承视图集时提供自动生成路由的功能。
如下图是继承视图集ModelViewSet后编写的代码及路由。
class _ModelViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookSerializer
#
# --------------------ModelViewSet-----------------------------------------
path('demo/books/', _ModelViewSet.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^demo/books/(?P<pk>\d+)/$', _ModelViewSet.as_view({
"get": 'retrieve',
'delete': 'destroy',
'put': 'update'
})),
对于视图集,我们除了可以自己手动指明请求方式与动作action(视图名)之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。如果是非视图集,不需要使用路由集routers
一、DefaultRouter
from rest_framework.routers.DefaultRouter
如下:通过DefaultRouter自动生成路由步骤(默认自动生成list、create、delete、update、retrieve五个视图函数的路由):
- 创建DefaultRouter实例对象routers
- 通过实例对象routers.register(prefix, viewset, basename=None)方法进行自动生成路由
- prefix:url路径
- viewset:继承视图集的视图
- basename:url路径的别名
- 将自动生成的路由添加到urlpatterns列表中去
1、代码
# -------------------DefaultRouter-----------------------------------------
from rest_framework.routers import DefaultRouter
# 1.实例化DefaultRouter路由对象
routers = DefaultRouter()
# 2.指定继承视图集的视图,自动生成路由
routers.register('demo/books', _ModelViewSet, basename='demo/books/')
for url in routers.urls:
print(url)
# 3.将生成的路由添加到urlpatterns中去
urlpatterns += routers.urls
2、路由
"""
1、对应创建模型对象和查询所有模型对象数据的路由
<URLPattern '^demo/books/$' [name='demo/books/-list']>
2、对应更改、查询、删除单个模型对象的路由
<URLPattern '^demo/books\.(?P<format>[a-z0-9]+)/?$' [name='demo/books/-list']>
<URLPattern '^demo/books/(?P<pk>[^/.]+)/$' [name='demo/books/-detail']>
<URLPattern '^demo/books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='demo/books/-detail']>
3、对应访问url路径http://127.0.0.1:8000时显示
{
"demo/books": "http://127.0.0.1:8000/demo/books/"
}
<URLPattern '^$' [name='api-root']>
4、对应访问url路径http://127.0.0.1:8000\时显示
{
"demo/books": "http://127.0.0.1:8000/demo/books/"
}
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
"""
3、测试
对应根路径的路由
<URLPattern '^$' [name='api-root']>
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
对应更改、查询、删除单个模型对象路径的路由
<URLPattern '^demo/books\.(?P<format>[a-z0-9]+)/?$' [name='demo/books/-list']>
<URLPattern '^demo/books/(?P<pk>[^/.]+)/$' [name='demo/books/-detail']>
<URLPattern '^demo/books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='demo/books/-detail']>
对应创建模型对象和查询所有模型对象数据的路径路由
<URLPattern '^demo/books/$' [name='demo/books/-list']>
二、SimpleRouter
使用方式与DefaultRouter一致的。只是少两个根目录url路径以及将四个url路径压缩为两个。
1、代码
# -------------------SimpleRouter-----------------------------------------
from rest_framework.routers import SimpleRouter
# 1.实例化DefaultRouter路由对象
routers = SimpleRouter()
# 2.指定继承视图集的视图,自动生成路由
routers.register('demo/books', _ModelViewSet, basename='demo/books/')
for url in routers.urls:
print(url)
# 3.将生成的路由添加到urlpatterns中去
urlpatterns += routers.urls
2、路由
1、对应创建模型对象和查询所有模型对象数据的路由
<URLPattern '^demo/books/$' [name='demo/books/-list']>
2、对应更改、查询、删除单个模型对象的路由
<URLPattern '^demo/books/(?P<pk>[^/.]+)/$' [name='demo/books/-detail']>
3、测试
缺少的根路径路由
1、对应创建模型对象和查询所有模型对象数据的路由
<URLPattern '^demo/books/$' [name='demo/books/-list']>
2、对应更改、查询、删除单个模型对象的路由
<URLPattern '^demo/books/(?P<pk>[^/.]+)/$' [name='demo/books/-detail']>
三、视图集中附加action的声明
rest_framework.decorators.action
在视图集中,如果想要让Router自动帮助我们自定义出除开(list、create、delete、update、retrieve)这五个视图函数的url路由外的路由,因为可能一个视图中不止这些方法。则我们需要在视图集中使用action装饰器。
以action装饰器装饰的视图函数方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
-
methods: 声明该action对应的请求方式,列表参数
-
detail: 声明该action的路径是否与单一资源对应
路由前缀/<pk>/action方法名/
-
True 表示路径格式是
xxx/<pk>/action方法名/
-
False 表示路径格式是
xxx/action方法名/
-
-
url_path:声明该action的路由尾缀。
1、不是单一资源
代码
class _ModelViewSet(ModelViewSet):
def get_serializer_class(self):
if self.action == 'get_books_name':
return BookNameSerializer
else:
return BookSerializer
queryset = BookInfo.objects.all()
@action(methods=['GET'], detail=False)
def get_books_name(self, request):
names = self.get_queryset()
ser = self.get_serializer(instance=names, many=True)
return Response(data=ser.data)
自动生成的路由
<URLPattern '^demo/books/get_books_name/$' [name='demo/books/-get-books-name']>
其中自动生成的后缀路由get_books_name/就是视图函数名,demo/books/为以下生成视图集路由时的前缀
routers.register('demo/books', _ModelViewSet, basename='demo/books/')
如果想后缀名/login不是由自动生成路由时的函数名,可以通过url_path自定义后缀名
class _ModelViewSet(ModelViewSet):
def get_serializer_class(self):
if self.action == 'get_books_name':
return BookNameSerializer
else:
return BookSerializer
queryset = BookInfo.objects.all()
@action(methods=['GET'], detail=False, url_path='get_name')
def get_books_name(self, request):
names = self.get_queryset()
ser = self.get_serializer(instance=names, many=True)
return Response(data=ser.data)
<URLPattern '^demo/books/get_name/$' [name='demo/books/-get-books-name']>
2、单一资源
代码
from rest_framework.decorators import action
from .Serializer import BookNameSerializer
class _ModelViewSet(ModelViewSet):
def get_serializer_class(self):
if self.action == 'get_books_name':
return BookNameSerializer
else:
return BookSerializer
queryset = BookInfo.objects.all()
@action(methods=['GET'], detail=True, url_path='get_name')
def get_books_name(self, request, pk):
names = self.get_object()
ser = self.get_serializer(instance=names)
return Response(data=ser.data)
自动生成的路由
<URLPattern '^demo/books/(?P<pk>[^/.]+)/get_name/$' [name='demo/books/-get-books-name']>