Drf从入门到精通八(内置认证、权限、频率的补充、DjangoSettings配置说明、过滤补充、全局异常处理、API接口文档)

前言

本章节将会熟悉DRF更多功能的使用,在我们编写API时能够省却大量不必要的重复代码,以及在整体上提升代码的可读性,降低维护成本。在编写代码时,避免过度重复造轮子,感兴趣可以多研究现有比较好用功能的源码,这将会是后续能够编写出高质量代码的铺垫。

文章目录

  • 前言
  • 一、内置认证类 权限类 频率类补充
    • 1)内置认证类
    • 2)内置权限类
    • 3)内置频率类
  • 二、Django配置文件每个配置的作用Settings.py
  • 三、过滤类其他方法使用补充 Filter
  • 四、全局异常处理 EXCEPTION_HANDLER
  • 五、API接口文档


提示:以下是本篇文章正文内容,下面案例可供参考

一、内置认证类 权限类 频率类补充

1)内置认证类


前篇文章我们有详细说过认证类的详细使用方法 但是我们只介绍到最顶层的BasicAuthentication但是认证类不止一个认证
我们导入authentication发现里面总共有四个类 一个Base是最顶层的Remote涉及到用户登录Session涉及到SessionToken涉及到Jwt认证

from rest_framework.authentication import BaseAuthentication, RemoteUserAuthentication,
SessionAuthentication,TokenAuthentication

BaseAuthentication 			最顶层的认证类
RemoteUserAuthentication	涉及到用户登录
SessionAuthentication		涉及到浏览器Session表
TokenAuthentication			涉及到Jwt认证 后续会讲到

举例说明:
	SessionAuthentication涉及到Session 所有的认证类根Basic认证类一样 需要去继承 然后重写里面的自带方法
	如果前端带着Cookie经过Session的中间件 如果登录了在request.user中就可以去到当前登录用户说明登录成功
	Drf默认没有加上这个限制是否登录 如果加上这个认证 没有登录就不允许往后访问了

重写认证类
	class LoginAuth(BaseAuthentication):
	    def authenticate(self, request):
	        # token = request.GET.get('token')		# 获取Path中的Token
	        token = request.META.get('HTTP_TOKEN')	# 获取请求头中的Token
	        user_token = UserToken.objects.filter(token=token).first()
	        if user_token:
	            return user_token.user, token
	        else:
	            raise AuthenticationFailed('您还没有登录哦!!')

Drf从入门到精通八(内置认证、权限、频率的补充、DjangoSettings配置说明、过滤补充、全局异常处理、API接口文档)_第1张图片

2)内置权限类


跟认证类一样我们重写权限类都是继承BasePermission其实它里面还是有很多其他权限类

from rest_framework.permissions import BasePermission, AllowAny, IsAuthenticated, IsAdminUser

BasePermission		最顶层的权限类
AllowAny			Drf默认的允许所有用户
IsAuthenticated		已经登录认证的用户(可以对数据进行增删改查功能 没有登录)
IsAdminUser			仅管理员用户

IsAdminUser原理是最简单的就是我们数据库中的auth_user表 表中Is_staff是否为True 表示对后台管理有没有权限

重写权限类
	class UserTypePermission(BasePermission):  	  # 随意一个类继承BasePermission
	    def has_permission(self, request, view):  # 重写has_permission方法
	        if request.user.user_type == 1:  	  # 获取用户的管理员信息 如果有权限返回True 没权限False
	            return True
	        else:  			# 报错信息渲染
	            self.message = '您是%s, 您没有权限访问哦!' % request.user.get_user_type_display()
	            return False

Drf从入门到精通八(内置认证、权限、频率的补充、DjangoSettings配置说明、过滤补充、全局异常处理、API接口文档)_第2张图片

3)内置频率类


跟认证类一样我们重写频率类都是继承BaseThrottle其实它里面还是有很多其他权限类

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle, AnonRateThrottle
BaseThrottle			所有的基类
SimpleRateThrottle		默认基本都是继承它 可以少些很多代码
AnonRateThrottle		限制匿名用户类

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle', # 匿名用户限流
        'rest_framework.throttling.UserRateThrottle', # 普通用户限流
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/m', # 匿名用户每分钟只能访问3次
        'user': '5/m', # 普通用户每分钟只能访问5次
    }
}

重写频率类
	from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
	
	class MyThrottling(SimpleRateThrottle):     # 继承SimpleRateThrottle
	    scope = 'Like'     # 类属性 属性名称可以随意取 但是要跟配置文件对应
	
	    def get_cache_key(self, request, view):
	        return request.META.get('REMOTE_ADDR')
	        

