咱们能够在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
属性,并无对登陆作权限的验证。数据库
主要用于对接口权限的控制,好比知否具备该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 })