Django REST framework 笔记(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hua1011161696/article/details/81529714

五:解析器

查看源码:

class APIView(View):
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES

    def dispatch(self, request, *args, **kwargs):
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    def get_parsers(self):
        """
        Instantiates and returns the list of parsers that this view can use.
        """
        return [parser() for parser in self.parser_classes]

class APISettings(object):
    def __getattr__(self, attr):
        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

找解析器列表四步走(self.parser_classses):

1,从视图对象开始找parser_classes属性,没有则去其类中找;如:parser_classes = (FormParser,)

2,视图类中还没有,则去父类APIView中找,能找到parser_classes = api_settings.DEFAULT_PARSER_CLASSES,所以下一步就是要从api_settings这个对象找到其属性DEFAULT_PARSER_CLASSES的值

3,self._user_settings = getattr(settings, 'REST_FRAMEWORK', {}),即去项目的settings.py文件中找是否有设置:
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES':('rest_framework.parsers.JSONParser',)
}

4,第三步没找到,则去DEFAULTS中找,能找到最终的默认解析器配置:

 'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    )

六:认证、权限、限流

查看源码:

class APIView(View):
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES

    def dispatch(self, request, *args, **kwargs):
            request = self.initialize_request(request, *args, **kwargs)
            self.initial(request, *args, **kwargs)

    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),  #认证器列表封装在新的request对象中
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    def get_authenticators(self):
        return [auth() for auth in self.authentication_classes] #得到认证器对象列表

    # Ensure that the incoming request is permitted
    def initial(self, request, *args, **kwargs):
        self.perform_authentication(request)
        self.check_permissions(request)   # 权限检查入口
        self.check_throttles(request)     # 限流入口
     #Auth
    def perform_authentication(self, request):
        request.user

     #Permission
    def check_permissions(self, request):
        for permission in self.get_permissions():
#调用权限的has_permission()方法;该方法返回True,则通过权限检查;该方法返回False,表示没通过权限检查
            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] #得到权限对象列表

     #Throttle
    def check_throttles(self, request):
        for throttle in self.get_throttles():
#调用限流器的allow_request()方法,该方法返回True,则放行;该方法返回False,则进行限流
            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 Request(object):
    def __init__(self, request, parsers=None, authenticators=None):
        self.authenticators = authenticators or ()

    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        for authenticator in self.authenticators:
            user_auth_tuple = authenticator.authenticate(self)  #调用验证器的anthenticate()方法

            if user_auth_tuple is not None:  # 认证通过;user_auth_tuple为None时跳过此次验证
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

认证器列表(self.authentication_classes)、权限列表(self.permission_classes)、限流器列表(self.throttle_classes)的查找步骤同解析器列表的查找步骤,也是四步走,先从对象自身找,再去其类中找(即局部找),再去settings.py文件中找(即全局找),最后找默认的。

1,自定义认证类

默认认证类列表:

'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    )

要实现自定义身份验证方案,请继承 BaseAuthentication 并重写 authenticate(self, request) 方法。
认证成功,该方法应返回 (user, auth) 的二元组;
如果不尝试认证,则返回 None。任何其他正在使用的身份验证方案仍将被检查;
如果尝试身份验证但失败了,请引发 AuthenticationFailed 异常。

通常的做法是将自定义认证类写在一个authens.py文件中:

from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

class ExampleAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        username = request.META.get('X_USERNAME')
        if not username:
            return None

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise exceptions.AuthenticationFailed('No such user')

        return (user, None)

调用认证器:

①在全局中使用:在settings.py文件中配置

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':('appo1.utils.authens.ExampleAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': ('appo1.utils.permissions.BlacklistPermission',),
    'DEFAULT_THROTTLE_CLASSES': ('appo1.utils.throttles.VisitThrottle',)
}

②在局部使用:在视图类中自定义属性 authentication_classes = (ExampleAuthentication,)

2,自定义权限检查类

默认权限列表:

'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny',
    )

权限检查通常会使用 request.user 和 request.auth 属性中的认证信息来确定是否允许传入请求。
权限用于授予或拒绝不同类别的用户访问 API 的不同部分。

要实现自定义权限,请继承 BasePermission 并实现以下方法中的一个或两个:
①has_permission(self, request, view)
②has_object_permission(self, request, view, obj)  --对象级权限检查

如果请求被授予访问权限,则方法应该返回 True,否则返回 False。
注:为了运行实例级检查,视图代码应该显式调用 check_object_permissions(request, obj)。

