CBV&APIView

  1. '''原生django as_view方法'''
  2. class View(object):
  3.  
  4. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] #用于判断请求方式是否符合http协议规定
  5.  
  6. @classonlymethod
  7. def as_view(cls, **initkwargs):
  8.  
  9. for key in initkwargs:
  10. if key in cls.http_method_names:
  11. raise TypeError("You tried to pass in the %s method name as a "
  12. "keyword argument to %s(). Don't do that."
  13. % (key, cls.__name__))
  14. if not hasattr(cls, key):
  15. raise TypeError("%s() received an invalid keyword %r. as_view "
  16. "only accepts arguments that are already "
  17. "attributes of the class." % (cls.__name__, key))
  18.  
  19. def view(request, *args, **kwargs): #定义一个view函数
  20. self = cls(**initkwargs) #实例化该类 生成对象
  21. if hasattr(self, 'get') and not hasattr(self, 'head'):
  22. self.head = self.get
  23. self.request = request
  24. self.args = args
  25. self.kwargs = kwargs
  26. return self.dispatch(request, *args, **kwargs) #view函数返回View对象的dispatch方法 在此进入dispatch方法
  27. view.view_class = cls
  28. view.view_initkwargs = initkwargs
  29.  
  30. update_wrapper(view, cls, updated=())
  31.  
  32. update_wrapper(view, cls.dispatch, assigned=())
  33. return view
  34.  
  35. '''APIView类'''
  36. class APIView(View):
  37. renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES #如果CBV中没有给这些参数赋值 则使用drf setting文件中的默认值
  38. parser_classes = api_settings.DEFAULT_PARSER_CLASSES
  39. authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #认证组件
  40. throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES #频率组件
  41. permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #权限组件
  42. content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
  43. metadata_class = api_settings.DEFAULT_METADATA_CLASS
  44. versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
  45.  
  46. settings = api_settings
  47. '''as_view'''
  48.  
  49. def as_view(cls, **initkwargs):
  50.  
  51. if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
  52. def force_evaluation():
  53. raise RuntimeError(
  54. 'Do not evaluate the `.queryset` attribute directly, '
  55. 'as the result will be cached and reused between requests. '
  56. 'Use `.all()` or call `.get_queryset()` instead.'
  57. )
  58. cls.queryset._fetch_all = force_evaluation
  59.  
  60. view = super(APIView, cls).as_view(**initkwargs) #继承原生view的as_view方法 按原生view 会走到dispatch方法中
  61. view.cls = cls
  62. view.initkwargs = initkwargs
  63.  
  64. return csrf_exempt(view) #装饰器csrf_exempt可以取消APIView的csrf认证 该方法也可以在视图中使用取消指定视图函数的csrf认证
  65.  
  66. '''dispatch'''
  67.  
  68. def dispatch(self, request, *args, **kwargs):
  69.  
  70. self.args = args
  71. self.kwargs = kwargs
  72. request = self.initialize_request(request, *args, **kwargs) #将原生request对象封装为drf request对象
  73. self.request = request
  74. self.headers = self.default_response_headers
  75.  
  76. try:
  77. self.initial(request, *args, **kwargs) #走drf request对象中的版本控制/认证/权限/频率组件
  78.  
  79. if request.method.lower() in self.http_method_names: #http_method_names=['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
  80. handler = getattr(self, request.method.lower(),
  81. self.http_method_not_allowed) #与原生view一样用反射调用与请求响应的视图函数
  82. else:
  83. handler = self.http_method_not_allowed #请求方式错误报异常
  84.  
  85. response = handler(request, *args, **kwargs)
  86.  
  87. except Exception as exc: #request中的各组件抛出的异常都在这被捕获
  88. response = self.handle_exception(exc) #handle_exception中调用过认证组件的authenticate_header方法 所以认证组件必须有该方法
  89.  
  90. self.response = self.finalize_response(request, response, *args, **kwargs)
  91. return self.response
  92.  
  93. '''initialize_request'''
  94.  
  95. def initialize_request(self, request, *args, **kwargs):
  96.  
  97. parser_context = self.get_parser_context(request)
  98.  
  99. return Request( #用Request类封装原生request对象
  100. request,
  101. parsers=self.get_parsers(),
  102. authenticators=self.get_authenticators(), #get_authenticators 内部以列表生成式的方式调用配置的认证组件
  103. parser_context=parser_context
  104. )
  105.  
  106. def get_authenticators(self):
  107. #以列表生成式的方式调用配置的认证组件 authentication_classes中为认证组件的类加上()实例化为对象
  108. #然后返回都是认证组件对象的列表
  109. return [auth() for auth in self.authentication_classes]
  110.  
  111. '''Request对象'''
  112. class Response(SimpleTemplateResponse):
  113. def __init__(self, request, parsers=None, authenticators=None,
  114. negotiator=None, parser_context=None):
  115. assert isinstance(request, HttpRequest), (
  116. 'The `request` argument must be an instance of '
  117. '`django.http.HttpRequest`, not `{}.{}`.'
  118. .format(request.__class__.__module__, request.__class__.__name__)
  119. )
  120.  
  121. self._request = request #调用_request来获取原生request对象
  122. self.parsers = parsers or ()
  123. self.authenticators = authenticators or () #一系列赋值操作来封装request
  124. self.negotiator = negotiator or self._default_negotiator()
  125. self.parser_context = parser_context
  126. self._data = Empty
  127. self._files = Empty
  128. self._full_data = Empty
  129. self._content_type = Empty
  130. self._stream = Empty
  131.  
  132. if self.parser_context is None:
  133. self.parser_context = {}
  134. self.parser_context['request'] = self
  135. self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
  136.  
  137. force_user = getattr(request, '_force_auth_user', None)
  138. force_token = getattr(request, '_force_auth_token', None)
  139. if force_user is not None or force_token is not None:
  140. forced_auth = ForcedAuthentication(force_user, force_token)
  141. self.authenticators = (forced_auth,)
  142.  
  143. @property
  144. def user(self):
  145.  
  146. if not hasattr(self, '_user'):
  147. with wrap_attributeerrors():
  148. self._authenticate()
  149. return self._user
  150.  
  151. def _authenticate(self):
  152.  
  153. for authenticator in self.authenticators: #authenticators是认证组件对象的列表
  154. try:
  155. user_auth_tuple = authenticator.authenticate(self) #启用认证组件调用组件中的authenticate方法 所以自定义认证组件时必须定义此方法
  156. except exceptions.APIException:
  157. self._not_authenticated()
  158. raise
  159.  
  160. if user_auth_tuple is not None: #user_auth_tuple为None 说明组件中的authenticate方法返回None 此代码块不走该次循环的认证组件
  161. self._authenticator = authenticator
  162. self.user, self.auth = user_auth_tuple #自定义的认证组件必须返回两个值 第一个值一般为用户名或token
  163. return #认证组件有返回值 直接退出该函数
  164.  
  165. self._not_authenticated() #如果所有组件返回值都为None 走此方法
  166.  
  167. def _not_authenticated(self):
  168.  
  169. self._authenticator = None
  170.  
  171. if api_settings.UNAUTHENTICATED_USER:
  172. self.user = api_settings.UNAUTHENTICATED_USER() # 所有认证组件均没有返回值,则user使用默认配置为匿名用户
  173. else:
  174. self.user = None
  175.  
  176. if api_settings.UNAUTHENTICATED_TOKEN:
  177. self.auth = api_settings.UNAUTHENTICATED_TOKEN()
  178. else:
  179. self.auth = None
  180.  
  181. '''initial'''
  182.  
  183. def initial(self, request, *args, **kwargs):
  184.  
  185. self.format_kwarg = self.get_format_suffix(**kwargs)
  186.  
  187. neg = self.perform_content_negotiation(request)
  188. request.accepted_renderer, request.accepted_media_type = neg
  189.  
  190. version, scheme = self.determine_version(request, *args, **kwargs)
  191. request.version, request.versioning_scheme = version, scheme #版本控制放回版本号
  192.  
  193. self.perform_authentication(request) #启用认证 调用request.user
  194. self.check_permissions(request) #启用权限 同样以列表生成式的方式调用配置
  195. self.check_throttles(request) #启用频率 同样以列表生成式的方式调用配置

