目录
一、实现数据库的增删改查 - 未优化常规写法(两个路由两个视图)
1-1 两条路由分发 - 接参不接参
1-2 Serializers用于获取数据序列化
1-3 视图函数
二、优化方式一 - GenericAPIView, ListModelMixin, CreateModelMixin……
2-1 视图函数 + 路由设计
2-2 视图优化思路 - 单独提出重复代码,封装成类及方法
2-3 源码分析
2-3-1 GenericAPIView - 视图优化基类
2-3-2 ListModelMixin - 用于get获取数据列表
2-3-3 CreateModelMixin - 创建对象
2-3-4 RetrieveModelMixin - 获取单个对象
2-3-5 UpdateModelMixin - 更新单个对象
2-3-6 DestroyModelMixin - 删除对象
三、方式二- ListCreateAPIView、RetrieveUpdateDestroyAPIView
3-1 视图函数
3-2 源码分析
3-2-1 ListCreateAPIView
3-2-2 RetrieveUpdateDestroyAPIView
3-2-3 RetrieveDestroyAPIView
3-2-4 RetrieveUpdateAPIView
四、方式三 - ModelViewSet 配合 urls路由(不推荐)
4-1 路由设计
4-2 视图函数
4-3 源码分析
一、实现数据库的增删改查 - 未优化常规写法(两个路由两个视图)
1-1 两条路由分发 - 接参不接参
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P
\d+)', views.PublishDetailView.as_view()), ] 1-2 Serializers用于获取数据序列化
from rest_framework import serializers from app01 import models class PublishSerializers(serializers.ModelSerializer): class Meta: model = models.Publish fields = '__all__'
1-3 视图函数
from django.shortcuts import render, HttpResponse from rest_framework.views import APIView from django.http import JsonResponse from app01 import MySerializer class PublishView(APIView): def get(self, request): publish_list = models.Publish.objects.all() ser = MySerializer.PublishSerializers(publish_list, many=True) return JsonResponse(ser.data, safe=False) def post(self, request): ser = MySerializer.PublishSerializers(data=request.data) if ser.is_valid(): ser.save() return JsonResponse(ser.data, safe=False) else: return JsonResponse(ser.errors, safe=False) class PublishDetailView(APIView): def get(self, request, pk): publish_obj = models.Publish.objects.filter(pk=pk).first() ser = MySerializer.PublishSerializers(publish_obj, many=False) return JsonResponse(ser.data, safe=False) def put(self, request, pk): publish_obj = models.Publish.objects.filter(pk=pk).first() ser = MySerializer.PublishSerializers(data=request.data, instance=publish_obj) if ser.is_valid(): ser.save() return JsonResponse(ser.data, safe=False) else: return JsonResponse(ser.errors, safe=False) def delete(self, request, pk): models.Publish.objects.filter(pk=pk).delete() return JsonResponse("delete", safe=False)
二、优化方式一 - GenericAPIView, ListModelMixin, CreateModelMixin……
总结:
- ListModelMixin - 获取对象列表
- CreateModelMixin - 创建对象数据
- RetrieveModelMixin - 获取指定对象数据
- UpdateModelMixin - 更新对象数据
- DestroyModelMixin - 删除对象数据
2-1 视图函数 + 路由设计
''' from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P
\d+)', views.PublishDetailView.as_view()), ] ''' from app01 import models from app01 import MySerializer from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \ DestroyModelMixin from rest_framework.generics import GenericAPIView class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = models.Publish.objects.all() serializer_class = MySerializer.PublishSerializers def get(self, request): return self.list(request) def post(self, request): return self.create(request) class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = models.Publish.objects.all() serializer_class = MySerializer.PublishSerializers def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk) 2-2 视图优化思路 - 单独提出重复代码,封装成类及方法
''' from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P
\d+)', views.PublishDetailView.as_view()), ] ''' ''' 数据库的增删改查逻辑,提出来封装成类,以及类内的方法 ''' class List: def list(self, request): # queryset : Publish.objects.all(),serializers : PublishSerializers queryset = self.queryset.all() ser = self.serializers(queryset, many=True) return JsonResponse(ser.data, safe=False) class Create: def create(self, request): print(request.data) ser = MySerializer.PublishSerializers(data=request.data) if ser.is_valid(): ser.save() # 生成记录 return JsonResponse(ser.data, safe=False) else: return JsonResponse(ser.errors, safe=False) class Retrieve: def retrieve(self, request, pk): queryset = self.queryset.all() obj = queryset.filter(pk=pk).first() ser = self.serializers(obj, many=False) return JsonResponse(ser.data, safe=False) class Update: def update(self, request, pk): obj = self.queryset.filter(pk=pk).first() ser = self.serializers(data=request.data, instance=obj, many=False) if ser.is_valid(): ser.save() return JsonResponse(ser.data, safe=False) else: return JsonResponse(ser.errors, safe=False) class Destroy: def destroy(self, request, pk): self.queryset.filter(pk=pk).delete() return JsonResponse("delete", safe=False) class PublishView(APIView, List, Create): queryset = models.Publish.objects.all() serializers = MySerializer.PublishSerializers def get(self, request): return self.list(request) def post(self, request): # 添加一条数据 return self.create(request) class PublishDetailView(APIView, Retrieve, Update, Destroy): queryset = models.Publish.objects.all() serializers = MySerializer.PublishSerializers def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk) 2-3 源码分析
2-3-1 GenericAPIView - 视图优化基类
class GenericAPIView(views.APIView): """ Base class for all other generic views. """ # You'll need to either set these attributes, # or override `get_queryset()`/`get_serializer_class()`. # If you are overriding a view method, it is important that you call # `get_queryset()` instead of accessing the `queryset` property directly, # as `queryset` will get evaluated only once, and those results are cached # for all subsequent requests. ''' 您需要设置这些属性,或者覆盖' get_queryset() ' / ' get_serializer_class() '。 如果你覆盖了一个视图方法,重要的是你调用' get_queryset() '而不是直接访问' queryset '属性, 因为‘queryset’只会被求值一次,而这些结果会被缓存到所有后续请求中。 ''' queryset = None serializer_class = None # If you want to use object lookups other than pk, set 'lookup_field'. # For more complex lookup requirements override `get_object()`. ''' 如果您想使用pk之外的对象查找,请设置“lookup_field”。 对于更复杂的查询需求,请重写' get_object() '。 ''' lookup_field = 'pk' lookup_url_kwarg = None # The filter backend classes to use for queryset filtering # 用于queryset筛选的筛选后端类 filter_backends = api_settings.DEFAULT_FILTER_BACKENDS # The style to use for queryset pagination. # 用于queryset分页的样式。 pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): """ Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using `self.queryset`. This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests. You may want to override this if you need to provide different querysets depending on the incoming request. (Eg. return a list of items that is specific to the user) """ assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ ) queryset = self.queryset if isinstance(queryset, QuerySet): # Ensure queryset is re-evaluated on each request. queryset = queryset.all() return queryset def get_object(self): """ Returns the object the view is displaying. You may want to override this if you need to provide non-standard queryset lookups. Eg if objects are referenced using multiple keyword arguments in the url conf. """ queryset = self.filter_queryset(self.get_queryset()) # Perform the lookup filtering. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field assert lookup_url_kwarg in self.kwargs, ( 'Expected view %s to be called with a URL keyword argument ' 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 'attribute on the view correctly.' % (self.__class__.__name__, lookup_url_kwarg) ) filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} obj = get_object_or_404(queryset, **filter_kwargs) # May raise a permission denied self.check_object_permissions(self.request, obj) return obj def get_serializer(self, *args, **kwargs): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. """ serializer_class = self.get_serializer_class() kwargs['context'] = self.get_serializer_context() return serializer_class(*args, **kwargs) def filter_queryset(self, queryset): """ Given a queryset, filter it with whichever filter backend is in use. You are unlikely to want to override this method, although you may need to call it either from a list view, or from a custom `get_object` method if you want to apply the configured filtering backend to the default queryset. 给定一个queryset,用使用的任何过滤器后端过滤它。 您不太可能想要覆盖这个方法,尽管您可能需要要从列表视图或自定义的“get_object”调用它, 请执行以下操作方法中应用已配置的筛选后端。默认queryset。 """ for backend in list(self.filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) return queryset
2-3-2 ListModelMixin - 用于get获取数据列表
class ListModelMixin(object): """ List a queryset. """ def list(self, request, *args, **kwargs): # GenericAPIView内的filter_queryset和get_queryset # 主要通过筛选等逻辑处理获取了一个queryset queryset = self.filter_queryset(self.get_queryset()) # 分页相关 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) # GenericAPIView内的get_serializer serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
2-3-3 CreateModelMixin - 创建对象
class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 调用下方perform_create self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) # 保存对象 def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
2-3-4 RetrieveModelMixin - 获取单个对象
class RetrieveModelMixin(object): """ Retrieve a model instance. """ def retrieve(self, request, *args, **kwargs): # GenericAPIView的get_object方法,获取单个对象 instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data) def get_object_or_404(queryset, *filter_args, **filter_kwargs): """ Same as Django's standard shortcut, but make sure to also raise 404 if the filter_kwargs don't match the required types. """ try: return _get_object_or_404(queryset, *filter_args, **filter_kwargs) except (TypeError, ValueError, ValidationError): raise Http404
2-3-5 UpdateModelMixin - 更新单个对象
class UpdateModelMixin(object): """ Update a model instance. """ 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) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} 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)
2-3-6 DestroyModelMixin - 删除对象
class DestroyModelMixin(object): """ Destroy a model instance. """ 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()
三、方式二- ListCreateAPIView、RetrieveUpdateDestroyAPIView
ListCreateAPIView - 等同于GenericAPIView, ListModelMixin, CreateModelMixin
RetrieveUpdateDestroyAPIView - 等同于GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
3-1 视图函数
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView from app01 import MySerializer from app01 import models # 同下 class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin): class PublishView(ListCreateAPIView): queryset = models.Publish.objects.all() serializer_class = MySerializer.PublishSerializers class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = models.Publish.objects.all() serializer_class = MySerializer.PublishSerializers
3-2 源码分析
3-2-1 ListCreateAPIView
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): """ Concrete view for listing a queryset or creating a model instance. """ def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
3-2-2 RetrieveUpdateDestroyAPIView
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): """ Concrete view for retrieving, updating or deleting a model instance. """ 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) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
3-2-3 RetrieveDestroyAPIView
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView): """ Concrete view for retrieving or deleting a model instance. """ def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
3-2-4 RetrieveUpdateAPIView
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView): """ Concrete view for retrieving, updating a model instance. """ 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)
四、方式三 - ModelViewSet 配合 urls路由(不推荐)
4-1 路由设计
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # 基于ViewSetMixin,重写as_view方法拦截 url(r'^publish/$', views.PublishView.as_view({'get': 'list', 'post': 'create'})), url(r'^publish/(?P
\d+)', views.PublishView.as_view({'get': 'retrieve', 'put': 'update','delete':'destroy'})), ] 4-2 视图函数
from rest_framework.viewsets import ModelViewSet # ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, # mixins.DestroyModelMixin, # mixins.ListModelMixin, # GenericViewSet): class PublishView(ModelViewSet): queryset = models.Publish.objects.all() serializer_class = MySerializer.PublishSerializers
4-3 源码分析
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass