django_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