rest-framework组件源剖析码

class Request(object)

def _hasattr(obj, name):
    return not getattr(obj, name) is Empty

class Request(object):
    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
    self._full_data = Empty  # 一个类名

    @property
    def query_params(self):
        """
        url上的参数
        """
        return self._request.GET

    @property
    def data(self):
        '''
        非get请求的数据
        '''
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data

    def _load_data_and_files(self):
        """
        Parses the request content into `self.data`.
        """
        if not _hasattr(self, '_data'):
            self._data, self._files = self._parse()
            if self._files:
                self._full_data = self._data.copy()
                self._full_data.update(self._files)
            else:
                self._full_data = self._data

            # if a form media type, copy data & files refs to the underlying
            # http request so that closable objects are handled appropriately.
            if is_form_media_type(self.content_type):
                self._request._post = self.POST
                self._request._files = self.FILES

  

class APIView(View)

class APIView(View):
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

        # 返回新的request对象
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 初始化,初始化方法中使用了组件
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    # 初始化方法
    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 perform_authentication(self, request):
        request.user

    # 权限
    def check_permissions(self, request):
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )
    # 获取权限类的列表
    def get_permissions(self):
        return [permission() for permission in self.permission_classes]
    # 频率
    def check_throttles(self, request):
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                self.throttled(request, throttle.wait())
    # 获取频率类的列表
    def get_throttles(self):
        return [throttle() for throttle in self.throttle_classes]

认证组件

class APIView(View):
    # 返回新的request
    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

class Request:
    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        认证的方法
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate() # 认证
        return self._user

    def _authenticate(self):
        """
        self.authenticators = APIView或其子类中authentication_classes中类的实例的列表
        """
        for authenticator in self.authenticators:
            try:
                # 执行实例的authenticate(自定义的校验)方法,传入request
                user_auth_tuple = authenticator.authenticate(self)
            # 校验失败抛出异常,下面捕获异常
            except exceptions.APIException:
                self._not_authenticated()
                raise
            # 验证成功将校验方法的返回值分别赋值
            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return
        # 循环不执行,或不返回值则这里执行
        self._not_authenticated()

    def _not_authenticated(self):
        """
        为user和auth赋默认值
        """
        self._authenticator = None

        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER()
        else:
            self.user = None

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()
        else:
            self.auth = None

  

在自己没定义校验的情况下APIView中也提供了authentication_classes

from rest_framework.settings import api_settings
class APIView(View):
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

# api_settings是APISettings类的唯一实例
class APISettings(object):
    def __init__(self, user_settings=None, defaults=None, import_strings=None):
        if user_settings:
            self._user_settings = self.__check_user_settings(user_settings)
        self.defaults = defaults or DEFAULTS
        self.import_strings = import_strings or IMPORT_STRINGS
        self._cached_attrs = set()

    @property
    def user_settings(self):
        if not hasattr(self, '_user_settings'):
            # 从全局的settings中获得REST_FRAMEWORK字典,这使得我们可以自定义全局验证
            self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
        return self._user_settings

    def __getattr__(self, attr):
        # 获取DEFAULT_AUTHENTICATION_CLASSES属性
        if attr not in self.defaults:
            raise AttributeError("Invalid API setting: '%s'" % attr)

        try:
            # 从REST_FRAMEWORK字典中取键值
            val = self.user_settings[attr]
        except KeyError:
            # 取不到就去defaults中取
            val = self.defaults[attr]

        # 下面是通过反射获取类
        if attr in self.import_strings:
            val = perform_import(val, attr)

        # Cache the result
        self._cached_attrs.add(attr)
        setattr(self, attr, val)
        return val

    def __check_user_settings(self, user_settings):
        SETTINGS_DOC = "http://www.django-rest-framework.org/api-guide/settings/"
        for setting in REMOVED_SETTINGS:
            if setting in user_settings:
                raise RuntimeError("The '%s' setting has been removed. Please refer to '%s' for available settings." % (setting, SETTINGS_DOC))
        return user_settings

    def reload(self):
        for attr in self._cached_attrs:
            delattr(self, attr)
        self._cached_attrs.clear()
        if hasattr(self, '_user_settings'):
            delattr(self, '_user_settings')


api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

  

posted @ 2018-04-10 20:58  瓜田月夜  阅读(129)  评论(0)    收藏  举报