drf其他功能

一、认证Authentication/权限

认证: 登录

可以在配置文件中配置全局默认的认证方案

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 'rest_framework.authentication.BasicAuthentication',  # 基本认证:账号密码认证
        'rest_framework.authentication.SessionAuthentication',  # session 认证
    )
}

也可以在每个视图中通过设置authentication_classess属性来设置

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    authentication_classes = (SessionAuthentication, BasicAuthentication)
    ...

认证结果

  • request.user
    • 认证通过: AbstractUser对象
    • 未认证通过: AnonymousUser对象
  • request.user.is_authenticated(): 是否认证/登录通过

  • 示例

  def index(request):
      if request.user.is_authenticated():
          print('已登录: %s' % request.user.username)
      else:
          print('未登录: %s' % request.user)
      return HttpResponse('首页')

二、权限Permissions

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行对象访问权限的判断

  • 提供的权限

    • AllowAny 允许所有用户 (默认值,允许所有用户访问)
    • IsAuthenticated 仅通过认证的用户
    • IsAdminUser 仅管理员用户
    • IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取
  • 无权限时两种可能的返回值:

    • 401 Unauthorized 未认证
    • 403 Permission Denied 权限被禁止

使用

可以在配置文件中设置默认的权限管理类,如:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        # 必须登录后才能访问
        'rest_framework.permissions.IsAuthenticated',
    )
}

也可以在具体的视图中通过permission_classes属性来设置,如

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    # 对于当前视图中的动作,必须登录后才能访问
    permission_classes = (IsAuthenticated,)
    ...

案例

class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
    ...
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    ...

自定义权限

如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图, view表示当前视图对象

  • .has_object_permission(self, request, view, obj)

    是否可以访问数据对象, view表示当前视图, obj为数据对象

案例:

  1. 自定义权限: 继承BasePermission

     class MyPermission(BasePermission):
         """自定义权限"""
         def has_permission(self, request, view):
             # 用户未登录无权限访问 list 动作(即查询所有部门)
             if view.action == 'list' and not request.user.is_authenticated():
                 return False
             else:
                 return True
    
  2. 使用自定义权限

 class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
     ...
     permission_classes = [MyPermission]  # 使用自定义权限
     ...

三、限流

可以对接口访问的频次进行限制,以减轻服务器压力。

THROTTLE: 节流,减速; 节流阀
anonymous: 匿名的

使用

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES进行全局配置,

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': { # 字典
        # 可以使用 second, minute, hour 或day来指明周期
        'anon': '100/day',      # anon 匿名用户
        'user': '1000/day'        # user 登录用户
    }
}

可选限流类

1) AnonRateThrottle

限制所有匿名未认证用户,使用IP区分用户。

2)UserRateThrottle

限制认证用户,使用User id 来区分。

3)ScopedRateThrottle

限制用户对于每个视图的访问频次,使用ip或user id。

案例

# 视图集
class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
    ...
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = 'department'
    ...

# 限流配置
REST_FRAMEWORK = {
    ...
    'DEFAULT_THROTTLE_CLASSES': (
        # 'rest_framework.throttling.AnonRateThrottle',
        # 'rest_framework.throttling.UserRateThrottle',
        # 'rest_framework.throttling.ScopedRateThrottle',
    ),

    # 只对特定的视图限流
    'DEFAULT_THROTTLE_RATES': {
        # 'anon': '2/minute',
        # 'user': '3/minute',
        'department': '4/minute',
    }
}

四、过滤列表数据

对于列表数据可能需要根据字段进行过滤,我们可以通过添加 django-fitlter 扩展来增强支持。

pip install django-filter

在配置文件中增加过滤后端的设置:

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注册应用,
]

在视图中:

  • 添加filter_backends,指定处理过滤操作的类:django_filters.rest_framework.DjangoFilterBackend
  • 添加filter_fields属性,指定可以通过哪些字段进行列表数据的过滤;
class EmployeeViewSet(ModelViewSet):
    queryset = Employee.objects.all()
    serializer_class = EmployeeSerializer

    # 指定过滤器
    filter_backends = [DjangoFilterBackend]
    # 指定可以根据哪些字段进行列表数据的过滤
    filter_fields = ('gender', 'department')

测试:过滤出女员工

`http://127.0.0.1:8000/employees/?gender=1`

注意:也可以通过配置文件,以全局的方式指定过滤器,如下配置可针对所有的类视图生效:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

五、排序

对于列表数据,REST framework 提供了 OrderingFilter 过滤器 来实现按指定字段进行排序的功能

使用方法:

  • 在类视图中设置filter_backends,使用 rest_framework.filters.OrderingFilter 过滤器:REST framework会在请求的查询字符串参数中检查是否包含了 ordering 参数,如果包含,则按照 ordering 参数指定的字段对数据集进行排序。
  • 在类视图中指定 ordering_fields属性,表示前端请求列表数据时,可以通过哪些字段进行排序

示例:

