前言

   drf视图的源码非常的绕,但是实现的功能却非常的神奇。

   它能够帮你快速的解决ORM增删改查的重复代码,非常的方便好用。

   下面是它源码中的一句话:

  1. class ViewSetMixin:
  2. """
  3. This is the magic.
  4. """

   好了,屁话不多说,直接看看drf视图中的功能吧。

准备工作

   此次的Django采用3版本,所以相对于1版本来说有一些差异。

模型表

   下面是模型表:

  1. from django.db import models
  2. # Create your models here.
  3. class User(models.Model):
  4. user_id = models.AutoField(primary_key=True)
  5. user_name = models.CharField(max_length=50)
  6. user_gender = models.BooleanField(
  7. [(0,"male"),(1,"female")],
  8. default = 0,
  9. )
  10. user_age = models.IntegerField()
  11. def __str__(self):
  12. return self.user_name
  13. class Meta:
  14. db_table = ''
  15. managed = True
  16. verbose_name = 'User'
  17. verbose_name_plural = 'Users'

   数据如下:

  1. INSERT INTO app01_user(user_name,user_age,user_gender) VALUES
  2. ("用户1",18,0),
  3. ("用户2",19,1),
  4. ("用户3",19,1);

序列类

   序列类采用ModelSerializer

  1. from rest_framework import serializers
  2. from . import models
  3. class UserModelSerializers(serializers.ModelSerializer):
  4. class Meta:
  5. model = models.User
  6. fields = "__all__"

url路由

   下面是url路由的设定:

  1. re_path('^api/users/(?P<uid>\d+)?',views.UserAPI.as_view())

封装Rsponse

   由于不需要返回原生的Response,所以我们封装了一个类,用于更加方便的返回Response

  1. class ResponseMeta(type):
  2. # 对Response类做封装
  3. def __call__(cls, *args, **kwargs):
  4. obj = cls.__new__(cls, *args, **kwargs)
  5. cls.__init__(obj, *args, **kwargs)
  6. return Response(data=obj.__dict__)
  7. class CommonResponse(object, metaclass=ResponseMeta):
  8. # 返回的信息
  9. def __init__(self, status, data=None, errors=None):
  10. self.status = status
  11. self.data = data
  12. self.errors = errors

APIView

继承关系

   APIView的导入如下:

  1. from rest_framework.views import APIView

   APIView继承了原生的DjangoView,在其之上做了一些封装,使操作更加简单。

  

封装特性

   在APIView中对原生的request对象进行封装,最常用的两个属性如下,它弥补了Django原生ViewJSON请求格式的数据没有处理的缺陷。

   同时,APIView认为对于GET请求的资源参数,不应该使用GET获取,而是应该使用query_params进行获取。

属性 描述
request.data 当请求数据为Json格式时,将以dict形式保存,主要针对request.POST请求
request.query_params 当请求方式为GET时,可获取url中的请求数据