权限&频率组件

  1. def initial(self, request, *args, **kwargs):
  2.  
  3. self.format_kwarg = self.get_format_suffix(**kwargs)
  4.  
  5. neg = self.perform_content_negotiation(request)
  6. request.accepted_renderer, request.accepted_media_type = neg
  7.  
  8. version, scheme = self.determine_version(request, *args, **kwargs)
  9. request.version, request.versioning_scheme = version, scheme
  10.  
  11. self.perform_authentication(request) #认证
  12. self.check_permissions(request) #权限
  13. self.check_throttles(request) #频率
  14.  
  15. '''check_permissions'''
  16.  
  17. def check_permissions(self, request):
  18.  
  19. for permission in self.get_permissions(): #get_permissions函数返回值做for循环
  20. if not permission.has_permission(request, self): #执行组件对象中的has_permission方法 判断返回值是T/F 所以权限组件必须写has_permission方法并返回Ture或False
  21. self.permission_denied(
  22. request, message=getattr(permission, 'message', None) #权限组件未通过抛异常 可自定message
  23. )
  24.  
  25. def get_permissions(self):
  26. #与认证组件一个套路
  27. return [permission() for permission in self.permission_classes]
  28.  
  29. '''check_throttles'''
  30. #套路基本一样
  31. def check_throttles(self, request):
  32.  
  33. for throttle in self.get_throttles(): #get_throttles返回列表
  34. if not throttle.allow_request(request, self): #执行allow_request 返回T/F
  35. self.throttled(request, throttle.wait()) #频率组件必须定义allow_request 与 wait 两个方法
  36.  
  37. def get_throttles(self):
  38. #老套路
  39. return [throttle() for throttle in self.throttle_classes]

