rest_framework源码分析
CBV&APIView
- '''原生django as_view方法'''
- class View(object):
- http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] #用于判断请求方式是否符合http协议规定
- @classonlymethod
- def as_view(cls, **initkwargs):
- 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. as_view "
- "only accepts arguments that are already "
- "attributes of the class." % (cls.__name__, key))
- def view(request, *args, **kwargs): #定义一个view函数
- self = cls(**initkwargs) #实例化该类 生成对象
- if hasattr(self, 'get') and not hasattr(self, 'head'):
- self.head = self.get
- self.request = request
- self.args = args
- self.kwargs = kwargs
- return self.dispatch(request, *args, **kwargs) #view函数返回View对象的dispatch方法 在此进入dispatch方法
- view.view_class = cls
- view.view_initkwargs = initkwargs
- update_wrapper(view, cls, updated=())
- update_wrapper(view, cls.dispatch, assigned=())
- return view
- '''APIView类'''
- class APIView(View):
- renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES #如果CBV中没有给这些参数赋值 则使用drf setting文件中的默认值
- parser_classes = api_settings.DEFAULT_PARSER_CLASSES
- authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #认证组件
- throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES #频率组件
- permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #权限组件
- content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
- metadata_class = api_settings.DEFAULT_METADATA_CLASS
- versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
- settings = api_settings
- '''as_view'''
- def as_view(cls, **initkwargs):
- 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的as_view方法 按原生view 会走到dispatch方法中
- view.cls = cls
- view.initkwargs = initkwargs
- return csrf_exempt(view) #装饰器csrf_exempt可以取消APIView的csrf认证 该方法也可以在视图中使用取消指定视图函数的csrf认证
- '''dispatch'''
- def dispatch(self, request, *args, **kwargs):
- self.args = args
- self.kwargs = kwargs
- request = self.initialize_request(request, *args, **kwargs) #将原生request对象封装为drf request对象
- self.request = request
- self.headers = self.default_response_headers
- try:
- self.initial(request, *args, **kwargs) #走drf request对象中的版本控制/认证/权限/频率组件
- if request.method.lower() in self.http_method_names: #http_method_names=['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
- handler = getattr(self, request.method.lower(),
- self.http_method_not_allowed) #与原生view一样用反射调用与请求响应的视图函数
- else:
- handler = self.http_method_not_allowed #请求方式错误报异常
- response = handler(request, *args, **kwargs)
- except Exception as exc: #request中的各组件抛出的异常都在这被捕获
- response = self.handle_exception(exc) #handle_exception中调用过认证组件的authenticate_header方法 所以认证组件必须有该方法
- self.response = self.finalize_response(request, response, *args, **kwargs)
- return self.response
- '''initialize_request'''
- def initialize_request(self, request, *args, **kwargs):
- parser_context = self.get_parser_context(request)
- return Request( #用Request类封装原生request对象
- request,
- parsers=self.get_parsers(),
- authenticators=self.get_authenticators(), #get_authenticators 内部以列表生成式的方式调用配置的认证组件
- parser_context=parser_context
- )
- def get_authenticators(self):
- #以列表生成式的方式调用配置的认证组件 authentication_classes中为认证组件的类加上()实例化为对象
- #然后返回都是认证组件对象的列表
- return [auth() for auth in self.authentication_classes]
- '''Request对象'''
- class Response(SimpleTemplateResponse):
- def __init__(self, request, parsers=None, authenticators=None,
- negotiator=None, parser_context=None):
- assert isinstance(request, HttpRequest), (
- 'The `request` argument must be an instance of '
- '`django.http.HttpRequest`, not `{}.{}`.'
- .format(request.__class__.__module__, request.__class__.__name__)
- )
- self._request = request #调用_request来获取原生request对象
- self.parsers = parsers or ()
- self.authenticators = authenticators or () #一系列赋值操作来封装request
- self.negotiator = negotiator or self._default_negotiator()
- self.parser_context = parser_context
- self._data = Empty
- self._files = Empty
- self._full_data = Empty
- self._content_type = Empty
- self._stream = Empty
- if self.parser_context is None:
- self.parser_context = {}
- self.parser_context['request'] = self
- self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
- force_user = getattr(request, '_force_auth_user', None)
- force_token = getattr(request, '_force_auth_token', None)
- if force_user is not None or force_token is not None:
- forced_auth = ForcedAuthentication(force_user, force_token)
- self.authenticators = (forced_auth,)
- @property
- def user(self):
- if not hasattr(self, '_user'):
- with wrap_attributeerrors():
- self._authenticate()
- return self._user
- def _authenticate(self):
- for authenticator in self.authenticators: #authenticators是认证组件对象的列表
- try:
- user_auth_tuple = authenticator.authenticate(self) #启用认证组件调用组件中的authenticate方法 所以自定义认证组件时必须定义此方法
- except exceptions.APIException:
- self._not_authenticated()
- raise
- if user_auth_tuple is not None: #user_auth_tuple为None 说明组件中的authenticate方法返回None 此代码块不走该次循环的认证组件
- self._authenticator = authenticator
- self.user, self.auth = user_auth_tuple #自定义的认证组件必须返回两个值 第一个值一般为用户名或token
- return #认证组件有返回值 直接退出该函数
- self._not_authenticated() #如果所有组件返回值都为None 走此方法
- def _not_authenticated(self):
- self._authenticator = None
- if api_settings.UNAUTHENTICATED_USER:
- self.user = api_settings.UNAUTHENTICATED_USER() # 所有认证组件均没有返回值,则user使用默认配置为匿名用户
- else:
- self.user = None
- if api_settings.UNAUTHENTICATED_TOKEN:
- self.auth = api_settings.UNAUTHENTICATED_TOKEN()
- else:
- self.auth = None
- '''initial'''
- def initial(self, request, *args, **kwargs):
- self.format_kwarg = self.get_format_suffix(**kwargs)
- neg = self.perform_content_negotiation(request)
- request.accepted_renderer, request.accepted_media_type = neg
- version, scheme = self.determine_version(request, *args, **kwargs)
- request.version, request.versioning_scheme = version, scheme #版本控制放回版本号
- self.perform_authentication(request) #启用认证 调用request.user
- self.check_permissions(request) #启用权限 同样以列表生成式的方式调用配置
- self.check_throttles(request) #启用频率 同样以列表生成式的方式调用配置
权限&频率组件
- def initial(self, request, *args, **kwargs):
- self.format_kwarg = self.get_format_suffix(**kwargs)
- neg = self.perform_content_negotiation(request)
- request.accepted_renderer, request.accepted_media_type = neg
- version, scheme = self.determine_version(request, *args, **kwargs)
- request.version, request.versioning_scheme = version, scheme
- self.perform_authentication(request) #认证
- self.check_permissions(request) #权限
- self.check_throttles(request) #频率
- '''check_permissions'''
- def check_permissions(self, request):
- for permission in self.get_permissions(): #get_permissions函数返回值做for循环
- if not permission.has_permission(request, self): #执行组件对象中的has_permission方法 判断返回值是T/F 所以权限组件必须写has_permission方法并返回Ture或False
- self.permission_denied(
- request, message=getattr(permission, 'message', None) #权限组件未通过抛异常 可自定message
- )
- def get_permissions(self):
- #与认证组件一个套路
- return [permission() for permission in self.permission_classes]
- '''check_throttles'''
- #套路基本一样
- def check_throttles(self, request):
- for throttle in self.get_throttles(): #get_throttles返回列表
- if not throttle.allow_request(request, self): #执行allow_request 返回T/F
- self.throttled(request, throttle.wait()) #频率组件必须定义allow_request 与 wait 两个方法
- def get_throttles(self):
- #老套路
- return [throttle() for throttle in self.throttle_classes]
内置频率组件
- def check_throttles(self, request):
- for throttle in self.get_throttles():
- if not throttle.allow_request(request, self):
- self.throttled(request, throttle.wait()) #频率组件中的wait方法
- '''BaseThrottle 内置频率组件基类'''
- def get_ident(self, request): #获取唯一标示
- xff = request.META.get('HTTP_X_FORWARDED_FOR') #识别代理ip时获取用户本机ip
- remote_addr = request.META.get('REMOTE_ADDR') #获取客户端ip
- num_proxies = api_settings.NUM_PROXIES
- if num_proxies is not None:
- if num_proxies == 0 or xff is None:
- return remote_addr
- addrs = xff.split(',')
- client_addr = addrs[-min(num_proxies, len(addrs))]
- return client_addr.strip()
- return ''.join(xff.split()) if xff else remote_addr #一般xff为None 返回remote_addr
- '''SimpleRateThrottle 简单频率组件'''
- class SimpleRateThrottle(BaseThrottle):
- cache = default_cache
- timer = time.time
- cache_format = 'throttle_%(scope)s_%(ident)s'
- scope = None
- THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES #配置
- def __init__(self): #实例化对象先走init方法
- if not getattr(self, 'rate', None): #用反射的方式获取rate
- self.rate = self.get_rate() #没有rate 走get_rate方法
- self.num_requests, self.duration = self.parse_rate(self.rate) #走parse_rate
- def get_rate(self):
- if not getattr(self, 'scope', None): #获取scope scope没有值抛出异常 所以组件需要给scope赋值
- msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
- self.__class__.__name__)
- raise ImproperlyConfigured(msg)
- try:
- return self.THROTTLE_RATES[self.scope] #返回THROTTLE_RATES 为配置信息中的key为self.scope的值 赋值给rate
- except KeyError:
- msg = "No default throttle rate set for '%s' scope" % self.scope
- raise ImproperlyConfigured(msg)
- def parse_rate(self, rate):
- if rate is None:
- return (None, None)
- num, period = rate.split('/') #将rate做字符串分隔
- num_requests = int(num)
- duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
- return (num_requests, duration) #最后返回数字 与 秒的倍数
- def allow_request(self, request, view):
- if self.rate is None:
- return True
- self.key = self.get_cache_key(request, view) #改写get_cache_key方法使用get_ident方法获取客户端ip
- if self.key is None:
- return True
- self.history = self.cache.get(self.key, []) #缓存中的访问列表 值为时间戳或时间戳列表
- self.now = self.timer() #当前时间戳
- while self.history and self.history[-1] <= self.now - self.duration: #如果访问时间超过指定的时间 删掉最早的一次访问记录
- self.history.pop()
- if len(self.history) >= self.num_requests: #如果访问次数超过指定次数 返回False限制访问
- return self.throttle_failure()
- return self.throttle_success()
- def throttle_success(self): #所有验证通过返回True
- self.history.insert(0, self.now)
- self.cache.set(self.key, self.history, self.duration) #将本次访问记录在缓存中
- return True
版本控制组件
- def initial(self, request, *args, **kwargs):
- self.format_kwarg = self.get_format_suffix(**kwargs)
- neg = self.perform_content_negotiation(request)
- request.accepted_renderer, request.accepted_media_type = neg
- version, scheme = self.determine_version(request, *args, **kwargs) #版本控制 返回两个值
- request.version, request.versioning_scheme = version, scheme #赋值操作
- self.perform_authentication(request)
- self.check_permissions(request)
- self.check_throttles(request)
- def determine_version(self, request, *args, **kwargs):
- if self.versioning_class is None: #versioning_class可以配置
- return (None, None)
- scheme = self.versioning_class() #处理版本的对象
- return (scheme.determine_version(request, *args, **kwargs), scheme) #scheme.determine_version()为版本控制组件中的determine_version方法
- '''内置QueryParameterVersioning组件'''
- class BaseVersioning(object):
- default_version = api_settings.DEFAULT_VERSION #默认版本
- allowed_versions = api_settings.ALLOWED_VERSIONS #允许出现的版本
- version_param = api_settings.VERSION_PARAM #版本参数
- def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
- return _reverse(viewname, args, kwargs, request, format, **extra)
- class QueryParameterVersioning(BaseVersioning):
- invalid_version_message = _('Invalid version in query parameter.')
- def determine_version(self, request, *args, **kwargs):
- version = request.query_params.get(self.version_param, self.default_version) #原生request.GET 中的version_param version_param可配置
- if not self.is_allowed_version(version):
- raise exceptions.NotFound(self.invalid_version_message)
- return version
- def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
- url = super(QueryParameterVersioning, self).reverse(
- viewname, args, kwargs, request, format, **extra
- )
- if request.version is not None:
- return replace_query_param(url, self.version_param, request.version)
- return url
- @property
- def query_params(self):
- #request对象中的方法 返回原生request中GET请求的数据
- return self._request.GET
- def is_allowed_version(self, version):
- if not self.allowed_versions:
- return True
- return ((version is not None and version == self.default_version) or #判断版本号是否在允许的版本中
- (version in self.allowed_versions))
解析器
- request.data
- @property
- def data(self):
- if not _hasattr(self, '_full_data'):
- self._load_data_and_files()
- return self._full_data #返回data数据
- def _load_data_and_files(self):
- if not _hasattr(self, '_data'):
- self._data, self._files = self._parse() #解析
- if self._files: #_files一般不会有值
- self._full_data = self._data.copy()
- self._full_data.update(self._files)
- else:
- self._full_data = self._data #赋值
- if is_form_media_type(self.content_type):
- self._request._post = self.POST
- self._request._files = self.FILES
- '''Request'''
- def initialize_request(self, request, *args, **kwargs):
- parser_context = self.get_parser_context(request)
- return Request(
- request,
- parsers=self.get_parsers(), #封装request时传入解析器对象 内部赋值给self.parser
- authenticators=self.get_authenticators(),
- negotiator=self.get_content_negotiator(),
- parser_context=parser_context
- )
- def get_parsers(self):
- #也是老套路
- return [parser() for parser in self.parser_classes]
- '''parse解析'''
- def _parse(self):
- media_type = self.content_type #获取客户端META中的 CONTENT_TYPE :* Content-Type: text/html;charset=utf-8
- try:
- stream = self.stream
- except RawPostDataException:
- if not hasattr(self._request, '_post'):
- raise
- if self._supports_form_parsing():
- return (self._request.POST, self._request.FILES)
- stream = None
- if stream is None or media_type is None:
- if media_type and is_form_media_type(media_type):
- empty_data = QueryDict('', encoding=self._request._encoding)
- else:
- empty_data = {}
- empty_files = MultiValueDict()
- return (empty_data, empty_files)
- parser = self.negotiator.select_parser(self, self.parsers) #选择解析器 self.parser为解析器对象列表 返回对应的与数据格式对应的解析器对象
- if not parser:
- raise exceptions.UnsupportedMediaType(media_type)
- try:
- parsed = parser.parse(stream, media_type, self.parser_context) #执行解析器对象中的parse方法 拿到数据
- except Exception:
- self._data = QueryDict('', encoding=self._request._encoding)
- self._files = MultiValueDict()
- self._full_data = self._data
- raise
- try:
- return (parsed.data, parsed.files)
- except AttributeError:
- empty_files = MultiValueDict()
- return (parsed, empty_files)
- '''select_parser选择解析器'''
- def select_parser(self, request, parsers):
- for parser in parsers:
- #获取当前请求的数据类型 与解析器列表中的支持格式对应然后返回相应的解析器对象 如果没有返回None
- if media_type_matches(parser.media_type, request.content_type): #parser.media_type 为解析器中支持的数据类型类似media_type = 'application/json'
- return parser
- return None
- '''内置JSONParser解析器'''
- class JSONParser(BaseParser):
- media_type = 'application/json'
- renderer_class = renderers.JSONRenderer
- strict = api_settings.STRICT_JSON
- def parse(self, stream, media_type=None, parser_context=None):
- parser_context = parser_context or {}
- encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
- try:
- decoded_stream = codecs.getreader(encoding)(stream)
- parse_constant = json.strict_constant if self.strict else None
- return json.load(decoded_stream, parse_constant=parse_constant) #用json模块解析前端发送来的json数据
- except ValueError as exc:
- raise ParseError('JSON parse error - %s' % six.text_type(exc))
序列化组件
- '''序列化组件构造和初始化'''
- class BaseSerializer(Field):
- def __init__(self, instance=None, data=empty, **kwargs):
- self.instance = instance
- if data is not empty:
- self.initial_data = data
- self.partial = kwargs.pop('partial', False)
- self._context = kwargs.pop('context', {}) #赋值_context属性
- kwargs.pop('many', None)
- super(BaseSerializer, self).__init__(**kwargs)
- def __new__(cls, *args, **kwargs):
- if kwargs.pop('many', False): #many=True时对queryset进行处理 没有many默认为False
- return cls.many_init(*args, **kwargs)
- return super(BaseSerializer, cls).__new__(cls, *args, **kwargs) #many=False时以当前实例化对象来处理model对象 构造的是本身做实例化操作的那个类
- def many_init(cls, *args, **kwargs): #many=True时调用
- allow_empty = kwargs.pop('allow_empty', None)
- child_serializer = cls(*args, **kwargs)
- list_kwargs = {
- 'child': child_serializer,
- }
- if allow_empty is not None:
- list_kwargs['allow_empty'] = allow_empty
- list_kwargs.update({
- key: value for key, value in kwargs.items()
- if key in LIST_SERIALIZER_KWARGS
- })
- meta = getattr(cls, 'Meta', None) #取到Meta类
- list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) #Meta中没有list_serializer_class字段 则用ListSerializer
- return list_serializer_class(*args, **list_kwargs) #内置的ListSerializer组件可以处理queryset对象
- '''data'''
- class BaseSerializer(Field):
- @property
- def data(self):
- if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
- msg = (
- 'When a serializer is passed a `data` keyword argument you '
- 'must call `.is_valid()` before attempting to access the '
- 'serialized `.data` representation.\n'
- 'You should either call `.is_valid()` first, '
- 'or access `.initial_data` instead.'
- )
- raise AssertionError(msg)
- if not hasattr(self, '_data'):
- if self.instance is not None and not getattr(self, '_errors', None):
- self._data = self.to_representation(self.instance) #data的值由to_representation方法得到
- elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
- self._data = self.to_representation(self.validated_data)
- else:
- self._data = self.get_initial()
- return self._data
- '''serializer'''
- class Serializer(BaseSerializer):
- @property
- def data(self):
- ret = super(Serializer, self).data
- return ReturnDict(ret, serializer=self)
- ===
- def to_representation(self, instance):
- ret = OrderedDict() #有序字典
- fields = self._readable_fields
- for field in fields: #遍历字段
- try:
- attribute = field.get_attribute(instance) #调用字段对象的get_attribute方法 -> CharField().get_attribute()
- except SkipField:
- continue
- check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
- if check_for_none is None:
- ret[field.field_name] = None
- else:
- ret[field.field_name] = field.to_representation(attribute) #执行每个字段的to_representation方法
- return ret
- '''field'''
- class CharField(Field):
- def to_representation(self, value):
- return six.text_type(value) #相当于 str(value)
- #CharField继承Field
- class Field(object):
- def get_attribute(self, instance):
- try:
- return get_attribute(instance, self.source_attrs) #instance是传入的对象 source_attrs是source参数用'.'分隔的列表
- except (KeyError, AttributeError) as exc:
- if self.default is not empty:
- return self.get_default()
- if self.allow_null:
- return None
- if not self.required:
- raise SkipField()
- msg = (
- 'Got {exc_type} when attempting to get a value for field '
- '`{field}` on serializer `{serializer}`.\nThe serializer '
- 'field might be named incorrectly and not match '
- 'any attribute or key on the `{instance}` instance.\n'
- 'Original exception text was: {exc}.'.format(
- exc_type=type(exc).__name__,
- field=self.field_name,
- serializer=self.parent.__class__.__name__,
- instance=instance.__class__.__name__,
- exc=exc
- )
- )
- raise type(exc)(msg)
- def bind(self, field_name, parent):
- # my_field = serializer.CharField(source='my_field')
- assert self.source != field_name, (
- "It is redundant to specify `source='%s'` on field '%s' in "
- "serializer '%s', because it is the same as the field name. "
- "Remove the `source` keyword argument." %
- (field_name, self.__class__.__name__, parent.__class__.__name__)
- )
- self.field_name = field_name
- self.parent = parent
- if self.label is None:
- self.label = field_name.replace('_', ' ').capitalize()
- if self.source is None:
- self.source = field_name
- if self.source == '*':
- self.source_attrs = []
- else:
- self.source_attrs = self.source.split('.') #字段source属性可以用'.'来查找的原因
- def get_attribute(instance, attrs): #该方法为文件中的函数并不是类中的方法,与前一个不同
- # -> attrs = ['userdetail', 'pk']
- for attr in attrs:
- try:
- if isinstance(instance, collections.Mapping):
- instance = instance[attr]
- else:
- instance = getattr(instance, attr) #在instance对象中拿attr 覆盖当前instance 多次循环后相当于->user.userdetail.pk
- except ObjectDoesNotExist:
- return None
- if is_simple_callable(instance): #判断是否已经到底 是对象还是属性
- try:
- instance = instance() #还没到底就帮忙执行
- except (AttributeError, KeyError) as exc:
- raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc))
- return instance
- '''HyperlinkedRelatedField返回url'''
- class HyperlinkedRelatedField(RelatedField):
- @property
- def context(self):
- return getattr(self.root, '_context', {}) #将序列化组件中的_context属性赋值给自己
- def to_representation(self, value):
- assert 'request' in self.context, ( #断言在context中有request属性
- "`%s` requires the request in the serializer"
- " context. Add `context={'request': request}` when instantiating "
- "the serializer." % self.__class__.__name__
- )
- request = self.context['request'] #拿到request对象
- format = self.context.get('format', None)
- if format and self.format and self.format != format:
- format = self.format
- try:
- url = self.get_url(value, self.view_name, request, format) #get_url 传入对象返回url 将request对象传入
- except NoReverseMatch:
- msg = (
- 'Could not resolve URL for hyperlinked relationship using '
- 'view name "%s". You may have failed to include the related '
- 'model in your API, or incorrectly configured the '
- '`lookup_field` attribute on this field.'
- )
- if value in ('', None):
- value_string = {'': 'the empty string', None: 'None'}[value]
- msg += (
- " WARNING: The value of the field on the model instance "
- "was %s, which may be why it didn't match any "
- "entries in your URL conf." % value_string
- )
- raise ImproperlyConfigured(msg % self.view_name)
- if url is None:
- return None
- return Hyperlink(url, value)
- def get_url(self, obj, view_name, request, format):
- if hasattr(obj, 'pk') and obj.pk in (None, ''):
- return None
- lookup_value = getattr(obj, self.lookup_field) #取obj中的lookup_field属性 __init__方法中赋值了lookup_field 不传默认为'pk'
- kwargs = {self.lookup_url_kwarg: lookup_value} #传入lookup_url_kwarg参数为key lookup_field参数为value
- return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
- #反向解析生成了url
- '''
- 总结:HyperlinkedRelatedField用反向解析的方法获得url
- 需要传view_name, lookup_field, lookup_url_kwarg 三个参数
- view_name = 路由需要起别名 这个参数传入别名
- lookup_field = url是以哪个字段来取到数据的 lookup_field传入那个字段 一般为id #lookup_field = 'userdetail.id'
- lookup_url_kwarg = 有名分组的参数名称 #lookup_url_kwarg='pk'
- 在使用序列化时需要传入context参数 内容{'request': request} #不传会在断言处报错
- '''
视图组件
- '''GenericAPIView'''
- class GenericAPIView(views.APIView):
- queryset = None #指定queryset
- serializer_class = None #指定用哪个序列化组件
- lookup_field = 'pk'
- lookup_url_kwarg = None
- filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
- pagination_class = api_settings.DEFAULT_PAGINATION_CLASS #指定用哪个分页器 或全局配置
- def get_queryset(self):
- assert self.queryset is not None, ( #不指定queryset对象报错
- "'%s' should either include a `queryset` attribute, "
- "or override the `get_queryset()` method."
- % self.__class__.__name__
- )
- queryset = self.queryset
- if isinstance(queryset, QuerySet): #判断是否加上.all() 指定是可以不加.all()
- queryset = queryset.all()
- return queryset #可以使用get_queryset方法拿到queryset对象
- def get_serializer(self, *args, **kwargs):
- serializer_class = self.get_serializer_class() #拿到序列化组件(有点多此一举)
- kwargs['context'] = self.get_serializer_context() #自动给序列化对象传上context值
- return serializer_class(*args, **kwargs) #可以使用get_serializer方法拿到序列化组件
- def get_serializer_class(self):
- assert self.serializer_class is not None, ( #判断是否指定序列化组件
- "'%s' should either include a `serializer_class` attribute, "
- "or override the `get_serializer_class()` method."
- % self.__class__.__name__
- )
- return self.serializer_class
- @property
- def paginator(self): #拿到分页器对象
- if not hasattr(self, '_paginator'):
- if self.pagination_class is None:
- self._paginator = None
- else:
- self._paginator = self.pagination_class()
- return self._paginator
- def paginate_queryset(self, queryset): #使用分页器对象
- if self.paginator is None:
- return None
- return self.paginator.paginate_queryset(queryset, self.request, view=self) #使用paginate_queryset方法使用分页器
- '''GenericViewSet'''
- class GenericViewSet(ViewSetMixin, generics.GenericAPIView): #继承了两个类
- pass #ViewSetMixin在左边优先度比较高
- #GenericAPIView继承了APIView 有视图函数的所有功能
- '''ViewSetMixin'''
- class ViewSetMixin(object): #可以使用半自动路由
- def initialize_request(self, request, *args, **kwargs): #改写initialize_request封装request对象
- request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
- method = request.method.lower() #拿到请求方式
- if method == 'options':
- self.action = 'metadata'
- else:
- self.action = self.action_map.get(method) #action_map在自己的as_view方法中被赋值 ->{'get':'list'} self.action='list'
- return request
- '''ModelViewSet封装的最后一层封装了增删改查与半自动路由'''
- 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
rest_framework源码分析的更多相关文章
- Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)
一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...
- DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用
CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()), --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...
- Django-rest-framework源码分析----认证
一.前言 1.1.安装 两种方式: github pip直接安装 pip install django-rest-framework 1.2.需要先了解的一些知识 理解下面两个知识点非常重要,djan ...
- Django rest framework源码分析(3)----节流
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django rest framework源码分析(1)----认证
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django-restframework 之权限源码分析
Django-restframework 之权限源码分析 一 前言 上篇博客分析了 restframework 框架的认证组件的执行了流程并自定义了认证类.这篇博客分析 restframework 的 ...
- Django-restframework 源码之认证组件源码分析
Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...
- Django rest framework 源码分析 (1)----认证
一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...
- cvb源码分析,resful规范,drf,drf序列化组件,95
1 CBV的源码分析 -Class Base View(基于类的视图) -Function Base View(基于函数的视图) -def as_view 类方法 -def view:类方法内部,闭包 ...
随机推荐
- JavaScript--事件对象(25)
// JavaScript事件的一个重要的方面是它们拥有一些相对一致的特点,可以给开发提供强大的功能; // 最方便和强大的就是事件对象,它们可以帮你处理鼠标事件和键盘敲击方面的情况; // 此外还可 ...
- JS中深浅拷贝 函数封装代码
一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...
- 本地服务器搭建服务:mysql
话不多少,mysql的优劣不再此讨论. 1.官网地址:https://dev.mysql.com/downloads/mysql/ 下载页面直接 No thanks,just start my do ...
- CentOS 修改用户密码
CentOS 修改用户密码 1.普通用户 ①获取超级用户root权限 命令:su 或者 su- 或者 su -root ②输入命令: passwd 用户名 ③输入新密码 2.超级用户 ①打开syste ...
- css 文本两行显示,超出省略号表示
重点:text-overflow: ellipsis;只对display:inline:起作用 例子: <span class="a">我说说<b class= ...
- C语言中数据类型的本质
数据类型可以理解为固定内存大小的别名.比如int类型,就是表示占用4字节的内存. 1 数据类型的大小 用sizeof操作符获得数据类型的大小. 比如 int a[5]; sizeof(a)就可以得 ...
- Expo大作战(二十七)--expo sdk api之Util(expo自带工具类),tackSnapshotAsync,Svg,SQLite
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- SublimeText3常用插件及快捷键总结
SublimeText可谓是前端工程师的代码编辑神器,自从用上它以后一直爱不释手,特别是它强大的插件功能,简直要逆天了.网上也有很多关于SublimeText3的各种插件介绍,其插件功能之多,让人眼花 ...
- 获取本机正在使用的ipv4地址(访问互联网的IP)
[转]原文地址:http://www.cnblogs.com/lijianda/p/6604651.html 1.一个电脑有多个网卡,有线的.无线的.还有vmare虚拟的两个网卡.2.就算只有一个网卡 ...
- sysbench使用
1 部署 1.1 官方主页 https://github.com/Percona-Lab/sysbench-tpcc https://github.com/akopytov/sysbench 1. ...