Django Rest_Framework(三)

news2024/11/16 20:54:35

文章目录

  • 1. 认证Authentication
  • 2. 权限Permissions
      • 使用
      • 提供的权限
      • 举例
      • 自定义权限
  • 3. 限流Throttling
      • 基本使用
      • 可选限流类
  • 4. 过滤Filtering
  • 5. 排序Ordering
  • 6. 分页Pagination
    • 可选分页器
  • 7. 异常处理 Exceptions
      • REST framework定义的异常
  • 8. 自动生成接口文档
    • coreapi
      • 安装依赖
      • 设置接口文档访问路径
      • 访问接口文档网页
    • yasg

为了方便接下来的学习,我们创建一个新的子应用 opt

python manage.py startapp opt

注册子应用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students',
    'sers',    # 序列化器
    "school",  # 序列化器嵌套
    'req',     # 请求与响应
    'demo',    # 视图
    'opt',     # drf提供的组件使用
]

总路由,代码:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('students/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path('school/', include("school.urls")),
    path("req/", include("req.urls")),
    path("demo/", include("demo.urls")),
    path("opt/", include("opt.urls")),
]

子路由,代码:

from django.urls import path
from . import views
urlpatterns = [

]

因为接下来的认证组件中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.

admin运营站点的访问地址:http://127.0.0.1:8000/admin

python manage.py createsuperuser
# 如果之前有账号,但是忘了,可以通过终端下的命令修改指定用户的密码,这里的密码必须8位长度以上的
python manage.py changepassword 用户名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5SSBmyPI-1691197559274)(assets/1557276390641.png)]

创建管理员以后,访问admin站点,先修改站点的语言配置

settings.py

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1xGvmiC-1691197559275)(assets/1553043081445.png)]

访问admin 站点效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DCDiDFhj-1691197559275)(assets/1553043054133.png)]

1. 认证Authentication

可以在配置文件中配置全局默认的认证方案

常见的认证方式:cookie、session、token

/site-packages/rest_framework/settings.py 默认配置文件

REST_FRAMEWORK = {
    # 配置认证方式的选项
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication', # session认证
        'rest_framework.authentication.BasicAuthentication',   # basic认证
    )
}

也可以在具体的视图类中通过设置authentication_classess类属性来设置单独的不同的认证方式

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # 类属性
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    def get(self,request):
        pass

认证失败会有两种可能的返回值,这个需要我们配合权限组件来使用:

  • 401 Unauthorized 未认证
  • 403 Permission Denied 权限被禁止

自定义认证,drfdemo.authentication代码:

from rest_framework.authentication import BaseAuthentication
from django.contrib.auth import get_user_model

class CustomAuthentication(BaseAuthentication):
    """
    自定义认证方式
    """
    def authenticate(self, request):
        """
        认证方法
        request: 本次客户端发送过来的http请求对象
        """
        user = request.query_params.get("user")
        pwd  = request.query_params.get("pwd")
        if user != "root" or pwd != "houmen":
            return None
        # get_user_model获取当前系统中用户表对应的用户模型类
        user = get_user_model().objects.first()
        return (user, None)  # 按照固定的返回格式填写 (用户模型对象, None)

视图调用自定义认证,视图代码:

from django.contrib.auth.models import AnonymousUser
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication
from drfdemo.authentication import CustomAuthentication
# Create your views here.
class HomeAPIView(APIView):
    # authentication_classes = [CustomAuthentication, ]
    def get(self,request):
        """单独设置认证方式"""
        print(request.user) # 在中间件AuthenticationMiddleware中完成用户身份识别的,如果没有登录request.user值为AnonymousUser
        if request.user.id is None:
            return Response("未登录用户:游客")
        else:
            return Response(f"已登录用户:{request.user}")

当然,也可以注释掉上面视图中的配置,改成全局配置。settings.py,代码:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # 配置认证方式的选项【drf的认证是内部循环遍历每一个注册的认证类,一旦认证通过识别到用户身份,则不会继续循环】
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'drfdemo.authentication.CustomAuthentication',          # 自定义认证
        'rest_framework.authentication.SessionAuthentication',  # session认证
        'rest_framework.authentication.BasicAuthentication',    # 基本认证
    )
}

2. 权限Permissions

权限控制可以限制用户对于视图的访问和对于具有模型对象的访问。

  • 在执行视图的as_view()方法的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体模型对象时,会进行模型对象访问权限的判断

使用

可以在配置文件settings中全局设置默认的权限管理类,如