接口书写

   以下是使用APIViewUser表进行增删改查的接口书写。

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from rest_framework.request import Request
  4. from . import models
  5. from . import ser
  6. class ResponseMeta(type):
  7. # 对Response类做封装
  8. def __call__(cls, *args, **kwargs):
  9. obj = cls.__new__(cls, *args, **kwargs)
  10. cls.__init__(obj, *args, **kwargs)
  11. return Response(data=obj.__dict__)
  12. class CommonResponse(object, metaclass=ResponseMeta):
  13. # 返回的信息
  14. def __init__(self, status, data=None, errors=None):
  15. self.status = status
  16. self.data = data
  17. self.errors = errors
  18. class UserAPI(APIView):
  19. def get(self, request, uid=None):
  20. if not uid:
  21. # 获取所有
  22. user_queryset = models.User.objects.all()
  23. if user_queryset.exists():
  24. serialization = ser.UserModelSerializers(instance=user_queryset, many=True)
  25. return CommonResponse(status=100, data=serialization.data, errors=None)
  26. return CommonResponse(status=200, errors="暂时没有任何学生")
  27. else:
  28. user_obj = models.User.objects.filter(pk=uid).first()
  29. if user_obj:
  30. serialization = ser.UserModelSerializers(instance=user_obj)
  31. return CommonResponse(status=100, data=serialization.data, errors=None)
  32. return CommonResponse(status=200, errors="没有该学生")
  33. def post(self, request):
  34. serialization = ser.UserModelSerializers(data=request.data)
  35. if serialization.is_valid():
  36. serialization.save()
  37. return CommonResponse(status=100, data=serialization.data, errors=None)
  38. return CommonResponse(status=200, errors=serialization.errors)
  39. def patch(self, request, uid):
  40. user_obj = models.User.objects.filter(pk=uid).first()
  41. if user_obj:
  42. serialization = ser.UserModelSerializers(instance=user_obj, data=request.data)
  43. if serialization.is_valid():
  44. serialization.save()
  45. return CommonResponse(status=100, data=serialization.data, errors=None)
  46. else:
  47. return CommonResponse(status=200, errors="修改失败,请检查字段是否一直")
  48. else:
  49. return CommonResponse(status=200, errors="修改失败,请检查该用户是否存在")
  50. def delete(self,request,uid):
  51. models.User.objects.get(pk=uid).delete()
  52. return CommonResponse(status=100,data="删除成功",errors=None)

问题发现

   在上述代码中,问题有以下几点:

  1. 重复代码多,在每个接口中都需要书写ORM查询
  2. 每个接口都需要针对同一个序列类做出不同的实例化

GenericAPIView

继承关系

   GenericAPIView的导入如下:

  1. from rest_framework.generics import GenericAPIView

   以下是它的继承关系:

  

   可以发现它是对APIView的继承,所以理论上来说应该又多了一些东西。

源码阅读

   下面来看一下GenericAPIView的源码,首先你可以发现大概有4个类属性:

  1. class GenericAPIView(views.APIView):
  2. queryset = None # 要查询的数据表
  3. serializer_class = None # 执行序列化的序列化类
  4. lookup_field = 'pk' # 查询时的查询条件,默认按主键查询
  5. lookup_url_kwarg = None # 如果在视图中,url捕获的查询数据表过滤参数不是pk,你应该进行声明

   接着往下看,其实它的方法很少,对外暴露的方法就更少了。

  

   我们这里就先看最常用的,即对外暴露的方法,首先是get_queryset()

  1. def get_queryset(self):
  2. assert self.queryset is not None, (
  3. "'%s' should either include a `queryset` attribute, "
  4. "or override the `get_queryset()` method."
  5. % self.__class__.__name__
  6. ) # 做验证,即实例属性queryset不能是空,代表这个类属性你必须要声明,你可以选择将它做成类属性也可以做成实例属性
  7. queryset = self.queryset # 进行赋值,将self.queryset赋值为类属性。先在UserAPI的实例中找,找不到再到UserAPI的类中找
  8. if isinstance(queryset, QuerySet):
  9. queryset = queryset.all() # 如果它是一个QuerySET对象,就获取全部,得到一个QuerySetDict对象
  10. return queryset # 进行返回

   看到这里发现了一个点,即queryset这个属性必须要进行赋值,由于属性查找顺序是先查找实例,而后查找类本身,所以我们直接在UserAPI中声明queryset为类属性即可。

   接下来继续继续看,get_object(),见明知意,它可以从数据表中获取单个对象:

  1. def get_object(self):
  2. queryset = self.filter_queryset(self.get_queryset()) # 首先会运行get_queryset(),获取一个所有对象的列表,然后进行filter过滤
  3. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field # 这里是对url中获取到的变量进行映射
  4. assert lookup_url_kwarg in self.kwargs, ( # 比如,url中获取到的名为uid,如果uid没有在kwargs中,即是{uid:4}中,则抛出异常
  5. 'Expected view %s to be called with a URL keyword argument '
  6. 'named "%s". Fix your URL conf, or set the `.lookup_field` '
  7. 'attribute on the view correctly.' %
  8. (self.__class__.__name__, lookup_url_kwarg)
  9. )
  10. filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} # 进行查询替换,默认的self.lookup_field是pk,将uid替换为pk。那么这里就是{pk:4}
  11. obj = get_object_or_404(queryset, **filter_kwargs) # 获取对象
  12. self.check_object_permissions(self.request, obj) # 进行验证权限
  13. return obj # 返回单个对象

   看到这里就发现了,默认查询条件是用pk,也就是说你的url中必须要用pk这个形参名进行分组捕获。否则就需要声明lookup_url_kwarg,即lokup_url_kwarg="uid",然后进行替换组建filter_kwargs。当然如果你的查询条件不是用的pk,就需要修改lookup_field为字段名,如我不是按照pk进行查询,而是按照name,就修改lookup_fieldname

  1. re_path('^api/users/(?P<uid>\d+)?',views.UserAPI.as_view())

   接下来再看另一个方法get_serializer()

  1. def get_serializer(self, *args, **kwargs):
  2. serializer_class = self.get_serializer_class() # 内部调get_serializer_class
  3. kwargs.setdefault('context', self.get_serializer_context()) # 获取context属性
  4. return serializer_class(*args, **kwargs) # 调用serializer_class并返回

   接下来是get_serializer_class()方法:

  1. def get_serializer_class(self):
  2. assert self.serializer_class is not None, ( # 传入的必须不能是None
  3. "'%s' should either include a `serializer_class` attribute, "
  4. "or override the `get_serializer_class()` method."
  5. % self.__class__.__name__
  6. )
  7. return self.serializer_class # 返回设置的属性,serializer_class,即序列化类

   OK,其实源代码读到这里就行了。

