目录
- GenericAPIView类---泛型工具视图类
- 视图工具类
- 工具视图类
- 视图集
- 实际开发中使用视图集时需要优化的点
- SimpleRouter简化...\d_proj\api\urls.py中的代码
GenericAPIView类---泛型工具视图类
- GenericAPIView类继承了APIView类
- APIView类: 1. 通过重写as_view方法禁用了csrf校验, 2. 通过重写dispatch方法, 二次封装request, 进行drf三大认证, 以及二次封装response
- GenericAPIView类定义了类属性: queryset, serializer_class, lookup_field, lookup_url_kwarg
- GenericAPIView类定义了类方法: get_queryset, get_object, get_serializer, get_serializer_class
'''
# ...\Lib\site-packages\rest_framework\generics.py
class GenericAPIView(views.APIView):
queryset = None
serializer_class = None
# 通过lookup_field对应的字段以及lookup_url_kwarg对应的字段值过滤出单个数据对象
lookup_field = 'pk'
lookup_url_kwarg = None
...
def get_queryset(self):
...
queryset = self.queryset
...
return queryset
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
...
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
...
return obj
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
...
return self.serializer_class
# ...\d_proj\api\urls.py
...
urlpatterns = [
url(r'^v2/cars/$', views.CarGenericAPIView.as_view()),
url(r'^v2/cars/(?P<xxx>\w+)/$', views.CarGenericAPIView.as_view()),
]
# ...\d_proj\api\views.py
...
class CarGenericAPIView(generics.GenericAPIView):
print(type(models.Car.objects)) # <class 'django.db.models.manager.Manager'>
print(type(models.Car.objects.all())) # <class 'django.db.models.query.QuerySet'>
print(type(models.Car.objects.filter())) # <class 'django.db.models.query.QuerySet'>
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializers.CarModelSerializer
lookup_url_kwarg = 'xxx'
lookup_field = 'name'
# # 群查
# def get(self, request, *args, **kwargs):
# car_queryset = self.get_queryset()
# car_ser = self.get_serializer(instance=car_queryset, many=True)
# return Response(data={
# 'code': 0,
# 'res': car_ser.data,
# }, status=200)
# 单查
def get(self, request, *args, **kwargs):
car_obj = self.get_object()
car_ser = self.get_serializer(instance=car_obj, many=False)
return Response(data={
'code': 0,
'res': car_ser.data,
}, status=200)
'''
视图工具类
'''
# ...\Lib\site-packages\rest_framework\mixins.py
...
class CreateModelMixin: # 单增
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
...
return Response(serializer.data, ...)
def perform_create(self, serializer):
serializer.save()
...
class ListModelMixin: # 群查
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
...
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class RetrieveModelMixin: # 单查
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class UpdateModelMixin: # 单改
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
...
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
class DestroyModelMixin: # 单删
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
'''
工具视图类
'''
# ...\Lib\site-packages\rest_framework\generics.py
from rest_framework import mixins
...
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
...
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
GenericAPIView):
def get(self, request, *args, **kwargs):
return self.retrieve(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)
'''
视图集
ViewSetMixin类---视图集工具类
-
ViewSetMixin类不继承任何类
-
定义了as_view方法和view函数, 可以通过给该方法传入字典形式的参数, 实现自定义请求方式与请求处理函数的映射关系
GenericViewSet(ViewSetMixin, generics.GenericAPIView)---泛型视图集: 处理与数据库资源密切相关的请求
ViewSet(ViewSetMixin, views.APIView): 处理与数据库资源不是密切相关的请求, 例如: 登录, 短信验证码
'''
# ...\Lib\site-packages\rest_framework\viewsets.py
...
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.action_map = actions
for method, action in actions.items():
handler = getattr(self, action)
setattr(self, method, handler)
...
return self.dispatch(request, *args, **kwargs)
...
view.cls = cls
view.initkwargs = initkwargs
view.actions = actions
return csrf_exempt(view)
...
class ViewSet(ViewSetMixin, views.APIView):
pass
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
'''
实际开发中使用视图集时需要优化的点
- 重写destroy方法, 使删除操作变成将is_delete字段值修改为True
- 重写create方法完成单增群增, 使单增群增共用一个接口
- 添加群该所有字段接口, 群改部分字段接口, 群删接口
'''
# ...\d_proj\api\views.py
class CarModelViewSet(ModelViewSet):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializers.CarModelSerializer
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.is_delete = True
instance.save()
return Response(data={'code': 0, 'res': '删除成功'}, status=200)
def create(self, request, *args, **kwargs):
if isinstance(request.data, list):
car_ser = self.serializer_class(data=request.data, many=True)
car_ser.is_valid(raise_exception=True)
instance = car_ser.save()
re_car_ser = self.serializer_class(instance=instance, many=True)
return Response(data={'code': 0, 'res': re_car_ser.data})
return super().create(request, *args, **kwargs)
def multiple_update(self, request, *args, **kwargs):
return Response(data={'code': 0, 'res': '群改所有字段'}, status=200)
def multiple_partial_update(self, request, *args, **kwargs):
return Response(data={'code': 0, 'res': '群改部分字段'}, status=200)
def multiple_destroy(self, request, *args, **kwargs):
return Response(data={'code': 0, 'res': '群删'}, status=200)
# ...\d_proj\api\urls.py
...
urlpatterns = [
url(r'^v7/cars/$', views.CarModelViewSet.as_view({
'get': 'list',
'post': 'create',
'put': 'multiple_update',
'patch': 'multiple_partial_update',
'delete': 'multiple_destroy',
})),
url(r'^v7/cars/(?P<pk>\d+)/$', views.CarModelViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
})),
]
'''
SimpleRouter简化...\d_proj\api\urls.py中的代码
'''
# ...\d_proj\api\urls.py
...
from .my_routers import MySimpleRouter
urlpatterns = [
...,
]
router = MySimpleRouter()
router.register('v7/cars', views.CarModelViewSet, basename='car')
urlpatterns.extend(router.urls)
# ...\d_proj\api\my_routers.py
from rest_framework.routers import SimpleRouter
from rest_framework.routers import Route
class MySimpleRouter(SimpleRouter):
routes = [
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'}
),
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'}
),
]
# ...\Lib\site-packages\rest_framework\routers.py
class SimpleRouter(BaseRouter):
routes = [
# List route.
Route(
url=r'^{prefix}{trailing_slash}$',
mapping={
'get': 'list',
'post': 'create'
},
name='{basename}-list',
detail=False,
...
),
# 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,
...
),
...,
]
...
def get_default_basename(self, viewset):
queryset = getattr(viewset, 'queryset', None)
...
return queryset.model._meta.object_name.lower()
'''