REST_FRAMEWORK = {
    ....
    
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

如果未指明,则采用如下默认配置rest_framework/settings.py

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

也可以在具体的视图中通过permission_classes属性来进行局部设置,如

from django.contrib.auth.models import AnonymousUser
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication
from drfdemo.authentication import CustomAuthentication
# Create your views here.
from rest_framework.permissions import AllowAny,IsAuthenticated
class HomeAPIView(APIView):
    # authentication_classes = [CustomAuthentication, ]
    # permission_classes = [AllowAny]       # 如果项目中大部分视图接口不许直接访问,少数接口可以直接访问,则可以全局配置权限认证,仅在部分不需要认证的视图类中加上AllowAny即可
    permission_classes = [IsAuthenticated]  # 如果项目中大部分视图接口允许直接访问,少数接口必修认证权限,则可以不要权限认证的全局配置,仅在需要认证权限的视图下,局部配置IsAuthenticated即可
    def get(self,request):
        """单独设置认证方式"""
        print(request.user) # 在中间件AuthenticationMiddleware中完成用户身份识别的,如果没有登录request.user值为AnonymousUser
        if request.user.id is None:
            return Response("未登录用户:游客")
        else:
            return Response(f"已登录用户:{request.user}")

提供的权限

  • AllowAny 允许所有用户,默认权限
  • IsAuthenticated 仅通过登录认证的用户
  • IsAdminUser 仅管理员用户
  • IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。

举例

视图代码:

from rest_framework.viewsets import ModelViewSet
from school.models import Student
from school.serializers import StudentModelSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class Hom2APIView(ModelViewSet):
    authentication_classes = [CustomAuthentication, ]
    # 游客仅能查看数据,登录用户可以进行数据的修改/添加/删除
    permission_classes = [IsAuthenticatedOrReadOnly]
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

路由代码:

from django.urls import path
from . import views
urlpatterns = [
    path("s1/", views.HomeAPIView.as_view()),
]

from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("s2", views.Hom2APIView, "s2")
urlpatterns += router.urls

自定义权限

如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图, view表示当前视图对象

  • .has_object_permission(self, request, view, obj)

    是否可以访问模型对象, view表示当前视图, obj为模型数据对象

例如:

在当前子应用下,创建一个权限文件drfdemo.permissions.py中声明自定义权限类:

from rest_framework.permissions import BasePermission
class IsXiaoMingPermission(BasePermission):
    """
    自定义权限,可用于全局配置,也可以用于局部配置
    """

    def has_permission(self, request, view):
        """
        视图权限
        返回结果未True则表示允许访问视图类
        request: 本次客户端提交的请求对象
        view: 本次客户端访问的视图类
        """
        # # 写在自己要实现认证的代码过程。
        # user = request.query_params.get("user")
        # # 返回值为True,则表示通行
        # return user == "xiaoming"
        return True

    def has_object_permission(self, request, view, obj):
        """
        模型权限,写了视图权限(has_permission)方法,一般就不需要写这个了。
        返回结果未True则表示允许操作模型对象
        """
        from school.models import Student
        if isinstance(obj, Student):
            # 限制只有小明才能操作Student模型
            user = request.query_params.get("user")
            return user == "xiaoming"  # 如果不是xiaoming,返回值为False,不能操作
        else:
            # 操作其他模型,直接放行
            return True

视图代码:

from rest_framework.viewsets import ModelViewSet
from school.models import Student
from school.serializers import StudentModelSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from drfdemo.permissions import IsXiaoMingPermission
class Hom2APIView(ModelViewSet):
    # authentication_classes = [CustomAuthentication, ]
    # 游客仅能查看数据,登录用户可以进行数据的修改/添加/删除
    # permission_classes = [IsAuthenticatedOrReadOnly]

    # 自定义权限
    permission_classes = [IsXiaoMingPermission]
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

认证和权限的举例代码:

settings.py,全局配置,代码:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # 配置认证方式的选项【drf的认证是内部循环遍历每一个注册的认证类,一旦认证通过识别到用户身份,则不会继续循环】
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 'drfdemo.authentication.CustomAuthentication',          # 自定义认证
        'rest_framework.authentication.SessionAuthentication',  # session认证
        'rest_framework.authentication.BasicAuthentication',    # 基本认证
    ),
    # 权限设置[全局配置,在视图中可以通过permission_classes进行局部配置,局部配置优先级高于全局配置]
    'DEFAULT_PERMISSION_CLASSES': (
        # 'rest_framework.permissions.IsAuthenticated',
        'drfdemo.permissions.IsXiaoMingPermission',
    ),
}