封装特性

   通过上面的源代码分析,总结出如下方法的使用:

方法/属性 描述
queryset 将要查询的数据表,类型应该是QuerySet
serializer_class 将要执行的序列化类,类型不能为None
lookup_field 查询时的查询条件,默认为pk
lookup_url_kwarg 视图中url捕获的查询条件变量名如果不是pk,则应该进行指定
get_queryset() 查询获取所有记录
get_object() 查询获取单条记录
get_serializer() 执行序列化对象

   关于最常用的调用方法就三个,常用属性四个。

   其他的方法基本上都是内部调用,所以暂时不深究。

接口书写

   接下来使用GenericAPIView进行接口书写。

  1. from rest_framework.response import Response
  2. from rest_framework.generics import GenericAPIView
  3. from . import models
  4. from . import ser
  5. class ResponseMeta(type):
  6. # 对Response类做封装
  7. def __call__(cls, *args, **kwargs):
  8. obj = cls.__new__(cls, *args, **kwargs)
  9. cls.__init__(obj, *args, **kwargs)
  10. return Response(data=obj.__dict__)
  11. class CommonResponse(object, metaclass=ResponseMeta):
  12. # 返回的信息
  13. def __init__(self, status, data=None, errors=None):
  14. self.status = status
  15. self.data = data
  16. self.errors = errors
  17. class UserAPI(GenericAPIView):
  18. queryset = models.User.objects # 传入对象即可
  19. serializer_class = ser.UserModelSerializers # 序列化类
  20. lookup_field = "pk"
  21. lookup_url_kwarg = "uid" # 由于捕获的是uid,需要声明
  22. def get(self, request, uid=None):
  23. if not uid:
  24. # 获取所有
  25. user_queryset = self.get_queryset() # 获取所有
  26. if user_queryset.exists():
  27. serialization = self.get_serializer(instance=user_queryset,many=True) # 获取序列化类,序列化多条
  28. return CommonResponse(status=100, data=serialization.data, errors=None)
  29. return CommonResponse(status=200, errors="暂时没有任何学生")
  30. else:
  31. user_obj = self.get_object()
  32. if user_obj:
  33. serialization = self.get_serializer(instance=user_obj)
  34. return CommonResponse(status=100, data=serialization.data, errors=None)
  35. return CommonResponse(status=200, errors="没有该学生")
  36. def post(self, request):
  37. serialization = self.get_serializer(data=request.data)
  38. if serialization.is_valid():
  39. serialization.save()
  40. return CommonResponse(status=100, data=serialization.data, errors=None)
  41. return CommonResponse(status=200, errors=serialization.errors)
  42. def patch(self, request, uid):
  43. user_obj = self.get_object()
  44. if user_obj:
  45. serialization = self.get_serializer(instance=user_obj,data=request.data)
  46. if serialization.is_valid():
  47. serialization.save()
  48. return CommonResponse(status=100, data=serialization.data, errors=None)
  49. else:
  50. return CommonResponse(status=200, errors="修改失败,请检查字段是否一直")
  51. else:
  52. return CommonResponse(status=200, errors="修改失败,请检查该用户是否存在")
  53. def delete(self,request,uid):
  54. self.get_object().delete()
  55. return CommonResponse(status=100,data="删除成功",errors=None)

