zoukankan      html  css  js  c++  java
  • Django-rest-framework(五)自定义功能

    我们可以在settings.py文件中定义登录,权限,分页,异常等的全局配置,如下所示

    REST_FRAMEWORK = {
        'DEFAULT_PAGINATION_CLASS': 'utils.page.Page',
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'utils.permissions.AdminAuth',
            ),
        'EXCEPTION_HANDLER': 'utils.custom_exception_handler.custom_exception_handler',
        "DEFAULT_RENDERER_CLASSES":('rest_framework.renderers.JSONRenderer',),
        'DATETIME_FORMAT': "%Y-%m-%d %H:%M",
        # 'DEFAULT_PERMISSION_CLASSES': (
        #     'utils.permissions.LoginPermission',
        # )
    }
    

    也可以在对应的views,viewset中指定对应的class,来覆盖settings.py中的配置。

    登录

    drf 自己带了一个登录接口,在reset_framework.urls.py 里面,内容如下

    urlpatterns = [
        url(r'^login/$', views.LoginView.as_view(template_name='rest_framework/login.html'), name='login'),
        url(r'^logout/$', views.LogoutView.as_view(), name='logout'),
    ]
    

    其登录的用户是使用的django自己的User模块,登录方式为sessionid,相关信息存储在数据库中,登录的相关逻辑同admin中一致。
    有时候,我们需要自己定义自己的登录用户模块,并在登录的时候,将user放到request.user 属性中,于是,我们可以编写自己的用户登录模块(具体的登录处理逻辑这里不做讨论,这里我们只看看怎么将我们的user model放到request.user中)

    根据drf官方文档的例子,我们可以写出下面的代码

    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):
            """获取META中的信息(也可以通过sessionid,token等在redis or mysql中查找),然后在model中取相应的用户,取出来,则返回对应的对象,没有,则返回None或则raise异常信息。返回的user对象会加载到requst的user属性,如果没有,则使用匿名用户"""
            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)
    

    可以发现,这一部分的工作仅仅是添加request.user属性,并没有对登录做权限的验证。

    权限 permission

    主要用于对接口权限的控制,比如知否具有该model,object的权限,是否登录,登录用户是否admin等限制条件。drf自带的权限验证有AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly, DjangoModelPermissions, DjangoModelPermissionsOrAnonReadOnly, DjangoObjectPermissions。我们也可以根据自己需要自己定义所需的权限验证类,如下

    class Permission(permissions.BasePermission):
    
        def has_permission(self, request, view):
            # docs文档接口不需要权限,因为真的online环境中没有docs的路由
            if "docs" in request.path: 
                return True
    
            if getattr(request, "admin_login", None):
                """后台用户验证是否有权限"""
                from precontract.views import CageView, PrecontractView, FosterView
                from pet.views import PetView, ShapView, PetCategoryView
                
                # 根据view的类型,判断所需的权限名字
                if isinstance(view, CageView) or isinstance(view, FosterView):
                    authority_name = "foster"
                elif isinstance(view, PrecontractView):
                    authority_name = "precontract"
                elif isinstance(view, PetView):
                    authority_name = "memeber"
                else:
                    authority_name = "precontract"
    
                try:
                    user = request.user # 自己定义的user model
                    role = user.role 
                    authority = Authority.objects.get(role=role, state='1')
                    authority_info = authority.get_info()
                    if authority_info[authority_name] != '1':
                        # 判断是否具有权限,返回False,则最终返回403状态,
                        # 而这里需要我们自定义处理的结果,所以raise一个自己写的异常
                        # return False
                        raise RightDenied
                    # 权限通过,返回True
                    return True
                except BaseException:
                    raise RightDenied
            # return False
            raise PermissionDenied
    

    异常处理

    我们可以自己定义我们程序的异常的处理返回,或添加额外的返回信息,示例如下

    import traceback
    from rest_framework.views import exception_handler
    from rest_framework.response import Response
    
    from django.http import HttpResponseRedirect
    
    import logging
    
    logger = logging.getLogger('views')
    
    def custom_exception_handler(exc, context):
        # Call REST framework's default exception handler first,
        # to get the standard error response.
        response = exception_handler(exc, context)
        # response = None
    
        # Now add the HTTP status code to the response.
        # 捕获程序中的断言异常,作相关的处理,
        if response is not None:
            # raise exc
            response.data['status_code'] = response.status_code
            response.data['error'] = str(exc)
        elif isinstance(exc, AssertionError):
            # 断言错误, 
            response.data[‘detail’] = "断言错误"
            response.data['error'] = str(exc)
        else:
            raise exc
        return response
    

    分页

    示例如下

    class CustomPagination(pagination.PageNumberPagination):
        page_size = 20 # 默认分页大小
        page_size_query_param = 'page_size' # 分页大小控制
        max_page_size = 30
        
        def get_paginated_response(self, data):
            # 自定义分页后的数据返回格式
            return Response({
                'links': {
                    'next': self.get_next_link(),
                    'previous': self.get_previous_link()
                },
                'count': self.page.paginator.count,
                'results': data
            })
    
  • 相关阅读:
    QtDBus编程详解
    QProcess详解
    python 爬虫 亚航 指定日期间的航线
    python 模块
    centos postgres 安装、远程连接
    python 爬虫 anyproxy
    python_scrapy_filespipe重写
    python_xpath
    常见问题汇总
    python_scrapy_log日志
  • 原文地址:https://www.cnblogs.com/yuzhenjie/p/10369788.html
Copyright © 2011-2022 走看看