认证主要的作用就是识别客户端的访问者的身份,但是不能拦截客户端的访问。

权限是基于认证来实现的,但是权限可以针对不同身份的用户,进行拦截用户对视图、模型的访问操作。

3. 限流Throttling

可以对接口访问的频次进行限制,以减轻服务器压力,或者实现特定的业务。

一般用于付费购买次数,投票等场景使用。

基本使用

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSESDEFAULT_THROTTLE_RATES进行全局配置,

REST_FRAMEWORK = {
    # 限流全局配置
    # 'DEFAULT_THROTTLE_CLASSES':[ # 限流配置类
    #     'rest_framework.throttling.AnonRateThrottle', # 未认证用户[未登录用户]
    #     'rest_framework.throttling.UserRateThrottle', # 已认证用户[已登录用户]
    # ],
    'DEFAULT_THROTTLE_RATES':{ # 频率配置
        'anon': '2/day',  # 针对游客的访问频率进行限制,实际上,drf只是识别首字母,但是为了提高代码的维护性,建议写完整单词
        'user': '5/day', # 针对会员的访问频率进行限制,
    }
}

DEFAULT_THROTTLE_RATES 可以使用 second, minute, hourday来指明周期。

也可以在具体视图中通过throttle_classess属性来配置,如

from rest_framework.throttling import UserRateThrottle
class Student2ModelViewSet(ModelViewSet):
    queryset = Student.objects
    serializer_class = StudentModelSerializer
    # 限流局部配置[这里需要配合在全局配置中的DEFAULT_THROTTLE_RATES来设置频率]
    throttle_classes = [UserRateThrottle]

可选限流类

1) AnonRateThrottle

限制所有匿名未认证用户,使用IP区分用户。【很多公司这样的,IP结合设备信息来判断,当然比IP要靠谱一点点而已】

使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次

2)UserRateThrottle

限制认证用户,使用User模型的 id主键 来区分。

使用DEFAULT_THROTTLE_RATES['user'] 来设置频次

3)ScopedRateThrottle

限制用户对于每个视图的访问频次,使用ip或user id。

settings.py,代码:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # 配置认证方式的选项【drf的认证是内部循环遍历每一个注册的认证类,一旦认证通过识别到用户身份,则不会继续循环】
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 'drfdemo.authentication.CustomAuthentication',          # 自定义认证
        'rest_framework.authentication.SessionAuthentication',  # session认证
        'rest_framework.authentication.BasicAuthentication',    # 基本认证
    ),
    # 权限设置[全局配置,在视图中可以通过permission_classes进行局部配置,局部配置优先级高于全局配置]
    'DEFAULT_PERMISSION_CLASSES': (
        # 'rest_framework.permissions.IsAuthenticated',
        'drfdemo.permissions.IsXiaoMingPermission',
    ),
    # 限流全局配置
    'DEFAULT_THROTTLE_CLASSES':[  # 限流配置类
    #     'rest_framework.throttling.AnonRateThrottle',  # 未认证用户[未登录用户]
    #     'rest_framework.throttling.UserRateThrottle',  # 已认证用户[已登录用户]
        'rest_framework.throttling.ScopedRateThrottle',  # 基于自定义的命名空间来限流
    ],
    'DEFAULT_THROTTLE_RATES': {  # 频率配置
        'anon': '1/s',  # 针对游客的访问频率进行限制,实际上,drf只是识别首字母,但是为了提高代码的维护性,建议写完整单词
        'user': '1/s',  # 针对会员的访问频率进行限制,
        'Hom3': '3/m',  # 针对自定义命名空间,进行限流
    }
}

视图代码:

from rest_framework.throttling import AnonRateThrottle,UserRateThrottle
class Hom3APIView(APIView):
    # authentication_classes = [CustomAuthentication]  # 调用自定义认证
    # 局部配置限流
    # throttle_classes = [AnonRateThrottle, UserRateThrottle]
    # 配置自定义限流
    throttle_scope = "Hom3"   # 自定义命名空间[少用,因为对于大部分的集体环境下都是公用一个IP地址]
    def get(self,request):
        return Response(f"访问了视图")

4. 过滤Filtering

对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。

pip install django-filter

settings.py,代码:

INSTALLED_APPS = [
    # ....
    'django_filters',
]