问题发现

   相对于使用APIView来说,它不必再手动去写ORM语句。

   但是对于返回信息、对于验证操作还是要自己写。

mixins中扩展类

五个扩展类

   下面是rest_framework.mixins中的五个扩展类,它们做了更高级别的封装,配合GenericAPIView使用有奇效。

  1. from rest_framework.mixins import ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
描述
ListModelMixin 该类主要负责查询所有记录
RetrieveModelMixin 该类主要负责查询单条记录
CreateModelMixin 该类主要负责创建记录
UpdateModelMixin 该类主要负责对记录做更新操作
DestroyModelMixin 该类主要负责删除记录

继承关系

   这五个类都继承于object,是独立的子类。

  

源码阅读

   下面是ListModelMixin的源码,不难发现,它就是配合GenericAPIView使用的,因为它会使用get_queryset()方法,并且,它会自动的返回Response对象,并把验证结果添加进去:

  1. class ListModelMixin:
  2. def list(self, request, *args, **kwargs):
  3. queryset = self.filter_queryset(self.get_queryset())
  4. page = self.paginate_queryset(queryset)
  5. if page is not None:
  6. serializer = self.get_serializer(page, many=True)
  7. return self.get_paginated_response(serializer.data)
  8. serializer = self.get_serializer(queryset, many=True)
  9. return Response(serializer.data)

   至于其他几个类,其实都差不多,这里摘出两个比较特别的类来看一下,分别是CreateModelMixinDestroyModelMixin这两个类。

   下面是CreateModelMixin类的源码:

  1. class CreateModelMixin:
  2. def create(self, request, *args, **kwargs):
  3. serializer = self.get_serializer(data=request.data)
  4. serializer.is_valid(raise_exception=True)
  5. self.perform_create(serializer) # 内部进行序列化类保存
  6. headers = self.get_success_headers(serializer.data) # 返回一个location请求头
  7. return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) # 注意返回结果,状态码是201
  8. def perform_create(self, serializer):
  9. serializer.save()
  10. def get_success_headers(self, data):
  11. try:
  12. return {'Location': str(data[api_settings.URL_FIELD_NAME])}
  13. except (TypeError, KeyError):
  14. return {}

   下面是DestroyModelMixin类的源码:

  1. class DestroyModelMixin:
  2. def destroy(self, request, *args, **kwargs):
  3. instance = self.get_object()
  4. self.perform_destroy(instance) # 内部执行删除
  5. return Response(status=status.HTTP_204_NO_CONTENT) # 返回状态码204
  6. def perform_destroy(self, instance):
  7. instance.delete()

   那么读这两个类的源码,就是想要让你知道,创建成功后的返回状态码是201,而删除成功的返回状态码是204。这在REST规范中写的很清楚,可以看见这里也是这么做的。

