from rest_framework import views,generics,mixins,viewsets
两大视图类:APIView、GenericAPIView
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
get_queryset
方法:配置queryset
类属性,群查获取QuerySet对象get_object
方法:配置lookup_url_kwarg
类属性,单查获取单个对象get_serializer
方法:配置serializer_class
类属性,提供序列化类并使用自定义的序列化类序列化总结:GenericAPIView就是在APIView基础上额外提供了三个方法和三个类属性,如果不配合视图工具类,则体现不出来优势所在
使用它的好处:视图中的增删改查逻辑其实大差不差,但操作的资源不一致(操作的资源指的是models模型类和序列化类),将资源形成配置,操作逻辑一致,就可以完成封装
群查
from rest_framework.generics import GenericAPIView
class ViewGenericAPIView(GenericAPIView):
# 配置关联表的属性
# 如果只写models.Car.objects的话那就是manager对象,不是QuerySet对象
queryset = models.Car.objects.filter(is_delete=False).all()
# 配置使用的序列化类
serializer_class = serializer.CarModelSerializer
# 群查
def get(self,request,*args,**kwargs):
# 帮我们去表里面拿数据
car_query = self.get_queryset()
# 帮我们去序列化
car_ser = self.get_serializer(car_query,many=True)
return APIResponse(results=car_ser.data)
单查
from rest_framework.generics import GenericAPIView
class ViewGenericAPIView(GenericAPIView):
# 配置关联表的属性
# 如果只写models.Car.objects的话那就是manager对象,不是QuerySet对象
queryset = models.Car.objects.filter(is_delete=False).all()
# 配置使用的序列化类
serializer_class = serializer.CarModelSerializer
# 配置查询的条件为pk,单查走pk过滤的条件
lookup_url_kwarg = 'pk'
# 单查
def get(self,request,*args,**kwargs):
car_obj = self.get_object()
car_ser = self.get_serializer(car_obj)
return APIResponse(results=car_ser.data)
from rest_framework import mixins
class ViewMixinsAPIView(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'
# 单查群查
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
return self.retrieve(request, *args, **kwargs)
return self.list(request, *args, **kwargs)
# 单增
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
# 单整体改
def put(self,request, *args, **kwargs):
return self.update(request, *args, **kwargs)
# 单局部改
def patch(self,request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
# 单删
def delete(self,request, *args, **kwargs):
# django中的删除是真正的删除
# 删除接口一般是自己实现重写到的,因为真正的业务不需要真正的删除
pass
# django源代码中是真的删除
return self.destroy(request, *args, **kwargs)
工具类加视图类的组合,只要继承工具该类,就有响应的方法,
随后就是用单查就继承单查的接口,用群查就继承群查的接口即可。
from rest_framework import generics
class ViewGenericsAPIView(generics.RetrieveAPIView,
generics.ListAPIView,
generics.CreateAPIView,
generics.UpdateAPIView,
generics.DestroyAPIView):
# 单查和群查只能使用一个get,具体调用哪个要看继承的顺序
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'
# 有删除需求的接口继承DestroyAPIView,重写destroy完成字段的删除
def destroy(self, request, *args, **kwargs):
pass
可自定义路由层中请求方法的映射关系来实现接口
路由层
url(r'^v5/cars/$', views.ViewViewsetsAPIView.as_view({
"get":"list",
"post":"create"
})),
url(r'^v5/cars/(?P\d+)/$', views.ViewViewsetsAPIView.as_view({
"get":"retrieve",
"put":"update",
"patch":"partial_update",
"delete":"destroy"
})),
视图层
from rest_framework import viewsets
# 视图集类
class ViewViewsetsAPIView(viewsets.ModelViewSet):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializer.CarModelSerializer
lookup_url_kwarg = 'pk'
以上的步骤我们继承视图集的ModelViewSet类实现了六大接口,但是从实际开发角度分析有很多不合理的点:
所以针对以上问题,我们解决一下:
路由层配置
url(r'^v5/cars/$', views.ViewViewsetsAPIView.as_view({
"get":"list",
"post":"create",
"put":"many_update",
"patch":"many_partial_update",
"delete":"many_destroy"
})),
url(r'^v5/cars/(?P\d+)/$', views.ViewViewsetsAPIView.as_view({
"get":"retrieve",
"put":"update",
"patch":"partial_update",
"delete":"destroy"
})),
视图层配置
# 群整体改
def many_update(self,request,*args,**kwargs):
try:
pks = []
for dic in request.data:
pks.append(dic.pop('pk'))
car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(car_query):
raise Exception('pk对象不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
car_ser = self.get_serializer(instance=car_query,data=request.data,many=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(results=self.get_serializer(car_obj,many=True).data)
# 群局部改
def many_partial_update(self,request,*args,**kwargs):
try:
pks = []
for dic in request.data:
pks.append(dic.pop('pk'))
car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(car_query):
raise Exception('pk对象不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
car_ser = self.get_serializer(instance=car_query,data=request.data,many=True,partial=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(results=self.get_serializer(car_obj,many=True).data)
# 群删
def many_destroy(self,request,*args,**kwargs):
pks = request.data
try:
rows = models.Car.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
except:
return APIResponse(1, '数据有误')
if rows:
return APIResponse(msg='删除成功')
return APIResponse(1, '删除失败')
# 群增和单增必须使用同一个接口,都要走create方法,重写create方法,使用逻辑拆分
def create(self, request, *args, **kwargs):
if isinstance(request.data,list):
car_ser = self.get_serializer(data=request.data,many=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(msg="群增成功",results=self.get_serializer(car_obj,many=True).data)
return super().create(request, *args, **kwargs)
# 解决2 destroy方法完成对字段的修改
def destroy(self, request, *args, **kwargs):
car_obj = self.get_object()
if not car_obj:
return APIResponse(1,msg="删除失败")
car_obj.is_delete = True
car_obj.save()
return APIResponse(msg="删除成功")
# 解决3 群查有状态码和状态信息,重写list方法
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
return APIResponse(results=response.data)
# 重写retrieve方法,单查有状态码和状态信息
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
return APIResponse(results=response.data)
使用SimpleRouter结合视图组件进行路由配置
from django.conf.urls import url,include
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 将所有路由与ViewSet视图类的都可以注册,会产生'^v5/cars/$' 和 '^v5/cars/(?P[^/.]+)/$'的url
router.register('v5/cars',views.ViewViewsetsAPIView,basename='car')
urlpatterns = [
# 第一种添加子列表方式
url(r'^', include(router.urls)),
]
# 第二种添加子列表方式
# urlpatterns.extend(router.urls)
路由组件源码部分
如果想实现其他映射关系的话,修改源码就行了
routes = [
# List route.
# 群增,如果想要在url中奖请求方式映射关系改变的话,可以重写这个
Route(
url=r'^{prefix}{trailing_slash}$',
mapping={
'get': 'list',
'post': 'create'
},
name='{basename}-list',
detail=False,
initkwargs={'suffix': 'List'}
),
# Dynamically generated list routes. Generated using
# @action(detail=False) decorator on methods of the viewset.
DynamicRoute(
url=r'^{prefix}/{url_path}{trailing_slash}$',
name='{basename}-{url_name}',
detail=False,
initkwargs={}
),
# Detail route.
Route(
url=r'^{prefix}/{lookup}{trailing_slash}$',
mapping={
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
},
name='{basename}-detail',
detail=True,
initkwargs={'suffix': 'Instance'}
),
# Dynamically generated detail routes. Generated using
# @action(detail=True) decorator on methods of the viewset.
DynamicRoute(
url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
name='{basename}-{url_name}',
detail=True,
initkwargs={}
),
]
或者自定义路由对象
from rest_framework.routers import Route, DynamicRoute, SimpleRouter as DRFSimpleRouter
class SimpleRouter(DRFSimpleRouter):
routes = [
# List route. /资源s/
Route(
url=r'^{prefix}{trailing_slash}$',
mapping={
'get': 'list', # 群查
'post': 'create', # 单增、群增
'put': 'many_update', # 群整改
'patch': 'many_partial_update', # 群局改
'delete': 'many_destroy', # 群删
},
name='{basename}-list',
detail=False,
initkwargs={'suffix': 'List'}
),
# Dynamically generated list routes. Generated using
# @action(detail=False) decorator on methods of the viewset.
DynamicRoute(
url=r'^{prefix}/{url_path}{trailing_slash}$',
name='{basename}-{url_name}',
detail=False,
initkwargs={}
),
# Detail route. /资源s/(pk)/
Route(
url=r'^{prefix}/{lookup}{trailing_slash}$',
mapping={
'get': 'retrieve', # 单查
'put': 'update', # 单整改
'patch': 'partial_update', # 单局改
'delete': 'destroy' # 单删
},
name='{basename}-detail',
detail=True,
initkwargs={'suffix': 'Instance'}
),
# Dynamically generated detail routes. Generated using
# @action(detail=True) decorator on methods of the viewset.
DynamicRoute(
url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
name='{basename}-{url_name}',
detail=True,
initkwargs={}
),
]
# 对外提供router对象
router = SimpleRouter()
# eg: router.register('users', UserModelViewSet, basename='user')