内置频率组件

  1. def check_throttles(self, request):
  2.  
  3. for throttle in self.get_throttles():
  4. if not throttle.allow_request(request, self):
  5. self.throttled(request, throttle.wait()) #频率组件中的wait方法
  6.  
  7. '''BaseThrottle 内置频率组件基类'''
  8.  
  9. def get_ident(self, request): #获取唯一标示
  10.  
  11. xff = request.META.get('HTTP_X_FORWARDED_FOR') #识别代理ip时获取用户本机ip
  12. remote_addr = request.META.get('REMOTE_ADDR') #获取客户端ip
  13. num_proxies = api_settings.NUM_PROXIES
  14.  
  15. if num_proxies is not None:
  16. if num_proxies == 0 or xff is None:
  17. return remote_addr
  18. addrs = xff.split(',')
  19. client_addr = addrs[-min(num_proxies, len(addrs))]
  20. return client_addr.strip()
  21.  
  22. return ''.join(xff.split()) if xff else remote_addr #一般xff为None 返回remote_addr
  23.  
  24. '''SimpleRateThrottle 简单频率组件'''
  25.  
  26. class SimpleRateThrottle(BaseThrottle):
  27.  
  28. cache = default_cache
  29. timer = time.time
  30. cache_format = 'throttle_%(scope)s_%(ident)s'
  31. scope = None
  32. THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES #配置
  33.  
  34. def __init__(self): #实例化对象先走init方法
  35. if not getattr(self, 'rate', None): #用反射的方式获取rate
  36. self.rate = self.get_rate() #没有rate 走get_rate方法
  37. self.num_requests, self.duration = self.parse_rate(self.rate) #走parse_rate
  38.  
  39. def get_rate(self):
  40.  
  41. if not getattr(self, 'scope', None): #获取scope scope没有值抛出异常 所以组件需要给scope赋值
  42. msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
  43. self.__class__.__name__)
  44. raise ImproperlyConfigured(msg)
  45.  
  46. try:
  47. return self.THROTTLE_RATES[self.scope] #返回THROTTLE_RATES 为配置信息中的key为self.scope的值 赋值给rate
  48. except KeyError:
  49. msg = "No default throttle rate set for '%s' scope" % self.scope
  50. raise ImproperlyConfigured(msg)
  51.  
  52. def parse_rate(self, rate):
  53.  
  54. if rate is None:
  55. return (None, None)
  56. num, period = rate.split('/') #将rate做字符串分隔
  57. num_requests = int(num)
  58. duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
  59. return (num_requests, duration) #最后返回数字 与 秒的倍数
  60.  
  61. def allow_request(self, request, view):
  62.  
  63. if self.rate is None:
  64. return True
  65.  
  66. self.key = self.get_cache_key(request, view) #改写get_cache_key方法使用get_ident方法获取客户端ip
  67. if self.key is None:
  68. return True
  69.  
  70. self.history = self.cache.get(self.key, []) #缓存中的访问列表 值为时间戳或时间戳列表
  71. self.now = self.timer() #当前时间戳
  72.  
  73. while self.history and self.history[-1] <= self.now - self.duration: #如果访问时间超过指定的时间 删掉最早的一次访问记录
  74. self.history.pop()
  75. if len(self.history) >= self.num_requests: #如果访问次数超过指定次数 返回False限制访问
  76. return self.throttle_failure()
  77. return self.throttle_success()
  78.  
  79. def throttle_success(self): #所有验证通过返回True
  80.  
  81. self.history.insert(0, self.now)
  82. self.cache.set(self.key, self.history, self.duration) #将本次访问记录在缓存中
  83. return True