类与方法

   下面是不同的五个扩展类中不同的五个方法,功能与类一样。

方法 描述
ListModelMixin list() 查询所有,并返回Response对象
RetrieveModelMixin retrieve() 查询单条,并返回Response对象
CreateModelMixin create() 创建记录,并返回Response对象
UpdateModelMixin update() 更新记录,并返回Response对象
DestroyModelMixin destroy() 删除记录,并返回Response对象

   由于它会自动进行return Response(),所以我们就不用再对返回对象进行包装了。

接口书写

   下面是利用GenericAPIViewmixins中的五个扩展类进行接口书写。

  1. from . import models
  2. from . import ser
  3. from rest_framework.generics import GenericAPIView
  4. from rest_framework.mixins import ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
  5. class UserAPI(GenericAPIView,ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin):
  6. queryset = models.User.objects # 传入对象即可
  7. serializer_class = ser.UserModelSerializers # 序列化类
  8. lookup_field = "pk"
  9. lookup_url_kwarg = "uid" # 由于捕获的是uid,需要声明
  10. def get(self, request, uid=None):
  11. if not uid:
  12. # 获取所有
  13. return self.list(request)
  14. else:
  15. return self.retrieve(request,uid)
  16. def post(self, request):
  17. return self.create(request)
  18. def patch(self, request, uid):
  19. return self.update(request,uid)
  20. def delete(self,request,uid):
  21. return self.destroy(request,uid)

问题发现

   可以看见,代码相比于前两个少了非常非常多。但是还是存在一些问题。

   第一个问题就是这个视图UserAPI继承的类太多了,太长了,其次就是每次都需要在视图中return,它能不能帮我们自己return呢?那这个就非常舒服了。

modelViewSet

基本使用

   modelViewSet是针对GenericAPIViewmixins中扩展类的结合使用做了一些优化,它可以根据不同的请求自动的做出回应。

   同时也不再需要你在视图中进行return。以下是基本使用方法,但是使用它时我们需要对路由做一些改进,具体的情况等下面的源码分析后你就明白了:

  1. urlpatterns = [
  2. path('admin/', admin.site.urls),
  3. path('api/users/', views.UserAPI.as_view(actions={"get":"list","post":"create"})),
  4. re_path('^api/users/(?P<uid>\d+)?',views.UserAPI.as_view(actions={"get":"retrieve","patch":"update","delete":"destroy"}))
  5. ]

   那么在views.py中,书写的话很简单:

  1. from . import models
  2. from . import ser
  3. from rest_framework.viewsets import ModelViewSet
  4. class UserAPI(ModelViewSet):
  5. queryset = models.User.objects # 传入对象即可
  6. serializer_class = ser.UserModelSerializers # 序列化类
  7. lookup_field = "pk"
  8. lookup_url_kwarg = "uid" # 由于捕获的是uid,需要声明

继承关系

   ModelViewSet的导入如下:

  1. from rest_framework.viewsets import ModelViewSet

   你可看它的源码,它其实也没什么特别之处,就是针对上面第一个问题做了改进。但是你会发现,它会继承一个新的类,即GenericViewSet这个类。

  1. class ModelViewSet(mixins.CreateModelMixin,
  2. mixins.RetrieveModelMixin,
  3. mixins.UpdateModelMixin,
  4. mixins.DestroyModelMixin,
  5. mixins.ListModelMixin,
  6. GenericViewSet):
  7. """
  8. A viewset that provides default `create()`, `retrieve()`, `update()`,
  9. `partial_update()`, `destroy()` and `list()` actions.
  10. """
  11. pass

   下面是它的继承图:

  

   那么GenericViewSet中又会有什么新的发现呢?我们先看一看它。