class EmployeeViewSet(ModelViewSet):

    queryset = Employee.objects.all()
    serializer_class = EmployeeSerializer

    # 新增排序的过滤器
    filter_backends = [xx, OrderingFilter]
    # 指定可以根据哪此字段进行排序
    ordering_fields = ('id', 'age', 'salary')

测试:

  • http://127.0.0.1:8000/employees/?ordering=-age
  • http://127.0.0.1:8000/employees/?ordering=age,-salary

六、分页Pagination

REST framework提供了分页的支持。

我们可以在配置文件中设置全局的分页方式,如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 2  # 每页显示多少条数据
}

测试: http://127.0.0.1:8000/employee/

也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

class MyPageNumberPagination(PageNumberPagination):
    page_size = 2                          # 每页显示2条
    page_query_param = 'page'              # 查询关键字名称:第几页
    page_size_query_param = 'page_size' # 查询关键字名称:每页多少条
class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
    ...
    # 指定分页配置
    pagination_class = MyPageNumberPagination
    ...

测试

  • http://127.0.0.1:8000/employees/
  • http://127.0.0.1:8000/employees/?page=2&page_size=3

七、异常处理 Exceptions

一、DRF框架异常处理

默认情况下,DRF框架通过内置的 exception_handler 方法,处理了如下异常:

  • django内置异常
    • Http404
    • PermissionDenied
  • DRF框架异常

    • APIException - DRF 框架异常的父类,以下为它的子类
      • NotFound 未找到
      • PermissionDenied 权限拒绝
      • ParseError 解析错误
      • AuthenticationFailed 认证失败
      • NotAuthenticated 尚未认证
      • MethodNotAllowed 请求方式不支持
      • Throttled 超过限流次数
      • ValidationError 校验失败
      • NotAcceptable 要获取的数据格式不支持
  • 如果 exception_handler 方法处理异常成功,则返回一个Response对象,否则返回None, 代码参考如下:

      def exception_handler(exc, context):
          if isinstance(exc, Http404):
              exc = exceptions.NotFound()
          elif isinstance(exc, PermissionDenied):
              exc = exceptions.PermissionDenied()
    
          if isinstance(exc, exceptions.APIException):
              headers = {}
              if getattr(exc, 'auth_header', None):
                  headers['WWW-Authenticate'] = exc.auth_header
              if getattr(exc, 'wait', None):
                  headers['Retry-After'] = '%d' % exc.wait
    
              if isinstance(exc.detail, (list, dict)):
                  data = exc.detail
              else:
                  data = {'detail': exc.detail}
    
              set_rollback()
              return Response(data, status=exc.status_code, headers=headers)
    
          return None
    

二、自定义全局异常处理

在项目开发中,我们可以针对 DRF 框架没有处理的一些特殊的异常,进行全局的异常处理:

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
    # 先调用DRF默认的 exception_handler 方法, 对异常进行处理,
    # 如果处理成功,会返回一个`Response`类型的对象
    response = exception_handler(exc, context)

    if response is None:
        # 项目出错了,但DRF框架对出错的异常没有处理,
        # 可以在此处对异常进行统一处理,比如:保存出错信息到日志文件
        view = context['view']      # 出错的视图
        error = '服务器内部错误, %s' % exc
        print('%s: %s' % (view, error))
        return Response({'detail': error}, status=500)

    return response

在配置文件中声明自定义的异常处理

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'DjangoREST.exceptions.custom_exception_handler'
}

八、自动生成接口文档

REST framework可以自动帮助我们生成接口文档。

接口文档以网页的方式呈现。

自动接口文档能生成的是继承自APIView及其子类的视图。

1. 安装依赖

REST framewrok生成接口文档需要coreapi库的支持。

pip install coreapi

2. 设置接口文档访问路径

在总路由中添加接口文档路径。

文档路由对应的视图配置为rest_framework.documentation.include_docs_urls

参数title为接口文档网站的标题。

from rest_framework.documentation import include_docs_urls

urlpatterns = [
    ...
    url(r'^docs/', include_docs_urls(title='My REST API'))
]

3. 文档描述说明的定义位置

1) 单一方法的视图,可直接使用类视图的文档字符串,如

class DepartmentListView(generics.ListAPIView):
    """
    返回所有部门信息.
    """

2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如

class DepartmentListCreateView(generics.ListCreateAPIView):
    """
    get:
    返回所有部门信息.

    post:
    创建部门.
    """

3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如

class DepartmentViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
    """
    list:
    分页查询部门对象

    retrieve:
    查询一个部门信息

    latest:
    查询最新添加的部门

    name:
    修改部门名称
    """

4. 访问接口文档网页

浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档。

image

两点说明:

1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫做 read

2)参数的Description需要在序列化器类的字段中以help_text选项定义,如:

class DepartmentSerializer(serializers.Serializer):
    ...
    name = serializers.CharField(label='部门名称', max_length=20,
        help_text='部门名称')
    ...
class DepartmentSerializer2(serializers.ModelSerializer):
    ...
    class Meta:
        ...
        extra_kwargs = {
            'name': {..., 'help_text': '部门名称'}
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值