版本控制组件

  1. def initial(self, request, *args, **kwargs):
  2.  
  3. self.format_kwarg = self.get_format_suffix(**kwargs)
  4.  
  5. neg = self.perform_content_negotiation(request)
  6. request.accepted_renderer, request.accepted_media_type = neg
  7.  
  8. version, scheme = self.determine_version(request, *args, **kwargs) #版本控制 返回两个值
  9. request.version, request.versioning_scheme = version, scheme #赋值操作
  10.  
  11. self.perform_authentication(request)
  12. self.check_permissions(request)
  13. self.check_throttles(request)
  14.  
  15. def determine_version(self, request, *args, **kwargs):
  16.  
  17. if self.versioning_class is None: #versioning_class可以配置
  18. return (None, None)
  19. scheme = self.versioning_class() #处理版本的对象
  20. return (scheme.determine_version(request, *args, **kwargs), scheme) #scheme.determine_version()为版本控制组件中的determine_version方法
  21.  
  22. '''内置QueryParameterVersioning组件'''
  23.  
  24. class BaseVersioning(object):
  25. default_version = api_settings.DEFAULT_VERSION #默认版本
  26. allowed_versions = api_settings.ALLOWED_VERSIONS #允许出现的版本
  27. version_param = api_settings.VERSION_PARAM #版本参数
  28.  
  29. def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
  30. return _reverse(viewname, args, kwargs, request, format, **extra)
  31.  
  32. class QueryParameterVersioning(BaseVersioning):
  33.  
  34. invalid_version_message = _('Invalid version in query parameter.')
  35.  
  36. def determine_version(self, request, *args, **kwargs):
  37. version = request.query_params.get(self.version_param, self.default_version) #原生request.GET 中的version_param version_param可配置
  38. if not self.is_allowed_version(version):
  39. raise exceptions.NotFound(self.invalid_version_message)
  40. return version
  41.  
  42. def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
  43. url = super(QueryParameterVersioning, self).reverse(
  44. viewname, args, kwargs, request, format, **extra
  45. )
  46. if request.version is not None:
  47. return replace_query_param(url, self.version_param, request.version)
  48. return url
  49.  
  50. @property
  51. def query_params(self):
  52. #request对象中的方法 返回原生request中GET请求的数据
  53. return self._request.GET
  54.  
  55. def is_allowed_version(self, version):
  56. if not self.allowed_versions:
  57. return True
  58. return ((version is not None and version == self.default_version) or #判断版本号是否在允许的版本中
  59. (version in self.allowed_versions))