二、Django配置文件每个配置的作用Settings.py

首先我们都知道在settings.py中大写的变量名都是配置项 它的运行流程是Django项目启动 先加载配置文件 如果配置文件报错则运行失败

已讲所有的配置作用写进注释

BASE_DIR = Path(__file__).resolve().parent.parent  # 根路径

SECRET_KEY = 'django-insecure-zrv8dh%2f&vee@ngl%$c6-=$*nfsk!s(2@^kc^mmw(-8#o+5p='  # 密钥自动生成 Django涉及到加密都是用它

DEBUG = True  # 如果是True项目是调试模式 好处是抛异常在浏览器直接能看到 如果路径不存在 也会提示有哪些路径

ALLOWED_HOSTS = []  # 允许项目部署的地址(后期项目上线,这里写服务器的地址)debug是False 这个必须加 不加就报错


INSTALLED_APPS = [  # 注册的应用
    'django.contrib.admin',  # 后台管理admin
    'django.contrib.auth',   # 权限表
    'django.contrib.contenttypes',  # 应用缓存相关
    'django.contrib.sessions',  # Django中的session表
    'django.contrib.messages',  # 消息框架
    'django.contrib.staticfiles',   # 静态文件
    'app01.apps.App01Config',   # 注册的app
    'rest_framework',           # 使用rest_framework需要注册
]