在配置文件中增加过滤器类的全局设置:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # ....代码省略。。。
    
    # 过滤查询,全局配置
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend'
    ],
}

在视图类中添加类属性filter_fields,指定可以过滤的字段

class Hom4APIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_fields = ["sex","classmate"]
    # list方法中进行调用->调用了GenericAPIView中声明的filter_queryset方法---> 配置中的过滤器类的filter_queryset---> filter_fields
    
# 单个字段过滤
# http://127.0.0.1:8000/opt/s4/?classmate=301
# http://127.0.0.1:8000/opt/s4/?sex=1
# 多个字段过滤
# http://127.0.0.1:8000/opt/s4/?classmate=502&sex=2

路由代码:

from django.urls import path,include
from . import views

from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("s2", views.Hom2APIView, "s2")
router.register("s4", views.Hom4APIView, "s4")

urlpatterns = [
    path("s1/", views.HomeAPIView.as_view()),
    path("", include(router.urls)),  # 等价于  urlpatterns += router.urls
    path("s3/", views.Hom3APIView.as_view()),
    path("s3/", views.Hom3APIView.as_view()),
]

局部设置,直接在视图中,指定当前视图类中调用的过滤器类

# 先注释掉settings中的全局过滤配置
from rest_framework.viewsets import ModelViewSet
from students.models import Student
from students.serializers import StudentModelSerializer
# Create your views here.
from django_filters.rest_framework import DjangoFilterBackend
class Hom4APIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend, ]
    filter_fields = ["sex","classmate"]
    # list方法中进行调用->调用了GenericAPIView中声明的filter_queryset方法---> 配置中的过滤器类的filter_queryset---> filter_fields

5. 排序Ordering

对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。

使用方法:

在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。

前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。

配置文件,settings.py,代码:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # 。。。代码省略
    # 过滤查询,全局配置
    # 过滤和排序使用了一个公用的配置项,所以2个组件要么一起全局配置,要么就一起局部配置
    'DEFAULT_FILTER_BACKENDS': [
    #     'django_filters.rest_framework.DjangoFilterBackend',  # 过滤
        'rest_framework.filters.OrderingFilter',  # 排序
    ],
}

视图代码:

from rest_framework.viewsets import ModelViewSet
from students.models import Student
from students.serializers import StudentModelSerializer
# Create your views here.
from django_filters.rest_framework import DjangoFilterBackend
class Hom4APIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 局部过滤
    # filter_backends = [DjangoFilterBackend, OrderingFilter]
    # 过滤字段
    # filter_fields = ["sex","classmate"]
    # 数据排序
    ordering_fields = ['id', 'age']

# 127.0.0.1:8000/books/?ordering=-age
# -id 表示针对id字段进行倒序排序
# id  表示针对id字段进行升序排序

上面提到,因为过滤和排序公用了一个配置项,所以排序和过滤要一起使用,则必须整个项目,要么一起全局过滤排序,要么一起局部过滤排序。决不能出现,一个全局,一个局部的这种情况,局部会覆盖全局的配置。

from rest_framework.viewsets import ModelViewSet
from students.models import Student
from students.serializers import StudentModelSerializer
# Create your views here.
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class Hom4APIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 局部过滤
    filter_backends = [DjangoFilterBackend, OrderingFilter]
    # 过滤字段
    filter_fields = ["sex","classmate"]
    # list方法中进行调用->调用了GenericAPIView中声明的filter_queryset方法---> 配置中的过滤器类的filter_queryset---> filter_fields

    # 数据排序
    ordering_fields = ['id', 'age']
    
# http://127.0.0.1:8000/opt/demo4/?ordering=id&classmate=301

6. 分页Pagination

因为django默认提供的分页器主要使用于前后端不分离的业务场景,所以REST framework也提供了分页的支持。

我们可以在配置文件中设置全局的分页方式,如:

REST_FRAMEWORK = {
    # 分页,全局配置
    # 页码分页器,  ?page=页码&page_size=单页数据量
    # 'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    # 偏移量分页器, ?limit=单页数据量&offset=数据开始下标
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10  # 每页数目,如果不设置,则没有进行分配
}
# 如果在settings.py配置文件中, 设置了全局分页,那么在drf中凡是调用了ListModelMixin的list(),都会自动分页。如果项目中出现大量需要分页的数据,只有少数部分的不需要分页,则可以在少部分的视图类中关闭分页功能。
# 另外,视图类在使用过分页以后,务必在编写queryset属性时,模型.objects后面调用结果。例如:
# Student.objects.all()
class Hom5APIView(ListAPIView):
	pagination_class = None