解析器

  1. request.data
  2.  
  3. @property
  4. def data(self):
  5. if not _hasattr(self, '_full_data'):
  6. self._load_data_and_files()
  7. return self._full_data #返回data数据
  8.  
  9. def _load_data_and_files(self):
  10.  
  11. if not _hasattr(self, '_data'):
  12. self._data, self._files = self._parse() #解析
  13. if self._files: #_files一般不会有值
  14. self._full_data = self._data.copy()
  15. self._full_data.update(self._files)
  16. else:
  17. self._full_data = self._data #赋值
  18.  
  19. if is_form_media_type(self.content_type):
  20. self._request._post = self.POST
  21. self._request._files = self.FILES
  22.  
  23. '''Request'''
  24. def initialize_request(self, request, *args, **kwargs):
  25.  
  26. parser_context = self.get_parser_context(request)
  27.  
  28. return Request(
  29. request,
  30. parsers=self.get_parsers(), #封装request时传入解析器对象 内部赋值给self.parser
  31. authenticators=self.get_authenticators(),
  32. negotiator=self.get_content_negotiator(),
  33. parser_context=parser_context
  34. )
  35.  
  36. def get_parsers(self):
  37. #也是老套路
  38. return [parser() for parser in self.parser_classes]
  39.  
  40. '''parse解析'''
  41.  
  42. def _parse(self):
  43.  
  44. media_type = self.content_type #获取客户端META中的 CONTENT_TYPE :* Content-Type: text/html;charset=utf-8
  45. try:
  46. stream = self.stream
  47. except RawPostDataException:
  48. if not hasattr(self._request, '_post'):
  49. raise
  50.  
  51. if self._supports_form_parsing():
  52. return (self._request.POST, self._request.FILES)
  53. stream = None
  54.  
  55. if stream is None or media_type is None:
  56. if media_type and is_form_media_type(media_type):
  57. empty_data = QueryDict('', encoding=self._request._encoding)
  58. else:
  59. empty_data = {}
  60. empty_files = MultiValueDict()
  61. return (empty_data, empty_files)
  62.  
  63. parser = self.negotiator.select_parser(self, self.parsers) #选择解析器 self.parser为解析器对象列表 返回对应的与数据格式对应的解析器对象
  64.  
  65. if not parser:
  66. raise exceptions.UnsupportedMediaType(media_type)
  67.  
  68. try:
  69. parsed = parser.parse(stream, media_type, self.parser_context) #执行解析器对象中的parse方法 拿到数据
  70. except Exception:
  71. self._data = QueryDict('', encoding=self._request._encoding)
  72. self._files = MultiValueDict()
  73. self._full_data = self._data
  74. raise
  75.  
  76. try:
  77. return (parsed.data, parsed.files)
  78. except AttributeError:
  79. empty_files = MultiValueDict()
  80. return (parsed, empty_files)
  81.  
  82. '''select_parser选择解析器'''
  83.  
  84. def select_parser(self, request, parsers):
  85.  
  86. for parser in parsers:
  87. #获取当前请求的数据类型 与解析器列表中的支持格式对应然后返回相应的解析器对象 如果没有返回None
  88. if media_type_matches(parser.media_type, request.content_type): #parser.media_type 为解析器中支持的数据类型类似media_type = 'application/json'
  89. return parser
  90. return None
  91.  
  92. '''内置JSONParser解析器'''
  93.  
  94. class JSONParser(BaseParser):
  95. media_type = 'application/json'
  96. renderer_class = renderers.JSONRenderer
  97. strict = api_settings.STRICT_JSON
  98.  
  99. def parse(self, stream, media_type=None, parser_context=None):
  100.  
  101. parser_context = parser_context or {}
  102. encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
  103.  
  104. try:
  105. decoded_stream = codecs.getreader(encoding)(stream)
  106. parse_constant = json.strict_constant if self.strict else None
  107. return json.load(decoded_stream, parse_constant=parse_constant) #用json模块解析前端发送来的json数据
  108. except ValueError as exc:
  109. raise ParseError('JSON parse error - %s' % six.text_type(exc))

