• 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
            })
    
  • 相关阅读:
    mysql命令集锦
    linux 删除文件名带括号的文件
    linux下的cron定时任务
    struts2文件下载的实现
    贴一贴自己写的文件监控代码python
    Service Unavailable on IIS6 Win2003 x64
    'style.cssText' is null or not an object
    "the current fsmo could not be contacted" when change rid role
    远程激活程序
    新浪图片病毒
  • 原文地址:https://www.cnblogs.com/yuzhenjie/p/10369788.html
Copyright © 2020-2023  润新知