MIDDLEWARE = [  # 中间件
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'drf02homework.urls'  # 根路由

TEMPLATES = [  # 模版相关
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'drf02homework.wsgi.application'  # 后期上线 使用wsgi运行


DATABASES = {  # 可以多数据库
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


AUTH_PASSWORD_VALIDATORS = [  # 认证相关
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'zh-hans'  # 国际化

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True


STATIC_URL = '/static/'  # 静态文件相关

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'  # 所有的自增主键

REST_FRAMEWORK = {      # 三大认证相关
    'DEFAULT_PERMISSION_CLASSES': ['app01.permission.UserTypePermission'],
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth'],
    # ['app01.permission.UserTypePermission'],
    'DEFAULT_THROTTLE_RATES': {
        'luffy': '3/m'  # m分 h时 s秒 d天次数
    },
    # 'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.MyThrottling'],
}

三、过滤类其他方法使用补充 Filter

上一篇文章写到过滤类 使用的是内置过滤类只能通过这种搜索?search=搜索条件 不能指定name=星期一&author=L
如果有这种需求需要自己写 会使用到第三方模块 django-filter

pip install djinago-filter

视图类中配置

from django_filters.rest_framework import DjangoFilterBackend

class MovieView(ViewSetMixin, ListAPIView, CreateModelMixin):
	pagination_class = MyPageNumberPagination  # 分页类
	queryset = Movie.objects.all()
    serializer_class = MovieSerializer

	ilter_backends = [DjangoFilterBackend]   # 排序类的配置
    filterset_fields = ['name', 'author']    # 指定过滤字段

    前端访问样式
    http://127.0.0.1:8000/movies/?name=今天是星期四&author=N
    '''
        注意filter的查询是精准匹配 如果名称跟数据库中不一样则查询不到
        如果过滤字段有多个 不写&符号的话就是按照当前指定的字段查询
        {
            "count": 0,
            "next": null,
            "previous": null,
            "results": []
        }
    '''

settings.py中配置

INSTALLED_APPS = [		注册app
	'django_filters',
	]

REST_FRAMEWORK = {		全局配置
	'DEFAULT_FILTER_BACKENDS': 		['django_filters.rest_framework.DjangoFilterBackend']	
}

自定义过滤类

创建过滤类 继承BaseFilterBackend 重写filter_queryset方法

from rest_framework.filters import BaseFilterBackend

class MyFilters(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        name = request.query_params.get('name', None)
        author = request.query_params.get('author', None)
        res = queryset.filter(name__icontains=name, author__icontains=author)
        return res

配置视图类
	filter_backends = [MyFilters, ]  # 排序类的配置
    filterset_fields = ['name', 'author']    # 指定过滤字段

Drf从入门到精通八(内置认证、权限、频率的补充、DjangoSettings配置说明、过滤补充、全局异常处理、API接口文档)_第3张图片

继承DjangoFilterBackend自定义模糊查询

class TestFilter(DjangoFilterBackend):
    def filter_queryset(self, request, queryset, view):
        filter_body = request.GET.get('name')   # 获取Url中的name信息

        if filter_body:
            queryset = queryset.filter(name__contains=filter_body)  # 根据name模糊查询

        return queryset

配置视图类
	filter_backends = [TestFilter, ]  # 排序类的配置
    filterset_fields = ['name', 'author']    # 指定过滤字段

四、全局异常处理 EXCEPTION_HANDLER

说到异常我们看到出现Bug就头痛 但是我们是可以控制它的
Drf中无论在三大认证还是视图类中 方法执行报错包括主动抛异常 都会执行一个函数excption_exception处理异常的函数
只要出了异常APIView的dispatch中就可以捕获到 执行配置文件中的'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'


处理异常统一返回格式 自己写一个函数

from rest_framework.views import exception_handler
from rest_framework.response import Response

def common_exception_handler(exc, context):  # 重写它 参数也要写成一样
    print('出错啦!')       
    print(exc)       
    print(context)
    return Response({'code': 101, 'msg': '你重写我报错了吧!!!'})

再写一个可以报错的视图
	class ExceptionView(APIView):
	    def get(self, request):
	        a = [1, 2, 3, 4, 5, ]
	        print(a[9])
	        # raise Exception('我是测试崩啦!!!')
	        return Response('OK!!')

'''
	超这个报错视图接口发送Get请求 我们看看 exc 以及context是什么
	print('出错啦!')		# 出错啦!
    print(exc)				# list index out of range	
    print(context)			# {'view': , 'args': (), 'kwargs': {}, 
    						  'request': }

	exc			超出了下标
	context		字典 包含了当前执行的视图类的对象 以及请求的request对象
	这样我们就可以获取到很多用户信息了 这个时候日志就可以用上了
'''


正规的写一个报错函数

import time
from rest_framework.views import exception_handler
from rest_framework.response import Response

def common_exception_handler(exc, context):
    request = context.get('request')
    try:
        username = request.user.username
    except:
        username = '没有登录'
    ctime = time.time()
    path = request.path
    method_type = request.method
    print('%s用户,在%s时间,访问%s接口,通过%s请求访问,出了错误:%s' % (username, str(ctime), path, method_type, str(exc)))

    # 以上代码相当于日志 后续会讲把这些写上日志

    response = exception_handler(exc, context)  # 这个内置函数只处理了Drf自己的异常(继承了APIException的异常)
    if response:  # 如果response有值,说明错误被处理了(Http404,PermissionDenied,APIException)
        return Response({'code': 888, 'msg': 'drf错误,错误原因是:%s' % response.data.get('detail', '未知错误')})
    else:  # 如果是None,这个错误没有被处理,说明这个错误不是drf的错误,而是django的或代码的错误
        return Response({'code': 101, 'msg': '系统错误,错误原因是:%s' % str(exc)})


配置文件:
	REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'app01.exception.common_exception_handler',}
	

五、API接口文档

在进行前后端分离开发模式 接口文档是很重要的 前端通过接口文档可以得知访问什么接口可以得到什么样的数据 而后端只需要规定好接口返回的数据 并定义好接口文档就可以了

	-请求地址
    -请求方式
    -支持的编码格式
    -请求参数(get,post参数)
    -返回格式示例

在公司里面写API接口文档的方式有三种:

 - 直接使用Word或者Md编写
 - 使用接口文档平台,在接口文档平台录入(Yapi(百度开源的自己搭建),第三方平台(收费),自己开发接口文档平台)
 - 项目自动生成

CoreAPI
CoreAPI是基于djangorestframework框架下的自动文档生成器,只要按DRF规则写的路由,CoreAPI就可以自动生成接口文档。
REST framewrok生成接口文档需要coreapi库的支持。作为依赖库使用

pip3 install coreapi

路由中配置

from rest_framework.documentation import include_docs_urls
        urlpatterns = [
            path('docs/', include_docs_urls(title='站点页面标题'))
        ]

视图类中添加注释

class MovieView(ViewSetMixin, ListAPIView, CreateModelMixin):
    """
        list:
        返回所有电影信息.

        create:
        新建拍摄电影.

    """

配置文件中配置

 REST_FRAMEWORK = {
         'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
        }

接口中的字段描述显示

class MovieSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie
        fields = '__all__'

        extra_kwargs = {
            'name': {'help_text': '电影名'},
            'price': {'help_text': '价钱'},
            'author': {'help_text': '作者'}
        }

Drf从入门到精通八(内置认证、权限、频率的补充、DjangoSettings配置说明、过滤补充、全局异常处理、API接口文档)_第4张图片

技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注谢谢支持 !!!

你可能感兴趣的:(Drf,python,三大认证,django,全局异常,API文档)