也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

可选分页器

1) PageNumberPagination

前端访问网址形式:

GET  http://127.0.0.1:8000/students/?page=4

可以在子类中定义的属性:

  • page_size 每页数目
  • page_query_param 前端发送的页数关键字名,默认为"page"
  • page_size_query_param 前端发送的每页数目关键字名,默认为None
  • max_page_size 前端最多能设置的每页数量

分页器类,paginations,代码:

from  rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
# PageNumberPagination,以页码作为分页条件
# page=1&page_size=10      第1页
# page=2&page_size=10      第2页
# ...
# LimitOffsetPagination,以数据库查询的limit和offset数值作为分页条件
# limit=10&offset=0   第1页
# limit=10&offset=10  第2页
# ...

# 自定义分页器,PageNumberPagination
class StudentPageNumberPagination(PageNumberPagination):
    page_query_param = "page" # 查询字符串中代表页码的变量名
    page_size_query_param = "size" # 查询字符串中代表每一页数据的变量名
    page_size = 2 # 每一页的数据量
    max_page_size = 4 # 允许客户端通过查询字符串调整的最大单页数据量

视图,views ,代码:


from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination

# 分页类往往会单独的保存到一个独立的模块,例如:当前子应用目录下创建一个pagination.py保存,使用时导包
class Hom5PageNumberPagination(PageNumberPagination):
    page_size = 10                  # 默认分页的每一页数据量
    max_page_size = 20              # 设置允许客户端通过地址栏参数调整的最大单页数据量
    page_query_param = "pn"         # 地址栏上代表页码的变量名,默认是 page
    page_size_query_param = "size"  # 地址栏上代表单页数据量的变量名,默认是page_size

class Hom5APIView(ModelViewSet):
    # queryset = Student.objects  # 这句话在没有进行分页时不会报错,调用了分页则会报错!
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    # 局部分页
    # pagination_class = None  # 关闭分页功能
    # 局部分页往往采用自定义分页类,进行分页数据量的配置
    pagination_class = Hom5PageNumberPagination

    def list(self, request, *args, **kwargs):
        # 获取django的配置项
        from django.conf import settings

        # 获取rest_framework的配置项
        # from rest_framework.settings import api_settings
        # print(api_settings.DEFAULT_PAGINATION_CLASS)
        return super().list(request, *args, **kwargs)

2)LimitOffsetPagination

前端访问网址形式:

GET http://127.0.0.1/four/students/?limit=100&offset=100

可以在子类中定义的属性:

  • default_limit 默认限制,默认值与PAGE_SIZE设置一直
  • limit_query_param limit参数名,默认’limit’
  • offset_query_param offset参数名,默认’offset’
  • max_limit 最大limit限制,默认None

分页类,代码:

from  rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
# PageNumberPagination,以页码作为分页条件
# page=1&size=10      第1页
# page=2&size=10      第2页
# LimitOffsetPagination,以数据库查询的limit和offset数值作为分页条件
# limit=10&offset=0   第1页
# limit=10&offset=10  第2页

# LimitOffsetPagination
class StudentLimitOffsetPagination(LimitOffsetPagination):
    limit_query_param = "limit" # 查询字符串中代表每一页数据的变量名
    offset_query_param = "offset" # 查询字符串中代表页码的变量名
    default_limit = 2 # 每一页的数据量
    max_limit = 4 # 允许客户端通过查询字符串调整的最大单页数据量

视图,views,代码:

from .paginations import StudentPageNumberPagination,StudentLimitOffsetPagination
class Student3ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 取消当前视图类的分页效果
    # pagination_class = None
    # 局部分页
    pagination_class = StudentLimitOffsetPagination

7. 异常处理 Exceptions

REST framework本身在APIView提供了异常处理,但是仅针对drf内部现有的接口开发相关的异常进行格式处理,但是开发中我们还会使用到各种的数据或者进行各种网络请求,这些都有可能导致出现异常,这些异常在drf中是没有进行处理的,所以就会冒泡给django框架了,django框架会进行组织错误信息,作为html页面返回给客户端,所在在前后端分离项目中,可能js无法理解或者无法接收到这种数据,甚至导致js出现错误的情况。因此为了避免出现这种情况,我们可以自定义一个属于自己的异常处理函数,对于drf无法处理的异常,我们自己编写异常处理的代码逻辑。

