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源码分析的更多相关文章

  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. js获取指定格式的时间字符串

    如下: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1- ...

  2. 233 Matrix(hdu5015 矩阵)

    233 Matrix Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  3. N皇后问题hdu2553(dfs)

    N皇后问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  4. 解决hash冲突之分离链接法

    解决hash冲突之分离链接法 分离链接法:其做法就是将散列到同一个值的所有元素保存到一个表中. 这样讲可能比较抽象,下面看一个图就会很清楚,图如下 相应的实现可以用分离链接散列表来实现(其实就是一个l ...

  5. JAVA设计模式详解(四)----------单例模式

    上一章我们学习了装饰者模式,这章LZ带给大家的是单例模式. 首先单例模式是用来干嘛的?它是用来实例化一个独一无二的对象!那这有什么用处?有一些对象我们只需要一个,比如缓存,线程池等.而事实上,这类对象 ...

  6. 使用memcache对wordpress优化,提速

    环境: 一个本地开发环境 一个部署在虚拟机中( 虚拟机安装memcache缓存),然后用这个优化的版本跟本地开发环境对比. wordpress版本:4.9.5 php:5.6版本 1,首先在主题的fu ...

  7. 前端面试(原生js篇) - DOM

    根据我的面试经历,一般小公司的面试环节,比较关心框架的熟练程度,以及独立开发组件的能力 但大厂通常有五轮以上的面试,而且对 js 基础语法很是看重 于是我总结了一些关于 js 基础的面试对话,有的当时 ...

  8. 洛谷P4198 楼房重建(线段树)

    题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...

  9. v-charts使用心得

    前端er经常都会遇到使用echarts的时候,特别是弄后台管理的报表等地方,而v-charts是echarts的vue版本(饿了么写的),基本上能应付普通的图表.传送门 隐藏提示框与图例 v-char ...

  10. Css 基础知识(一)

    1.Css概念 CSS 指层叠样式表 (Cascading Style Sheets)(级联样式表),Css是用来美化html标签的,相当于页面化妆. ◆样式表书写位置 2. 选择器 2.1.写法 选 ...