序列化组件

  1. '''序列化组件构造和初始化'''
  2. class BaseSerializer(Field):
  3.  
  4. def __init__(self, instance=None, data=empty, **kwargs):
  5. self.instance = instance
  6. if data is not empty:
  7. self.initial_data = data
  8. self.partial = kwargs.pop('partial', False)
  9. self._context = kwargs.pop('context', {}) #赋值_context属性
  10. kwargs.pop('many', None)
  11. super(BaseSerializer, self).__init__(**kwargs)
  12.  
  13. def __new__(cls, *args, **kwargs):
  14.  
  15. if kwargs.pop('many', False): #many=True时对queryset进行处理 没有many默认为False
  16. return cls.many_init(*args, **kwargs)
  17. return super(BaseSerializer, cls).__new__(cls, *args, **kwargs) #many=False时以当前实例化对象来处理model对象 构造的是本身做实例化操作的那个类
  18.  
  19. def many_init(cls, *args, **kwargs): #many=True时调用
  20.  
  21. allow_empty = kwargs.pop('allow_empty', None)
  22. child_serializer = cls(*args, **kwargs)
  23. list_kwargs = {
  24. 'child': child_serializer,
  25. }
  26. if allow_empty is not None:
  27. list_kwargs['allow_empty'] = allow_empty
  28. list_kwargs.update({
  29. key: value for key, value in kwargs.items()
  30. if key in LIST_SERIALIZER_KWARGS
  31. })
  32. meta = getattr(cls, 'Meta', None) #取到Meta类
  33. list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) #Meta中没有list_serializer_class字段 则用ListSerializer
  34. return list_serializer_class(*args, **list_kwargs) #内置的ListSerializer组件可以处理queryset对象
  35.  
  36. '''data'''
  37.  
  38. class BaseSerializer(Field):
  39. @property
  40. def data(self):
  41. if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
  42. msg = (
  43. 'When a serializer is passed a `data` keyword argument you '
  44. 'must call `.is_valid()` before attempting to access the '
  45. 'serialized `.data` representation.\n'
  46. 'You should either call `.is_valid()` first, '
  47. 'or access `.initial_data` instead.'
  48. )
  49. raise AssertionError(msg)
  50.  
  51. if not hasattr(self, '_data'):
  52. if self.instance is not None and not getattr(self, '_errors', None):
  53. self._data = self.to_representation(self.instance) #data的值由to_representation方法得到
  54. elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
  55. self._data = self.to_representation(self.validated_data)
  56. else:
  57. self._data = self.get_initial()
  58. return self._data
  59.  
  60. '''serializer'''
  61.  
  62. class Serializer(BaseSerializer):
  63.  
  64. @property
  65. def data(self):
  66. ret = super(Serializer, self).data
  67. return ReturnDict(ret, serializer=self)
  68.  
  69. ===
  70. def to_representation(self, instance):
  71. ret = OrderedDict() #有序字典
  72. fields = self._readable_fields
  73.  
  74. for field in fields: #遍历字段
  75. try:
  76. attribute = field.get_attribute(instance) #调用字段对象的get_attribute方法 -> CharField().get_attribute()
  77. except SkipField:
  78. continue
  79.  
  80. check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
  81. if check_for_none is None:
  82. ret[field.field_name] = None
  83. else:
  84. ret[field.field_name] = field.to_representation(attribute) #执行每个字段的to_representation方法
  85. return ret
  86.  
  87. '''field'''
  88.  
  89. class CharField(Field):
  90. def to_representation(self, value):
  91. return six.text_type(value) #相当于 str(value)
  92.  
  93. #CharField继承Field
  94.  
  95. class Field(object):
  96.  
  97. def get_attribute(self, instance):
  98.  
  99. try:
  100. return get_attribute(instance, self.source_attrs) #instance是传入的对象 source_attrs是source参数用'.'分隔的列表
  101. except (KeyError, AttributeError) as exc:
  102. if self.default is not empty:
  103. return self.get_default()
  104. if self.allow_null:
  105. return None
  106. if not self.required:
  107. raise SkipField()
  108. msg = (
  109. 'Got {exc_type} when attempting to get a value for field '
  110. '`{field}` on serializer `{serializer}`.\nThe serializer '
  111. 'field might be named incorrectly and not match '
  112. 'any attribute or key on the `{instance}` instance.\n'
  113. 'Original exception text was: {exc}.'.format(
  114. exc_type=type(exc).__name__,
  115. field=self.field_name,
  116. serializer=self.parent.__class__.__name__,
  117. instance=instance.__class__.__name__,
  118. exc=exc
  119. )
  120. )
  121. raise type(exc)(msg)
  122.  
  123. def bind(self, field_name, parent):
  124.  
  125. # my_field = serializer.CharField(source='my_field')
  126. assert self.source != field_name, (
  127. "It is redundant to specify `source='%s'` on field '%s' in "
  128. "serializer '%s', because it is the same as the field name. "
  129. "Remove the `source` keyword argument." %
  130. (field_name, self.__class__.__name__, parent.__class__.__name__)
  131. )
  132.  
  133. self.field_name = field_name
  134. self.parent = parent
  135.  
  136. if self.label is None:
  137. self.label = field_name.replace('_', ' ').capitalize()
  138.  
  139. if self.source is None:
  140. self.source = field_name
  141.  
  142. if self.source == '*':
  143. self.source_attrs = []
  144. else:
  145. self.source_attrs = self.source.split('.') #字段source属性可以用'.'来查找的原因
  146.  
  147. def get_attribute(instance, attrs): #该方法为文件中的函数并不是类中的方法,与前一个不同
  148. # -> attrs = ['userdetail', 'pk']
  149. for attr in attrs:
  150. try:
  151. if isinstance(instance, collections.Mapping):
  152. instance = instance[attr]
  153. else:
  154. instance = getattr(instance, attr) #在instance对象中拿attr 覆盖当前instance 多次循环后相当于->user.userdetail.pk
  155. except ObjectDoesNotExist:
  156. return None
  157. if is_simple_callable(instance): #判断是否已经到底 是对象还是属性
  158. try:
  159. instance = instance() #还没到底就帮忙执行
  160. except (AttributeError, KeyError) as exc:
  161. raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc))
  162. return instance
  163.  
  164. '''HyperlinkedRelatedField返回url'''
  165.  
  166. class HyperlinkedRelatedField(RelatedField):
  167. @property
  168. def context(self):
  169. return getattr(self.root, '_context', {}) #将序列化组件中的_context属性赋值给自己
  170.  
  171. def to_representation(self, value):
  172. assert 'request' in self.context, ( #断言在context中有request属性
  173. "`%s` requires the request in the serializer"
  174. " context. Add `context={'request': request}` when instantiating "
  175. "the serializer." % self.__class__.__name__
  176. )
  177.  
  178. request = self.context['request'] #拿到request对象
  179. format = self.context.get('format', None)
  180.  
  181. if format and self.format and self.format != format:
  182. format = self.format
  183.  
  184. try:
  185. url = self.get_url(value, self.view_name, request, format) #get_url 传入对象返回url 将request对象传入
  186. except NoReverseMatch:
  187. msg = (
  188. 'Could not resolve URL for hyperlinked relationship using '
  189. 'view name "%s". You may have failed to include the related '
  190. 'model in your API, or incorrectly configured the '
  191. '`lookup_field` attribute on this field.'
  192. )
  193. if value in ('', None):
  194. value_string = {'': 'the empty string', None: 'None'}[value]
  195. msg += (
  196. " WARNING: The value of the field on the model instance "
  197. "was %s, which may be why it didn't match any "
  198. "entries in your URL conf." % value_string
  199. )
  200. raise ImproperlyConfigured(msg % self.view_name)
  201.  
  202. if url is None:
  203. return None
  204.  
  205. return Hyperlink(url, value)
  206.  
  207. def get_url(self, obj, view_name, request, format):
  208.  
  209. if hasattr(obj, 'pk') and obj.pk in (None, ''):
  210. return None
  211.  
  212. lookup_value = getattr(obj, self.lookup_field) #取obj中的lookup_field属性 __init__方法中赋值了lookup_field 不传默认为'pk'
  213. kwargs = {self.lookup_url_kwarg: lookup_value} #传入lookup_url_kwarg参数为key lookup_field参数为value
  214. return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
  215. #反向解析生成了url
  216.  
  217. '''
  218. 总结:HyperlinkedRelatedField用反向解析的方法获得url
  219. 需要传view_name, lookup_field, lookup_url_kwarg 三个参数
  220. view_name = 路由需要起别名 这个参数传入别名
  221. lookup_field = url是以哪个字段来取到数据的 lookup_field传入那个字段 一般为id #lookup_field = 'userdetail.id'
  222. lookup_url_kwarg = 有名分组的参数名称 #lookup_url_kwarg='pk'
  223.  
  224. 在使用序列化时需要传入context参数 内容{'request': request} #不传会在断言处报错
  225. '''