针对于现有的drf的异常处理进行额外添加属于开发者自己的逻辑代码,一般我们编写的异常处理函数,会写一个公共的目录下或者主应用目录下。这里主应用下直接创建一个excepitions.py,代码:

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
# 针对mysql、mongoDB、redis、第三方数据接口
def custom_exception_handler(exc, context):
    """
    自定义异常函数
    exc: 异常实例对象,发生异常时实例化出来的
    context: 字典,异常发生时python解释器收集的执行上下文信息。
             所谓的执行上下文就是python解释器在执行代码时保存在内存中的变量、函数、类、对象、模块等一系列的信息组成的环境信息。
    """
    response = exception_handler(exc, context)

    if response is None:
        """当前异常,drf无法处理"""
        if isinstance(exc, ZeroDivisionError):
            response = Response({"detail":"数学老师还有30秒达到战场,0不能作为除数!"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    return response

在配置文件中声明自定义的异常处理,settings,代码:

REST_FRAMEWORK = {
    # 异常配置
    'EXCEPTION_HANDLER': 'drfdemo.exceptions.custom_exception_handler'
}

如果未声明自定义异常的话,drf会采用默认的方式,使用自己封装的异常处理函数,rest_frame/settings.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

例如:

补充上处理关于数据库的异常,这里使用其他异常来举例:

主应用.exceptions,代码:

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
from django.db import DatabaseError
# 针对mysql、mongoDB、redis、第三方数据接口
def custom_exception_handler(exc, context):
    """
    自定义异常函数
    exc: 异常实例对象,发生异常时实例化出来的
    context: 字典,异常发生时python解释器收集的执行上下文信息。
             所谓的执行上下文就是python解释器在执行代码时保存在内存中的变量、函数、类、对象、模块等一系列的信息组成的环境信息。
    """
    response = exception_handler(exc, context)
    print(f"context={context}")
    if response is None:
        """当前异常,drf无法处理"""
        view = context["view"] # 获取异常发生时的视图类
        request = context["request"] # 获取异常发生时的客户端请求对象
        if isinstance(exc, ZeroDivisionError):
            response = Response({"detail":"数学老师还有30秒达到战场,0不能作为除数!"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        if isinstance(exc, TypeError):
            print('[%s]: %s' % (view, exc))
            response = Response({'detail': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return response

视图中,故意报错:

from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination

class Hom5PageNumberPagination(PageNumberPagination):
    page_size = 10                  # 默认分页的每一页数据量
    max_page_size = 20              # 设置允许客户端通过地址栏参数调整的最大单页数据量
    page_query_param = "pn"         # 地址栏上代表页码的变量名,默认是 page
    page_size_query_param = "size"  # 地址栏上代表单页数据量的变量名,默认是page_size

class Hom5APIView(ModelViewSet):
    queryset = Student.objects  # 这句话在没有进行分页时不会报错,调用了分页则会报错,所以会进入异常处理!
    # queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    # 局部分页
    # pagination_class = None  # 关闭分页功能
    # 局部分页往往采用自定义分页类,进行分页数据量的配置
    pagination_class = Hom5PageNumberPagination

    def list(self, request, *args, **kwargs):
        # 获取django的配置项
        from django.conf import settings

        # 获取rest_framework的配置项
        # from rest_framework.settings import api_settings
        # print(api_settings.DEFAULT_PAGINATION_CLASS)
        return super().list(request, *args, **kwargs)

REST framework定义的异常

  • APIException 所有异常的父类
  • ParseError 解析错误
  • AuthenticationFailed 认证失败
  • NotAuthenticated 尚未认证
  • PermissionDenied 权限拒绝
  • NotFound 404 未找到
  • MethodNotAllowed 请求方式不支持
  • NotAcceptable 要获取的数据格式不支持
  • Throttled 超过限流次数
  • ValidationError 校验失败

也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。

8. 自动生成接口文档

REST framework可以自动帮助我们生成接口文档。

接口文档以网页的方式呈现。

自动接口文档能生成的是继承自APIView及其子类的视图。

coreapi

安装依赖

REST framewrok生成接口文档需要coreapi库的支持。

pip install coreapi

设置接口文档访问路径

在总路由中添加接口文档路径。

文档路由对应的视图配置为rest_framework.documentation.include_docs_urls

参数title为接口文档网站的标题。总路由urls.py,代码:

from rest_framework.documentation import include_docs_urls

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

在settings.py中配置接口文档。

INSTALLED_APPS = [
 
    'coreapi',


]
REST_FRAMEWORK = {
    # 。。。 其他选项
    # 接口文档
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
}

8.3. 文档描述说明的定义位置

1) 单一方法的视图,可直接使用类视图的文档字符串,如

class BookListView(generics.ListAPIView):
    """
    返回所有图书信息
    """

2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如

class BookListCreateView(generics.ListCreateAPIView):
    """
    get:
    返回所有图书信息.

    post:
    新建图书.
    """

3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    """
    list:
    返回图书列表数据

    retrieve:
    返回图书详情数据

    latest:
    返回最新的图书数据

    read:
    修改图书的阅读量
    """

访问接口文档网页

浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wJtyTHNM-1691197559276)(assets/接口文档页面.png)]

两点说明:

1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫做read

2)参数的Description需要在模型类或序列化器类的字段中以help_text选项定义,如:

class Student(models.Model):
    ...
    age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄')
    ...

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
            'age': {
                'required': True,
                'help_text': '年龄'
            }
        }

yasg

安装

pip install drf-yasg

配置,settings.py,代码:

INSTALLED_APPS = [

    'drf_yasg',  # 接口文档drf_yasg

]

总路由,

from django.contrib import admin
from django.urls import path, include
from rest_framework.documentation import include_docs_urls

# yasg的视图配置类,用于生成a'pi
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
    openapi.Info(
        title="drf接口文档",  # 必传
        default_version='v1.0,0',  # 必传
        description="描述信息",
        terms_of_service='',
        contact=openapi.Contact(email="649641514@qq.com"),
        license=openapi.License(name="协议版本")
    ),
    public=True,
    # permission_classes=(rest_framework.permissions.AllowAny)  # 权限类
)


