路由(前三种写法)
url(r'^books/$',views.BooksView.as_view()), url(r'^books/(?P<pk>\d+)$',views.BookDetailView.as_view())基本写法(继承APIView)
# 写一个出版社的增删查改resful接口 """路由""" url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P<pk>\d+)/$', views.PublishDetailView.as_view()), """视图""" class PublishSerializers(serializers.ModelSerializer): class Meta: model=models.Publish fields='__all__' class PublishView(APIView): def get(self, request): publish_list = models.Publish.objects.all() bs = PublishSerializers(publish_list, many=True) # 序列化数据 return Response(bs.data) def post(self, request): # 添加一条数据 print(request.data) bs=PublishSerializers(data=request.data) if bs.is_valid(): bs.save() # 生成记录 return Response(bs.data) else: return Response(bs.errors) class PublishDetailView(APIView): def get(self,request,pk): publish_obj=models.Publish.objects.filter(pk=pk).first() bs=PublishSerializers(publish_obj,many=False) return Response(bs.data) def put(self,request,pk): publish_obj = models.Publish.objects.filter(pk=pk).first() bs=PublishSerializers(data=request.data,instance=publish_obj) if bs.is_valid(): bs.save() # update return Response(bs.data) else: return Response(bs.errors) def delete(self,request,pk): models.Publish.objects.filter(pk=pk).delete() return Response("")第二种写法
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \ ListModelMixin, RetrieveModelMixin from rest_framework.generics import GenericAPIView from app01 import myser from app01 import models class BooksView(CreateModelMixin, ListModelMixin, GenericAPIView): queryset = models.Book.objects.all() serializer_class = myser.BookSerializer def post(self, request, *args, **kwargs): print(request.data) return self.create(request, *args, **kwargs) # 返回多条数据 def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class BookDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView): queryset = models.Book.objects.all() serializer_class = myser.BookSerializer # 返回单条数据 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 delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)第三种写法
class BooksView(ListCreateAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers class BookDetailView(RetrieveUpdateDestroyAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers第四种写法(两个视图类合成一个)
路由
url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})), url(r'^publish/(P<pk>\d+)/$',views.PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})), from rest_framework.viewsets import ModelViewSet class PublishView(ModelViewSet): queryset=models.Publish.objects.all() serializer_class=PublishSerializers # ViewSetMixin重写了as_view方法,路由配置就改了,可以写成映射的形式{get:get_one} # as_view方法内部执行效果 # 通过反射的取值跟赋值,完成映射,根据请求方式执行对应的方法(比如:get请求执行get_one方法,在路由中配置{get:getone})ModelViewSet源码流程分析
""" ModelViewSet: 1.----> 首先 源码中ModelViewSet继承了如下mixins.CreateModelMixin....等五种Mixin方法,最重要的变化是继承了 GenericViewSet 2.----> 进入 GenericViewSet 继承了 ViewSetMixin, generics.GenericAPIView 变化在于继承的ViewSetMixin 3.----> 进入 ViewSetMixin 和 APIView 区别就在与重写了 as_view 方法 4.----> 5.----> 6.----> 7.----> 8.----> 9.----> 10.---> """ 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 class GenericViewSet(ViewSetMixin, generics.GenericAPIView): """ The GenericViewSet class does not provide any actions by default, but does include the base set of generic view behavior, such as the `get_object` and `get_queryset` methods. """ pass class ViewSetMixin(object): """ This is the magic. 重写了 as_view方法 目的是为了获得一个个key对应一个个 Http请求的方法的映射关系 Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource. For example, to create a concrete view binding the 'GET' and 'POST' methods to the 'list' and 'create' actions... view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """ # 这里是重写的 as_view方法 ,传入 action-即为 前面 as_view({'get':'list',}) @classonlymethod def as_view(cls, actions=None, **initkwargs): """ Because of the way class based views create a closure around the instantiated view, we need to totally reimplement `.as_view`, and slightly modify the view function that is created and returned. """ # The name and description initkwargs may be explicitly overridden for # certain route confiugurations. eg, names of extra actions. cls.name = None cls.description = None # The suffix initkwarg is reserved for displaying the viewset type. # This initkwarg should have no effect if the name is provided. # eg. 'List' or 'Instance'. cls.suffix = None # The detail initkwarg is reserved for introspecting the viewset type. cls.detail = None # Setting a basename allows a view to reverse its action urls. This # value is provided by the router through the initkwargs. cls.basename = None # actions must not be empty # 这里 actions 不能为空,所以 as_view({'..':'..'}) 必须穿参数 if not actions: raise TypeError("The `actions` argument must be provided when " "calling `.as_view()` on a ViewSet. For example " "`.as_view({'get': 'list'})`") # sanitize keyword arguments for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r" % ( cls.__name__, key)) # name and suffix are mutually exclusive if 'name' in initkwargs and 'suffix' in initkwargs: raise TypeError("%s() received both `name` and `suffix`, which are " "mutually exclusive arguments." % (cls.__name__)) def view(request, *args, **kwargs): self = cls(**initkwargs) # We also store the mapping of request methods to actions, # so that we can later set the action attribute. # eg. `self.action = 'list'` on an incoming GET request. # 将 actions 传过来的字典映射关系给 self.action_map self.action_map = actions # Bind methods to actions # This is the bit that's different to a standard view # 这里就是和标准的as_view 不同之处 for method, action in actions.items(): # 通过反射获取对象中 actions的key(这里赋值给了action)的方法 handler = getattr(self, action) # 获得是内存地址 setattr(self, method, handler) # 将内存地址赋值给 method 也就是此时method方法就是handler方法 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # And continue as usual return self.dispatch(request, *args, **kwargs) # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) # We need to set these on the view function, so that breadcrumb # generation can pick out these bits of information from a # resolved URL. view.cls = cls view.initkwargs = initkwargs view.actions = actions return csrf_exempt(view)对比 APIView 中的 as_view()
from rest_framework.views import APIView # APIView 中的 as_view() @classmethod def as_view(cls, **initkwargs): """ Store the original class on the view function. This allows us to discover information about the view when we do URL reverse lookups. Used for breadcrumb generation. """ if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)转载于:https://www.cnblogs.com/qianzhengkai/p/11135416.html