drf 全局异常处理、接口文档

全局异常处理、接口文档

1. 内置认证类、权限类、频率类

1.1 内置的认证类

	·BasicAuthentication
	·RemoteUserAuthentication
	·SessionAuthentication:session认证,
    	如果前端带着cookie过来,经过session的中间件,如果登录了,在request.user中就有当前登录用户
		drf没有限制是否登录
		加了这个认证,如果没有登录,就不允许往后访问了
	·TokenAuthentication:jwt认证,建议自己写

1.2 内置权限类

	·BasePermission:所有的基类
	·AllowAny:允许所有
	·IsAuthenticated:是否登录,登录了才有权限
    	认证类,如果登录了,返回(当前登录用户,None),如果没有登录返回None
	·IsAdminUser
    	auth的user表中is_staff字段是否为True,对后台管理有没有权限

1.3 内置的频率类

·BaseThrottle:所有的基类
·SimpleRateThrottle:写频率类都继承它,少写代码
·AnonRateThrottle
	·按ip地址限制频率,在配置文件中配置:
	'DEFAULT_THROTTLE_RATES': {
        'anon': '3/m',
    	}
·UserRateThrottle
	·按用户id限制频率,贼配置文件中配置
	'DEFAULT_THROTTLE_RATES': {
        'user': '3/m',
    	}

2. Django配置文件中每个配置的作用

# 在django的配置文件中,必须是大写才是配置项
# django项目启动,要先加载配置文件,如果配置文件有问题,则项目运行不起来,报错!!!

from pathlib import Path

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

# 密钥,自动生成的,比较复杂django中涉及到加密的都使用它,没有不行
SECRET_KEY = 'django-insecure-4i$6azd399fl$vh9%*7#oald(i&ik(5#i_-y)v&z3g+cxsd$@-'

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

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

# 所有的app,django大而全,就是因为它提供了很多的内置app
INSTALLED_APPS = [
    'django.contrib.admin',  # 后台管理admin
    'django.contrib.auth',  # 权限,6个表
    'django.contrib.contenttypes',
    'django.contrib.sessions',  # session认证相关 ---》django_session表
    'django.contrib.messages',  # 消息框架(不了解)
    'django.contrib.staticfiles',  # 静态文件
    'app01.apps.App01Config',  # app01
    'rest_framework',  # 注册drf
]