urlpatterns = [
    # 文档路由
    path('doc/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger'),
    path('docs/', include_docs_urls(title='站点页面标题')),
    path('admin/', admin.site.urls),
    path('students/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path('school/', include("school.urls")),
    path("req/", include("req.urls")),
    path("demo/", include("demo.urls")),
    path("opt/", include("opt.urls")),
]

http://127.0.0.1:8000/doc/,访问效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6dSlTZQE-1691197559276)(assets/image-20210901182801990.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYVYIXsn-1691197559277)(assets/image-20210901182739563.png)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/838357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言参悟-数据类型

C语言的数据类型 一、概述二、基础数据类型1. 整数1. 计算2. 索引 2. 浮点数3. 字符4. 字符串5. 指针 三、特殊数据类型1. 枚举2. 共用体2. struct结构体 四、数据类型修饰符1. const2. unsigned、signed 一、概述 编程语言为抽象这个物理世界提供了依据,其中对于描…

[Docker实现测试部署CI/CD----自由风格和流水线的CD操作(6)]

目录 12、自由风格的CD操作发布 V1.0.0 版本修改代码并推送GitLab 中项目打 Tag 发布 V2.0.0 版本Jenkins 配置 tag 参数添加 Git 参数添加 checkout 命令修改构建命令配置修改 SSH 配置 部署 v1.0.0重新构建工程构建结果 部署 v2.0.0重新构建工程访问 部署v3.0.0 13、流水线任…

Delphi Architect Crack,部署支持Swagger

Delphi Architect Crack,部署支持Swagger 单一代码库-用更少的编码工作为所有主要平台创建应用程序。写一次,到处编译。 Windows-使用最新的用户界面控件、WinRT API和HighDPI相关功能,使Windows的VCL应用程序现代化。 远程桌面-使用改进的VCL和IDE远程桌…

Java问题排查工具Arthas安装教程

Java问题排查工具Arthas入门教程 什么是阿里Arthas? 在生产环境经常遇到大量的日志,同时还有一些性能问题,需要进行进程分析,排查,有时候确实比较花时间,所以可以借助一些开源的框架来实现,Art…

全志F1C200S嵌入式驱动开发(从DDR中截取内存)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 linux内核起来的时候,不一定所有的内存都是分配给linux使用的。有的时候,我们是希望能够截留一部分内存的。为什么保留这部分内存呢?这里面可以有很多的用途。比如说,第一,如果…

Python GUI编程(Tkinter)

Python GUI编程(Tkinter) Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows …

Qt下载慢/无法下载解决方式

文章目录 一. Qt在线安装下载二. 安装方式 一. Qt在线安装下载 官网下载:https://www.qt.io/download清华源下载:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ 二. 安装方式 进入下载好的目录 在目录栏输入CMD&…

vue+element中如何设置单个el-date-picker开始时间和结束时间关联

功能&#xff1a;选了开始时间&#xff0c;则结束时间只能选择开始时间之后的&#xff1b;选了结束时间&#xff0c;则开始时间只能选择结束时间之前的 重点是picker-options属性 图示&#xff1a; 代码展示: // body 内部<el-form-item><el-date-pickerv-model&qu…

vscode无法连接远程服务器的可能原因:远程服务器磁盘爆了

vscode输入密码后一直等待&#xff0c;无法进入远程服务器终端&#xff1a; 同时Remote-SSH输出包含以下内容 在日志中的以下几个部分&#xff1a; [17:15:05.529] > wget download failed 这表明VS Code尝试在远程服务器上下载VS Code服务器时失败了。> Cannot write…

程序环境和预处理(含C语言程序的编译+链接)--1

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN…

嵌入式面试刷题(day3)

文章目录 前言一、怎么判断两个float是否相同二、float数据可以移位吗三、数据接收和发送端大小端不一致怎么办四、怎么传输float类型数据1.使用联合进行传输2.使用字节流3.强制类型转换 总结 前言 本篇文章我们继续讲解嵌入式面试刷题&#xff0c;给大家继续分享嵌入式中的面…

docker search 镜像报错: connect: no route to host (桥接模式配置静态IP)

如下 原因 可能有多种&#xff1a; ① 没有开放防火墙端口 ② ip地址配置有误 解决 我是因为虚拟机采用了桥接模式&#xff0c;配置静态ip地址有问题。 先确认虚拟机采用的是 桥接模式&#xff0c;然后启动虚拟机。 1、打开命令行&#xff0c;输入下面指令&#xff0c;打开…

【Docker】Docker容器数据卷、容器卷之间的继承和DockerFIle的详细讲解

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

大数据教材推荐|Python数据挖掘入门、进阶与案例分析

主 编&#xff1a; 卢滔&#xff0c;张良均&#xff0c;戴浩&#xff0c;李曼&#xff0c;陈四德 出版社&#xff1a; 机械工业出版社 内容提要 本书从实践出发&#xff0c;结合11个“泰迪杯”官方推出的赛题&#xff0c;按照赛题的难易程度进行排序&#xff0c;由浅入深…

Meta开源AI音频和音乐生成模型

在过去的几年里&#xff0c;我们看到了AI在图像、视频和文本生成方面的巨大进步。然而&#xff0c;音频生成领域的进展却相对滞后。MetaAI这次再为开源贡献重磅产品&#xff1a;AudioCraft&#xff0c;一个支持多个音频生成模型的音频生成开发框架。 AudioCraft开源地址 开源地…

阿里为啥禁止三表Join关联?

阿里出过一个《Java开发手册》&#xff0c;上面有一条规约是禁止超过三张表的join。 为什么要禁止&#xff0c;其实最主要的原因就是join的效率比较低。 mysql只有一种表连接类型:嵌套循环连接(nested-loop)&#xff0c;不支持排序-合并连接(sort-merge join)与散列连接(hash …

【动态规划刷题 5】 最小路径和地下城游戏

最小路径和 链接: 64. 最小路径和 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 输入&#xff1a;grid [[1,3,1],[1,5,1],[4,2,1]] 输…

《OWASP代码审计》学习——跨站脚本注入(XSS)

一、跨站脚本概述 1.什么是跨站脚本 跨站点脚本(XSS)是一种编码注入漏洞。它通常出现在 web 应用程序中。XSS 使攻击者能够向其他用户浏览的网页中注入恶意内容。XSS 允许攻击者绕过访问控制&#xff0c;它是 OWASP Top10 最常见的漏洞之一。XSS 是网络服务器上的第二大漏洞。…

CSS元素的显示模式

1、现在我想做成小米左侧边栏这样的效果&#xff0c;该怎么做呢&#xff1f; 2、小米商城触碰之后会显示出新的商品案例 3、一碰到之后会出现这个列表 4、这里涉及到了元素显示模式&#xff1a; 5、用人进行划分可以分为男人和女人&#xff0c;根据男人和女人的特性进行相应的…

Leetcode-每日一题【剑指 Offer 17. 打印从1到最大的n位数】

题目 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 示例 1: 输入: n 1输出: [1,2,3,4,5,6,7,8,9] 说明&#xff1a; 用返回一个整数列表来代替打印 n 为正整数 解题思路 前置知识 M…