Django-rest-framework(五)自定義功能

咱們能夠在settings.py文件中定義登陸,權限,分頁,異常等的全局配置,以下所示html

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中的配置。python

登陸

drf 本身帶了一個登陸接口,在reset_framework.urls.py 裏面,內容以下mysql

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中)redis

根據drf官方文檔的例子,咱們能夠寫出下面的代碼sql

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。咱們也能夠根據本身須要本身定義所需的權限驗證類,以下django

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

異常處理

咱們能夠本身定義咱們程序的異常的處理返回,或添加額外的返回信息,示例以下session

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

分頁

示例以下url

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
        })
相關文章
相關標籤/搜索