DRF框架之视图集ViewSet
- 视图集ViewSet与路由Router
- 视图集ViewSet
- 路由Router
- 视图集和路由的基本使用
- 视图集ViewSet的使用
- ViewSet
- GenericViewSet
- ModelViewSet
- ReadOnlyModelViewSet
- 视图集添加其他方法
- 视图集对象action属性
- 路由Router的使用
- SimpleRouter
- DefaultRouter
- 基本使用
- 自定义方法生成路由
视图集ViewSet与路由Router
视图集ViewSet
在DRF中,视图集(Viewsets)是一种特殊的视图类,它将多个视图组合在一起,方便进行管理和维护,并提供通用的CRUD操作。
视图集可以分为两种类型:基于Model的视图集和基于普通类的视图集。基于Model的视图集允许快速创建一个RESTful API,它可以执行标准的CRUD操作。而基于普通类的视图集则允许更加灵活地定义自己的API逻辑。
视图集主要有以下几种:
1. ViewSet:扩展APIView,具有更加灵活的操作方式
2. GenericViewSet:可以自定义操作,需要手动指定queryset和serializer_class属性
3. ModelViewSet: 处理与模型相关的操作(list, create, retrieve, update, partial_update, destroy)
4. ReadOnlyModelViewSet:只读操作,相当于ModelViewSet中的list和retrieve方法
路由Router
在Django中,路由用于将请求映射到相应的视图函数上。而在DRF中,路由则用于将请求映射到视图集上。
在DRF中,视图集通常会与路由器(Router)一起使用,以便自动注册URL,并将请求分配给相应的视图集方法。
Routers提供了一种简单的方式来自动生成URL路由,将HTTP请求映射到相应的视图函数上。使用Routers可以大大减少代码量,降低开发难度。
DRF提供了两种路由方式:
1. SimpleRouter: 适用于基本的CRUD操作
2. DefaultRouter:更加灵活,可以支持自定义操作
视图集和路由的基本使用
定义一个模型类
from django.db import models
class User(models.Model):
name = models.CharField(max_length=6, unique=True, verbose_name='姓名')
age = models.IntegerField(default=0, verbose_name='年龄')
class Meta:
db_table = 'tb_user'
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return "name:%s age:%s" % (self.name, self.age)
定义一个序列化器类
from rest_framework import serializers
from user.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
定义一个UserViewSet视图集
from rest_framework import viewsets
from user.models import User
from user.utils import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
将视图集注册到SimpleRouter路由中。接着将路由的urls属性添加到Django的urlpatterns列表中即可。
from user import views
urlpatterns = [
]
# 创建Router对象
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 注册视图集
router.register('user', views.UserViewSet, basename='users')
# 打印生成的url配置项
for url in router.urls:
print(url)
# 将生成的路由配置项添加到urlpatterns列表中
urlpatterns = router.urls
将会自动生成两个Router配置项
<URLPattern '^user/$' [name='users-list']>
<URLPattern '^user/(?P<pk>[^/.]+)/$' [name='users-detail']>
因此,使用DRF的视图集和路由可以快速地构建出完整且灵活的API。
视图集ViewSet的使用
ViewSet
ViewSet继承自APIView与ViewSetMixin,作用与APIView基本类似,提供了身份认证、权限校验、流量管理等。
视图集中的处理方法不再对应请求方式(get、post等)命名,而是以对应的操作(action)命名。
list:提供一组数据
retrieve:提供单个数据
create:创建数据
update:保存数据
destory:删除数据
class UserViewSet(viewsets.ViewSet):
def list(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def create(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def retrieve(self, request, pk):
try:
user = User.objects.get(id=pk)
except User.DoesNotExist:
raise Http404
serializer = UserSerializer(user)
return Response(serializer.data)
def update(self, request, pk):
try:
user = User.objects.get(id=pk)
except User.DoesNotExist:
raise Http404
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def destroy(self, request, pk):
try:
user = User.objects.get(id=pk)
except User.DoesNotExist:
raise Http404
user.delete()
return Response(status=status.HTTP_204_NOT_CONNECTED)
在进行URL配置时,需要明确指明某个请求方式请求某个URL地址时,对应的是视图集中的哪个处理函数。
urlpatterns = [
re_path(r'^test/$', views.TestView.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^test/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}))
]
GenericViewSet
GenericViewSet继承自GenericAPIView与ViewSetMixin,可以直接搭配Mixin扩展类使用。
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
class TestView(mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
urlpatterns = [
re_path(r'^test/$', views.TestView.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^test/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}))
]
ModelViewSet
ModelViewSet继承自GenericViewSet,同时包括ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
from rest_framework import mixins
from rest_framework.viewsets import ModelViewSet
class BookInfoViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
urlpatterns = [
re_path(r'^test/$', views.TestView.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^test/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}))
]
ReadOnlyModelViewSet
ReadOnlyModelViewSet继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。
from rest_framework.viewsets import ReadOnlyModelViewSet
class TestView(ReadOnlyModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
urlpatterns = [
re_path(r'^test/$', views.TestView.as_view({
'get': 'list',
})),
re_path(r'^test/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'retrieve',
}))
]
视图集添加其他方法
在视图集中,除了默认的action处理方法之外,还可以添加额外的其他处理方法。
class TestView(ViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def other(self, request, pk):
user = User.objects.get(id=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
re_path(r'^test/$', views.TestView.as_view({
'get': 'list',
})),
re_path(r'^test/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'retrieve',
})),
re_path(r'^test/other/(?P<pk>\d+)/$', views.TestView.as_view({
'get': 'other'
}))
Get http://127.0.0.1:8000/test/other/1/
视图集对象action属性
在视图集中,可以通过视图集对象.action获取所有执行action的操作。
应用场景:重写get_serializer_class和get_queryset,根据不同的action操作返回不同的序列化器类和不同的查询集。
def get_serializer_class(self):
if self.action == 'list':
return 'list操作所使用的序列化器类'
else:
return '其他操作所使用的序列化器类'
def get_queryset(self):
if self.action == 'list':
return 'list操作所使用的查询集'
else:
return '其他操作所使用的查询集'
class TestView(ViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def other(self, request, pk):
user = self.get_object(pk)
serializer = self.get_serializer(user)
return Response(serializer.data)
def get_serializer(self, user):
if self.action == 'other':
return UserSerializer(user)
else:
return self.serializer_classa
def get_object(self, pk):
if self.action == 'other':
return User.objects.get(id=pk)
else:
return self.queryset
路由Router的使用
对于视图集ViewSet,除了可以手动进行URL配置指明请求方式与action处理函数之间的对应关系外,还可以使用路由Router来自动生成路由信息。
SimpleRouter
SimpleRouter为每一条url添加一个斜杠后缀,可以在初始化的时候提供 trailing_slash 参数,并设置为 False
router = SimpleRouter(trailing_slash=False)
SimpleRouter生成URL的方式
DefaultRouter
DefaultRouter会生成一个根路径/的配置项
DefaultRouter生成的每个配置项后都可以跟上.json,直接返回json数据
DefaultRouter生成URL的方式
基本使用
创建Router对象,并注册视图集。
from rest_framework.routers import SimpleRouter, DefaultRouter
router = SimpleRouter() 或 DefaultRouter()
注册视图集
# prefix:该视图集所有处理函数url地址的统一前缀
# viewset:视图集
# base_name:该视图集所有处理函数路由name的统一前缀
router.register(prefix, viewset, base_name)
添加路由数据,将生成的路由配置项添加到urlpatterns列表中
urlpatterns = [
]
# 通过router.urls可以获取路由Router生成的url配置项列表。
urlpatterns += router.urls
完整使用如下:
from user import views
urlpatterns = [
]
# 创建Router对象
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 注册视图集
router.register('user', views.UserViewSet, basename='users')
# 打印生成的url配置项
for url in router.urls:
print(url)
# 将生成的路由配置项添加到urlpatterns列表中
urlpatterns = router.urls
将会生成两个Router配置项
<URLPattern '^user/$' [name='users-list']>
<URLPattern '^user/(?P<pk>[^/.]+)/$' [name='users-detail']>
可以指定提取参数的正则表达式,在视图集中设置lookup_value_regex指定。
class UserViewSet(ModelViewSet):
# 指定路由Router生成url配置项时,从路径中提取参数的正则表达式
lookup_value_regex = '\d+'
queryset = User.objects.all()
serializer_class = UserSerializer
<URLPattern '^user/$' [name='users-list']>
<URLPattern '^user/(?P<pk>\d+)/$' [name='users-detail']>
在settings.py
设置使用JSON渲染器
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}
访问测试
http://127.0.0.1:8000/user/user/
http://127.0.0.1:8000/user/user/1
自定义方法生成路由
在视图集中,如果想要让路由Router自动生成视图集中额外添加的处理方法的url配置项,需要给额外的处理方法添加
rest_framework.decorators.action
装饰器。
action装饰器可以接收两个参数:
methods:表明该处理方法对应的请求方式,列表传递
detail:表明生成url配置项时,是否需要从路径中提取pk数据
True:生成url配置项时,需要从url地址中提取pk参数
False:生成url配置项时,不需要从url地址中提取pk参数
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from user.models import User
from user.utils import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
lookup_value_regex = '\d+'
@action(methods=["get"], detail=False, )
def test1(self, request):
users = User.objects.all()
print(users)
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
@action(methods=["get"], detail=True)
def test2(self, request, pk):
users = User.objects.get(id=pk)
serializer = UserSerializer(users)
return Response(serializer.data)
test1函数
使用 @action 装饰器将方法添加到视图集中,并将其映射到名为
/test1/
的路由。该方法使用 GET 请求返回所有用户的数据,并使用 UserSerializer 序列化响应数据。
test2函数
使用 @action 装饰器将方法添加到视图集中,并将其映射到名为
/users/<pk>/test2/
的路由。该方法使用 GET 请求返回具有给定主键值的用户的数据,并使用 UserSerializer 序列化响应数据。
参数提取:
lookup_value_regex 属性设置为 \d+,这表示主键值必须是数字。
<URLPattern '^user/$' [name='users-list']>
<URLPattern '^user/test1/$' [name='users-test1']>
<URLPattern '^user/(?P<pk>\d+)/$' [name='users-detail']>
<URLPattern '^user/(?P<pk>\d+)/test2/$' [name='users-test2']>
访问测试
http://127.0.0.1:8000/user/user/test1/
http://127.0.0.1:8000/user/user/1/test2/