GenericViewSet

   打开GenericViewSet中发现什么都没有。但是它继承了ViewSetMixin

  1. class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
  2. """
  3. The GenericViewSet class does not provide any actions by default,
  4. but does include the base set of generic view behavior, such as
  5. the `get_object` and `get_queryset` methods.
  6. """
  7. pass

ViewSetMixin

   我们可以在上面基本使用时对urlas_view()传参发现了一点不一样的地方,我们传递进了一个关键字参数actions,这个参数非常的蹊跷,因为在APIView中的as_view()方法中并没有为该参数预留位置。

  1. def as_view(cls, **initkwargs):

   我们再接着看看GenericAPIView中的as_view()方法有没有为该参数预留位置,非常遗憾的是在GenericAPIView中根本就没有as_view()方法,说明它用了父类也就是APIViewas_view()方法

   那么只有一个可能,就是ViewSetMixin覆写了as_view()方法,那么到底是不是这么回事?我们看一下就知道了:

  1. class ViewSetMixin:
  2. @classonlymethod
  3. def as_view(cls, actions=None, **initkwargs):

   是的,那么它内部是怎么做的呢?实际上它的核心代码就是那个for循环,它会根据不同的请求方式来执行不同的mixins中五个扩展类的方法,因此我们需要两条url来放入不同的actions。由于modelsViewSet继承了mixins五个扩展类,所以才能够调用扩展类下的方法。

  1. @classonlymethod
  2. def as_view(cls, actions=None, **initkwargs): # cls即为UserAPI这个类
  3. cls.name = None
  4. cls.description = None
  5. cls.suffix = None
  6. cls.detail = None
  7. cls.basename = None
  8. if not actions: # 必须传入actions,否则抛出异常
  9. raise TypeError("The `actions` argument must be provided when "
  10. "calling `.as_view()` on a ViewSet. For example "
  11. "`.as_view({'get': 'list'})`")
  12. for key in initkwargs: # 构造字典,不用管
  13. if key in cls.http_method_names:
  14. raise TypeError("You tried to pass in the %s method name as a "
  15. "keyword argument to %s(). Don't do that."
  16. % (key, cls.__name__))
  17. if not hasattr(cls, key):
  18. raise TypeError("%s() received an invalid keyword %r" % (
  19. cls.__name__, key))
  20. if 'name' in initkwargs and 'suffix' in initkwargs: # 不用管,这个也是构造字典
  21. raise TypeError("%s() received both `name` and `suffix`, which are "
  22. "mutually exclusive arguments." % (cls.__name__))
  23. def view(request, *args, **kwargs): # 闭包函数view
  24. self = cls(**initkwargs)
  25. if 'get' in actions and 'head' not in actions:
  26. actions['head'] = actions['get']
  27. self.action_map = actions
  28. for method, action in actions.items(): # 其实这里是核心代码, actions={"get":"retrieve","patch":"update","delete":"destroy"},或者等于{"get":"list","post":"create"}
  29. handler = getattr(self, action) # 根据请求方式,来执行list、create、retrieve、update、destroy这几个方法
  30. setattr(self, method, handler)
  31. self.request = request
  32. self.args = args
  33. self.kwargs = kwargs
  34. return self.dispatch(request, *args, **kwargs)
  35. update_wrapper(view, cls, updated=()) # 传入执行update_wrapper(),不用管
  36. update_wrapper(view, cls.dispatch, assigned=()) # 不用管
  37. view.cls = cls
  38. view.initkwargs = initkwargs
  39. view.actions = actions
  40. return csrf_exempt(view)

   根据不同的请求方式来执行不同的函数方法,可以说这个设计非常的巧妙,所以你可以像下面这样做:

  1. # views.py
  2. from rest_framework.viewsets import ViewSetMixin
  3. class Book6View(ViewSetMixin,APIView): # 一定要放在APIVIew前,因为as_view()的查找顺序一定要先是ViewSetMixin
  4. def get_all_book(self,request):
  5. print("xxxx")
  6. book_list = Book.objects.all()
  7. book_ser = BookSerializer(book_list, many=True)
  8. return Response(book_ser.data)
  9. # urls.py
  10. #继承ViewSetMixin的视图类,路由可以改写成这样
  11. path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),