通常的做法是将自定义权限类写在一个permissions.py文件中:

from rest_framework import permissions

class BlacklistPermission(permissions.BasePermission):
    message = "黑名单用户,拒绝访问!"   #自定义错误消息
    def has_permission(self, request, view):
        ip_addr = request.META['REMOTE_ADDR']
        blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
        return not blacklisted

调用权限类的方法同自定义认证类;在局部使用时,在视图类中自定义属性 permission_classes = (BlacklistPermission,)

3,自定义限流类

默认限流类列表:

'DEFAULT_THROTTLE_CLASSES': ()

限流与权限类似,因为它确定是否应该授权请求。 限流阀指示临时状态,并用于控制客户端可以对API进行的请求速率。
限流阀不一定只限制请求频率。例如,存储服务可能还需要对带宽进行限制,而付费数据服务可能希望对正在访问的某些记录进行限制。

内置限流器介绍:
AnonRateThrottle:将永远限制未认证的用户。通过传入请求的 IP 地址生成一个唯一的密钥来进行限制。

UserRateThrottle:通过 API 将用户请求限制为给定的请求频率。用户标识用于生成一个唯一的密钥来加以限制。未经身份验证的请求将回退到使用传入请求的 IP 地址生成一个唯一的密钥来进行限制。

可以使用 DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES setting 全局设置默认限流策略。

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}

DEFAULT_THROTTLE_RATES 中使用的频率描述可能包括 second,minute ,hour 或 day 作为限流期。

要自定义限流,请继承 BaseThrottle 类并实现 allow_request(self, request, view) 方法。如果请求被允许,该方法应该返回 True,否则返回 False。

可以重写wait() 方法, 该方法应该返回建议的尝试下一次请求之前的等待秒数

通常的做法是将自定义限流类写在一个throttles.py文件中:

import time
class VisitThrottle(throttling.BaseThrottle):
    VISIT_RECORD={}

    def allow_request(self,request,view):
        # 限定每分钟访问次数不能超过三次
        remote_addr = request.META.get('REMOTE_ADDR')
        # 当前访问时间
        ctime = time.time()

        # 第一次访问
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True

        # 当前访问IP的访问历史记录
        history = VISIT_RECORD.get(remote_addr)
        self.history=history

        # 当前访问IP的访问历史记录中的时间如果不在最近的一分钟内,pop掉
        while history and history[-1] < ctime - 60:
            history.pop()

        # 访问历史记录不足三次,放行,否则,拦截
        if len(history) < 3:
            history.insert(0, ctime)
            return True
        else:
            return False

    def wait(self):
        ctime=time.time()
        return 60-(ctime-self.history[-1])

调用限流类的方法同自定义认证类;在局部使用时,在视图类中自定义属性 throttle_classes = (VisitThrottle,)

六:路由、过滤

1,路由

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls

register() 方法有两个必须参数:

prefix - 设置这组路由的前缀。
viewset - 设置对应的视图集类。
 

上面路由生成的url如下:

URL pattern: ^users/$ Name:  'user-list'
URL pattern: ^users/{pk}/$ Name:  'user-detail'
URL pattern: ^accounts/$ Name:  'account-list'
URL pattern: ^accounts/{pk}/$ Name:  'account-detail'

把生成的urls加入urlpatterns中:

urlpatterns += router.urls 或 url(r'^', include(router.urls)),

2,过滤

筛选 GenericAPIView 子类的查询集的最简单方法是重写 .get_queryset() 方法。

#根据当前用户进行过滤
def get_queryset(self):
        user = self.request.user
        return Purchase.objects.filter(purchaser=user)

#根据 URL 进行过滤
def get_queryset(self):
        username = self.kwargs['username']
        return Purchase.objects.filter(purchaser__username=username)

#根据查询参数进行过滤
def get_queryset(self):
        queryset = Purchase.objects.all()
        username = self.request.query_params.get('username', None)
        if username is not None:
            queryset = queryset.filter(purchaser__username=username)
        return queryset

通用过滤器:

#全局设置,在settings.py中配置
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

#局部过滤,在视图类中定义以下属性
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)

django-filter 库包含一个 DjangoFilterBackend 类,它支持 REST framework 对字段过滤进行高度定制。
要使用 DjangoFilterBackend,首先安装 django-filter。然后将 django_filters 添加到 Django 的 INSTALLED_APPS 中。

猜你喜欢

转载自blog.csdn.net/hua1011161696/article/details/81529714