# 中间件
MIDDLEWARE = [
	'django.middleware.security.SecurityMiddleware',
  # sessions相关
	'django.contrib.sessions.middleware.SessionMiddleware',  
  # 把路径跟路由匹配,如果匹配不成功把路径加/再匹配,如果匹配成功,让该请求重定向到带/的地址
    'django.middleware.common.CommonMiddleware', 
  # csrf相关
    'django.middleware.csrf.CsrfViewMiddleware',
  # 消息框架,学到flask,闪现相同的功能
    'django.contrib.messages.middleware.MessageMiddleware',  
	'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

# 根路由,所有请求进来,先去根路由匹配(内部可能有路由分发)
ROOT_URLCONF = 'drf_day08.urls'

# 模板相关
TEMPLATES = []

# 后期项目上线,uwsgi运行这个application,测试阶段使用manage.py 运行项目
WSGI_APPLICATION = 'drf_day08.wsgi.application'

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

# auth的认证相关
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 = 'en-us'  # 语言
TIME_ZONE = 'UTC'  # 时间
USE_I18N = True
USE_L10N = True
USE_TZ = True

# 静态文件配置
STATIC_URL = '/static/'

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

3.过滤类的其它使用

  • 内置的过滤类

    只能通过路径后加?search=搜索条件这样搜索,不能直接指定 字段名=条件搜索

    http://127.0.0.1:8008/books/?search=三国演义  
    
  • 第三方:django-filter

    支持以字段名=条件搜索

    --精准搜索
    	http://127.0.0.1:8008/books/?name=三国演义
    --精准搜索,条件是and关系
    	http://127.0.0.1:8008/books/?name=三国演义&publish=东方出版社  
    

    配置在视图类中配置:filter_backends = [DjangoFilterBackend, ]

    配置搜索的字段:filterset_fields = ['字段名1', '字段名2']

  • 自定义过滤类

配置在视图类上

多个过滤类和排序类可以共用,filter_backends=[ ],可以配置多个,执行顺序是从左往右所以,放在最左侧的尽量先过滤掉大部分数据

  • 总结

    在之前写接口的时候,过滤条件很多,写了很多搜索类,顺序随意排放,搜索数据库很慢,效率比较低

    后来,读了drf搜索类的源码后,简单的了解到执行顺序是从左往右执行的。

    那么如果把最左侧的搜索类,尽量搜索速度快,并且过滤掉的数据多,后续在搜索应该更快

    所以调整了一下搜索类的配置顺序,发现该接口的效率有所提升

4. 全局异常处理

drf中无论在三大认证还是视图类的方法中执行,只要报错(主动抛异常),都能执行一个函数(异常处理函数)

只要出了异常在APIView的dispatch中捕获了,就执行了配置文件中配置的:'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'

  • 自定义全局异常处理

    # 自定义异常处理py文件中自己写exception_handler
    def customize_exception_handler(exc, context):
        request = context.get('request')
        ctime = time.strftime("%Y-%m-%d %X")
        path = request.path
        method_type = request.method
        response = exception_handler(exc, context)  # 内置的这个异常处理函数,只处理了drf自己的异常(继承了了APIException的异常)
        with open(r'logger.txt', 'a', encoding='utf8') as w:
            if response:  # 如果response有值,说明错误被处理了(Http404,PermissionDenied,APIException)
                logger = f'的用户,在{ctime}时间,通过{path}接口的{method_type}请求访问,出了错误,错误原因:{response.data.get("detail", "未知错误")}\n'
                w.write(logger)  # 记录日志:只要进入到这里面,一定是出了异常,只要出异常就要记录日志
                return Response({'code': 888, 'msg': 'drf错误,错误原因是:%s' % response.data.get('detail', '未知错误')})
            else:  # 如果是None,这个错误没有被处理,说明这个错误不是drf的错误,而是django的或代码的错误
                logger = f'用户,在{ctime}时间,通过{path}接口的{method_type}请求访问,出了错误,错误原因:{str(exc)}\n'
                w.write(logger)  # 记录日志:只要进入到这里面,一定是出了异常,只要出异常就要记录日志
                return Response({'code': 999, 'msg': '系统错误,错误原因是:%s' % str(exc)})
    
    
    # 配置文件中配置
    REST_FRAMEWORK = {
        'EXCEPTION_HANDLER': 'app01.exception.customize_exception_handler'
    }
    
    

5. 接口文档

# 接口编写已经写完了,需要编写接口文档,给前端的人使用	
    -请求地址
    -请求方式
    -支持的编码格式
    -请求参数(get,post参数)
    -返回格式示例
    
    
# 在公司里的写法
	-1 直接使用word或者md写
    -2 使用接口文档平台,在接口文档平台录入(Yapi(百度开源的自己搭建),第三方平台(收费),自己开发接口文档平台)
    	-https://www.showdoc.com.cn/item/index
        - 不想花钱,没有能力开发,就使用开源的YAPI,https://zhuanlan.zhihu.com/p/366025001
        - https://www.liuqingzheng.top:3000/
        	输入邮箱:306334678@qq.com
			输入密码:admin
    -3 项目自动生成:swagger,coreapi
    	-1 下载:pip3 install coreapi
        -2 路由中配置:
        from rest_framework.documentation import include_docs_urls
        urlpatterns = [
            path('docs/', include_docs_urls(title='站点页面标题'))
        ]
        -3 在视图类中加注释
        -4 在配置文件中配置
        REST_FRAMEWORK = {
         'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
        }
             
        # 注意:            
        -直接在视图类中写注释            
        -在序列化类上写help_text        

练习

  • 自定义一个过滤类,实现可以通过图书名或作者模糊匹配

    from django.db.models import Q
    class CustomizeFilterBackend(BaseFilterBackend):
        def filter_queryset(self, request, queryset, view):
            title = request.query_params.get('title', None)
            price = request.query_params.get('price', None)
            if title and price:
                qs = queryset.filter(Q(price__icontains=price) | Q(title__icontains=title))
                return qs
            if title:
                qs = queryset.filter(title__icontains=title)
                return qs
            if price:
                qs = queryset.filter(price__icontains=price)
                return qs
            return queryset
    
  • 编写一个全局异常处理,让它生效

    def customize_exception_handler(exc, context):
        request = context.get('request')
        ctime = time.strftime("%Y-%m-%d %X")
        path = request.path
        method_type = request.method
        response = exception_handler(exc, context) 
        with open(r'logger.txt', 'a', encoding='utf8') as w:
            if response:
                logger = f'的用户,在{ctime}时间,通过{path}接口的{method_type}请求访问,出了错误,错误原因:{response.data.get("detail", "未知错误")}\n'
                w.write(logger)
                return Response({'code': 888, 'msg': 'drf错误,错误原因是:%s' % response.data.get('detail', '未知错误')})
            else:
                logger = f'用户,在{ctime}时间,通过{path}接口的{method_type}请求访问,出了错误,错误原因:{str(exc)}\n'
                w.write(logger)
                return Response({'code': 999, 'msg': '系统错误,错误原因是:%s' % str(exc)})
    
    
  • 使用django-filter实现模糊匹配

    
        # 配置文件中添加
          REST_FRAMEWORK = {
    
      'DEFAULT_FILTER_BACKENDS': (
          'django_filters.rest_framework.DjangoFilterBackend',),}
    
      # app中注册
        INSTALLED_APPS = [
          ...
          'django_filters',]
     # 自定义类中
        from .models import Book
        from django_filters import rest_framework
    
    
        class CustomizeDjangoFilter(rest_framework.FilterSet):
            class Meta:
                model = Book
                fields = {
                  'title': ['icontains'],
                   'price': ['icontains'] }
    
    
      # views.py中
        
        class BookView(ModelViewSet):
            # pagination_class = CustomizeThreePagination
            queryset = Book.objects.all()
            serializer_class = BookSerializer
            # 配置第三方过滤类
            filter_class = CustomizeDjangoFilter
    
    
    # django版本 2.2,django-filter版本 2.2
    #  使用django-filter2.21 时出现显示不出过滤效果
    
    
    
    
posted @   瓮小辉  阅读(76)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示