drf 视图使用及源码分析的更多相关文章

  1. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  2. 探索drf执行流程之APIView源码分析

    Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...

  3. drf 简介以及部分源码分析

    目录 复习 drf框架 全称:django-rest framework 知识点 接口 restful接口规范 基于restful规范的原生Django接口 主路由:url.py api组件的子路由: ...

  4. drf 认证校验及源码分析

    认证校验 认证校验是十分重要的,如用户如果不登陆就不能访问某些接口. 再比如用户不登陆就不能够对一个接口做哪些操作. drf中认证的写法流程如下: 1.写一个类,继承BaseAuthenticatio ...

  5. DRF中的APIView源码分析

    首先写一个简单的drf接口 from rest_framework.views import APIView from rest_framework.response import Response ...

  6. cvb源码分析,resful规范,drf,drf序列化组件,95

    1 CBV的源码分析 -Class Base View(基于类的视图) -Function Base View(基于函数的视图) -def as_view 类方法 -def view:类方法内部,闭包 ...

  7. DRF之视图类(mixin)源码解析

     同样的增删改查操作,如果我们还像之前序列化组件那样做,代码重复率过多,所以我们用视图表示: 具体源码实现:首先定义一个视图类,然后根据mixin点进去有五个封装好的方法,这五个方法共有的属性就是都需 ...

  8. drf源码分析系列---节流(访问频率限制)

    使用 from rest_framework.throttling import AnonRateThrottle from rest_framework.generics import ListAP ...

  9. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...

随机推荐

  1. xss利用——BeEF#stage4(其余功能介绍)

    目录 信息收集 => 社会工程 =>网络扫描 => 结合metasploit => tunneling => xss => 维持权限 功能介绍 #1 - 信息收集 ...

  2. IntelliJ IDEA 2020.2 x64 最新破解教程有效期到2089年 完全免费分享

    作者:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,原创文章, B站技术分享 B站视频 : Bilibili.com 个 ...

  3. Python练习题 001:4个数字求不重复的3位数

    听说做练习是掌握一门编程语言的最佳途径,那就争取先做满100道题吧. ----------------------------------------------------------------- ...

  4. 086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结

    086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结 本文知识点:面向对象基础(类和对象)总结 说明 ...

  5. 072 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 04 综合案例-数组移位-在指定位置处插入数据方法

    072 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 04 综合案例-数组移位-在指定位置处插入数据方法 本文知识点:综合案例-数组移位-在指定位置处插入数据方法 ...

  6. MATLAB中exist函数的用法

    exist:exist主要有两种形式,一个参数和两个参数的,作用都是用于确定某值是否存在:1. b = exist( a)      若 a 存在,则 b = 1: 否则 b = 0:2. b = e ...

  7. # vue 如何通过前端来导出excel表格

    在做一些简单的demo时,偶尔会遇到导出excel表格.如果请后端帮忙的话 比较浪费时间,那么前端如何导出excel表格,下面就来记录一下之前使用到的案例 一.安装依赖 npm i file-save ...

  8. Apple uses Multipath TCP

    http://blog.multipath-tcp.org/blog/html/2018/12/15/apple_and_multipath_tcp.html December 15, 2018 Ap ...

  9. 【idea&spring mvc】搭建简易的spring mvc项目(基于maven)!

    一.创建项目 1.打开idea,file--new--project 2.按照步骤①②③④操作 3.输入包名,并点击下一步 4.选择下载包的maven的setting.xml配置路径和包的存放地,然后 ...

  10. MeteoInfoLab脚本示例:Maskout图形

    Maskout通常有两种类型:Maskout图形和Maskout数据.这里是Maskout图形的示例.需要用shaperead读取地图数据形成图层作为Maskout图层(这里是中国的行政区域china ...