视图组件

  1. '''GenericAPIView'''
  2.  
  3. class GenericAPIView(views.APIView):
  4. queryset = None #指定queryset
  5. serializer_class = None #指定用哪个序列化组件
  6.  
  7. lookup_field = 'pk'
  8. lookup_url_kwarg = None
  9.  
  10. filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
  11.  
  12. pagination_class = api_settings.DEFAULT_PAGINATION_CLASS #指定用哪个分页器 或全局配置
  13.  
  14. def get_queryset(self):
  15.  
  16. assert self.queryset is not None, ( #不指定queryset对象报错
  17. "'%s' should either include a `queryset` attribute, "
  18. "or override the `get_queryset()` method."
  19. % self.__class__.__name__
  20. )
  21.  
  22. queryset = self.queryset
  23. if isinstance(queryset, QuerySet): #判断是否加上.all() 指定是可以不加.all()
  24. queryset = queryset.all()
  25. return queryset #可以使用get_queryset方法拿到queryset对象
  26.  
  27. def get_serializer(self, *args, **kwargs):
  28.  
  29. serializer_class = self.get_serializer_class() #拿到序列化组件(有点多此一举)
  30. kwargs['context'] = self.get_serializer_context() #自动给序列化对象传上context值
  31. return serializer_class(*args, **kwargs) #可以使用get_serializer方法拿到序列化组件
  32.  
  33. def get_serializer_class(self):
  34. assert self.serializer_class is not None, ( #判断是否指定序列化组件
  35. "'%s' should either include a `serializer_class` attribute, "
  36. "or override the `get_serializer_class()` method."
  37. % self.__class__.__name__
  38. )
  39. return self.serializer_class
  40.  
  41. @property
  42. def paginator(self): #拿到分页器对象
  43. if not hasattr(self, '_paginator'):
  44. if self.pagination_class is None:
  45. self._paginator = None
  46. else:
  47. self._paginator = self.pagination_class()
  48. return self._paginator
  49.  
  50. def paginate_queryset(self, queryset): #使用分页器对象
  51. if self.paginator is None:
  52. return None
  53. return self.paginator.paginate_queryset(queryset, self.request, view=self) #使用paginate_queryset方法使用分页器
  54.  
  55. '''GenericViewSet'''
  56.  
  57. class GenericViewSet(ViewSetMixin, generics.GenericAPIView): #继承了两个类
  58. pass #ViewSetMixin在左边优先度比较高
  59. #GenericAPIView继承了APIView 有视图函数的所有功能
  60.  
  61. '''ViewSetMixin'''
  62.  
  63. class ViewSetMixin(object): #可以使用半自动路由
  64. def initialize_request(self, request, *args, **kwargs): #改写initialize_request封装request对象
  65. request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
  66. method = request.method.lower() #拿到请求方式
  67. if method == 'options':
  68. self.action = 'metadata'
  69. else:
  70. self.action = self.action_map.get(method) #action_map在自己的as_view方法中被赋值 ->{'get':'list'} self.action='list'
  71. return request
  72.  
  73. '''ModelViewSet封装的最后一层封装了增删改查与半自动路由'''
  74.  
  75. class ModelViewSet(mixins.CreateModelMixin,
  76. mixins.RetrieveModelMixin,
  77. mixins.UpdateModelMixin,
  78. mixins.DestroyModelMixin,
  79. mixins.ListModelMixin,
  80. GenericViewSet):
  81. """
  82. A viewset that provides default `create()`, `retrieve()`, `update()`,
  83. `partial_update()`, `destroy()` and `list()` actions.
  84. """
  85. pass

rest_framework源码分析的更多相关文章

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

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

  2. DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用

    CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()),  --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...

  3. Django-rest-framework源码分析----认证

    一.前言 1.1.安装 两种方式: github pip直接安装 pip install django-rest-framework 1.2.需要先了解的一些知识 理解下面两个知识点非常重要,djan ...

  4. Django rest framework源码分析(3)----节流

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  5. Django rest framework源码分析(1)----认证

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  6. Django-restframework 之权限源码分析

    Django-restframework 之权限源码分析 一 前言 上篇博客分析了 restframework 框架的认证组件的执行了流程并自定义了认证类.这篇博客分析 restframework 的 ...

  7. Django-restframework 源码之认证组件源码分析

    Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...

  8. Django rest framework 源码分析 (1)----认证

    一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...

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

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

随机推荐

  1. JavaScript--事件对象(25)

    // JavaScript事件的一个重要的方面是它们拥有一些相对一致的特点,可以给开发提供强大的功能; // 最方便和强大的就是事件对象,它们可以帮你处理鼠标事件和键盘敲击方面的情况; // 此外还可 ...

  2. JS中深浅拷贝 函数封装代码

    一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...

  3. 本地服务器搭建服务:mysql

    话不多少,mysql的优劣不再此讨论. 1.官网地址:https://dev.mysql.com/downloads/mysql/ 下载页面直接  No thanks,just start my do ...

  4. CentOS 修改用户密码

    CentOS 修改用户密码 1.普通用户 ①获取超级用户root权限 命令:su 或者 su- 或者 su -root ②输入命令: passwd 用户名 ③输入新密码 2.超级用户 ①打开syste ...

  5. css 文本两行显示,超出省略号表示

     重点:text-overflow: ellipsis;只对display:inline:起作用 例子: <span class="a">我说说<b class= ...

  6. C语言中数据类型的本质

    数据类型可以理解为固定内存大小的别名.比如int类型,就是表示占用4字节的内存. 1 数据类型的大小 用sizeof操作符获得数据类型的大小. 比如 int a[5];   sizeof(a)就可以得 ...

  7. Expo大作战(二十七)--expo sdk api之Util(expo自带工具类),tackSnapshotAsync,Svg,SQLite

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  8. SublimeText3常用插件及快捷键总结

    SublimeText可谓是前端工程师的代码编辑神器,自从用上它以后一直爱不释手,特别是它强大的插件功能,简直要逆天了.网上也有很多关于SublimeText3的各种插件介绍,其插件功能之多,让人眼花 ...

  9. 获取本机正在使用的ipv4地址(访问互联网的IP)

    [转]原文地址:http://www.cnblogs.com/lijianda/p/6604651.html 1.一个电脑有多个网卡,有线的.无线的.还有vmare虚拟的两个网卡.2.就算只有一个网卡 ...

  10. sysbench使用

      1 部署 1.1 官方主页 https://github.com/Percona-Lab/sysbench-tpcc https://github.com/akopytov/sysbench 1. ...