zoukankan      html  css  js  c++  java
  • 07.APIView

    01.APIView介绍

     1.1 APIView特点

    APIView是REST framework提供的所有视图的基类,继承自Django的View类。

    APIViewView的区别:

    • 请求对象:传入到视图中的request对象是REST framework的Request对象,而不再是Django原始的HttpRequest对象;
    • 响应对象:视图可以直接返回REST framework的Response对象,响应数据会根据客户端请求头Accpet自动转换为对应的格式进行返回;
    • 异常处理:任何APIException的子异常都会被DRF框架默认的异常处理机制处理成对应的响应信息返回给客户端;
    • 其他功能:认证、权限、限流。

    1.2 Request对象

    • 视图继承APIView之后,传入视图的request对象是DRF框架提供的Request类的对象
    • Request类的对象有两个属性:
    属性名 说明
    data 包含解析之后的请求体数据,已经解析为了字典或类字典,相当于Django原始request对象的body、POST、FILES属性。
    query_params 包含解析之后的查询字符串数据,相当于Django原始request对象的GET属性

    1.3 Response对象

    • 视图继承APIView之后,响应时可以统一返回Response对象,格式如下:
    from rest_framework.response import Response
    
    response = Response(<原始响应数据>)
    • 原始的响应数据,会根据客户端请求头的Accpet,自动转换为对应的格式并进行返回,如:
    Accept请求头 说明
    application/json 服务器会将原始响应数据转换为json数据进行返回,没指定Accept时,默认返回json
    text/html 服务器会将原始响应数据转换为html网页进行返回

    02.DRF全局配置

     2.1 settings.py注册

    • 注册
    INSTALLED_APPS = [
        'rest_framework',
        'django_filters',
    ]

    2.2 全局配置DRF

    # 过滤器
    # 1,安装 django-filter
    # 2,注册应用
    # 3,配置settings, 在view里配置可过滤的字段
    # 4,使用 查询字符串携带过滤信息
    
    REST_FRAMEWORK = {
        # 1.认证器(全局):用户登录校验用户名密码或者token是否合法
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 在DRF中配置JWT认证
            'rest_framework.authentication.SessionAuthentication',          # 使用session时的认证器
            'rest_framework.authentication.BasicAuthentication'             # 提交表单时的认证器
        ],
        #2.权限配置(全局): 顺序靠上的严格(根据不同的用户角色,可以操作不同的表)
        'DEFAULT_PERMISSION_CLASSES': [
            # 'rest_framework.permissions.IsAdminUser',                # 管理员可以访问
            # 'rest_framework.permissions.IsAuthenticated',            # 认证用户可以访问
            # 'rest_framework.permissions.IsAuthenticatedOrReadOnly',  # 认证用户可以访问, 否则只能读取
            # 'rest_framework.permissions.AllowAny',                   # 所有用户都可以访问
        ],
        #3.限流(防爬虫)
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle',
        ],
        #3.1限流策略
        'DEFAULT_THROTTLE_RATES': {
            'user': '1000/hour',    # 认证用户每小时100次
            'anon': '300/day',       # 未认证用户每天能访问3次
        },
    
        'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
        'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
        'DEFAULT_VERSIONING_CLASS': None,
    
        #4.分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        # 每页返回数量
        'PAGE_SIZE': 10,  # 默认 None
    
        #5.过滤器后端
        'DEFAULT_FILTER_BACKENDS': [
            'django_filters.rest_framework.DjangoFilterBackend',
            # 'django_filters.rest_framework.backends.DjangoFilterBackend', 包路径有变化
        ],
    
        #5.1过滤排序(全局):Filtering 过滤排序
        'SEARCH_PARAM': 'search',
        'ORDERING_PARAM': 'ordering',
    
        'NUM_PROXIES': None,
    
        #6.版本控制:Versioning  接口版本控制
        'DEFAULT_VERSION': None,
        'ALLOWED_VERSIONS': None,
        'VERSION_PARAM': 'version',
    }

    03.APIView基本使用

    3.1 book/models.py

    from django.db import models
    
    #定义图书模型类BookInfo
    class BookInfo(models.Model):
        btitle = models.CharField(max_length=20, verbose_name='名称')
        bpub_date = models.DateField(verbose_name='发布日期')
        bread = models.IntegerField(default=0, verbose_name='阅读量')
        bcomment = models.IntegerField(default=0, verbose_name='评论量')
        is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
    
        class Meta:
            db_table = 'tb_books'  # 指明数据库表名
            verbose_name = '图书'  # 在admin站点中显示的名称
            verbose_name_plural = verbose_name  # 显示的复数名称
    
        def __str__(self):
            """定义每个数据对象的显示信息"""
            return self.btitle

    3.2 book/serializers.py

    # -*- coding: utf-8 -*-
    from rest_framework import serializers
    from book.models import BookInfo
    
    class BookInfoSerializer2(serializers.ModelSerializer):
        """图书序列化器类"""
        class Meta:
            model = BookInfo
            fields = '__all__'

    3.3 book/views.py

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from book import serializers
    from book.models import BookInfo
    
    class APIViewBookInfoViewSet(APIView):
        def get(self, request):
            obj = BookInfo.objects.all()
            ser = serializers.BookInfoSerializer2(instance=obj, many=True)  # 关联数据多条
            return Response(ser.data)

    3.4 book/urls.py

    from django.urls import re_path,path
    from book import views
    
    urlpatterns = [
        path('book1/', views.APIViewBookInfoViewSet.as_view()),
    ]

    3.5 测试接口

    3.5.1 get获取数据

    http://127.0.0.1:8000/book/book1/ 

    [
        {
            "id": 1,
            "btitle": "西游记",
            "bpub_date": "2020-08-11",
            "bread": 666,
            "bcomment": 123,
            "heroinfo_set": [],
            "xxx": "西游记"
        },
        {
            "id": 2,
            "btitle": "水浒传",
            "bpub_date": "2020-08-11",
            "bread": 200,
            "bcomment": 100,
            "heroinfo_set": [],
            "xxx": "水浒传"
        }
    ]

    3.5.2 post添加数据

    http://127.0.0.1:8000/book/book1/


    3.5.3 put修改数据

    http://127.0.0.1:8000/book/book1/?pk=4 

    04.自定义分页

    4.1 自定义分页

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.pagination import PageNumberPagination
    from book import serializers
    from book.models import BookInfo
    
    
    # 分页(局部):自定义分页器 局部
    class PageNum(PageNumberPagination):
        # 查询字符串中代表每页返回数据数量的参数名, 默认值: None
        page_size_query_param = 'page_size'
        # 查询字符串中代表页码的参数名, 有默认值: page
        # page_query_param = 'page'
        # 一页中最多的结果条数
        max_page_size = 2
    
    class APIViewBookInfoViewSet(APIView):
        def get(self, request):
            queryset = BookInfo.objects.all()
            # 分页
            pg = PageNum()
            page_objs = pg.paginate_queryset(queryset=queryset, request=request, view=self)
            ser = serializers.BookInfoSerializer2(instance=page_objs, many=True)  # 关联数据多条
            return Response(ser.data)

    4.2 测试分页效果

    查找第一页,每页显示两条数据

    http://127.0.0.1:8000/book/book1/?page=1&page_size=2

    05.认证权限

    5.1 使用自带权限

    # 注:认证类都在 `rest_framework.authentication` 模块中
    from rest_framework.authentication import SessionAuthentication
    from rest_framework.permissions import IsAuthenticated, AllowAny
    
    
    class APIViewBookInfoViewSet(APIView):
        authentication_classes = (SessionAuthentication,)
        # permission_classes = [IsAuthenticated]   # 只有认证用户才能访问接口
        permission_classes = [AllowAny]   # 只有认证用户才能访问接口
    
        def get(self, request):
            queryset = BookInfo.objects.all()
            # 分页
            pg = PageNum()
            page_objs = pg.paginate_queryset(queryset=queryset, request=request, view=self)
            ser = serializers.BookInfoSerializer2(instance=page_objs, many=True)  # 关联数据多条
            return Response(ser.data)


    5.2 自定义权限

    5.2.1 自定义权限

    from rest_framework.permissions import BasePermission
    
    # 自定义权限(局部)
    class MyPermission(BasePermission):
        # has_permission 是用户对这个视图有没有 GET POST PUT PATCH DELETE 权限的分别判断
        def has_permission(self, request, view):
            print('has_perm')
            # print(view.kwargs.get("pk"), request.user.id)
            """判断用户对模型有没有访问权"""
            # 任何用户对使用此权限类的视图都有访问权限
            if request.user.is_superuser:
                # 管理员对用户模型有访问权
                return True
            elif view.kwargs.get('pk') == str(request.user.id):
                # 携带的id和用户的id相同时有访问权
                return True
            return False
    
        # has_object_permission 是用户过了 has_permission 判断有权限以后,再判断这个用户有没有对一个具体的对象有没有操作权限
        def has_object_permission(self, request, view, obj):
            print('has_object_perm')
            """获取单个数据时,判断用户对某个数据对象是否有访问权限"""
            if request.user.id == obj.id:
                return True
            return False

    5.2.2 使用自定义权限

    # 注:认证类都在 `rest_framework.authentication` 模块中
    from rest_framework.authentication import SessionAuthentication
    
    class APIViewBookInfoViewSet(APIView):
        authentication_classes = (SessionAuthentication,)
        permission_classes = [MyPermission,]     # 只有认证用户才能访问接口
    
        def get(self, request):
            queryset = BookInfo.objects.all()
            # 分页
            pg = PageNum()
            page_objs = pg.paginate_queryset(queryset=queryset, request=request, view=self)
            ser = serializers.BookInfoSerializer2(instance=page_objs, many=True)  # 关联数据多条
            return Response(ser.data)

    06.限流

     6.1 全局配置

    • DEFAULT_THROTTLE_RATES 可以使用 secondminutehour 或day来指明限流周期。
    REST_FRAMEWORK = {
        ...
        # 针对匿名用户和认证通过用户分别进行限流控制
        'DEFAULT_THROTTLE_CLASSES': (
            # 针对未登录(匿名)用户的限流控制类
            'rest_framework.throttling.AnonRateThrottle',
            # 针对登录(认证通过)用户的限流控制类
            'rest_framework.throttling.UserRateThrottle'
        ),
        # 指定限流频次
        'DEFAULT_THROTTLE_RATES': {
            # 认证用户的限流频次
            'user': '5/minute',
            # 匿名用户的限流频次
            'anon': '3/minute',
        },
    }

    6.2 指定视图配置

    • 也可以某个视图中通过 throttle_classes 属性来指定某视图所使用的限流控制类
    from rest_framework.throttling import AnonRateThrottle
    
    class BookInfoViewSet(ReadOnlyModelViewSet):
        ...
        # 此时设置当前视图仅针对匿名用户进行限流控制
        throttle_classes = [AnonRateThrottle]

    07.过滤

     7.1 自定义过滤

    from django_filters.rest_framework import DjangoFilterBackend
    
    class APIViewBookInfoViewSet(APIView):
        filter_backends = (DjangoFilterBackend,)
        # 指定过滤字段, 不设置, 过滤功能不起效
        filter_fields = ('btitle', )  # ?username=tom&phone=&is_active=true
    
        def filter_queryset(self, queryset):
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
    
        def get(self, request):
            queryset = BookInfo.objects.all()
            # 过滤
            queryset = self.filter_queryset(queryset)
    
            # 分页
            pg = PageNum()
            page_objs = pg.paginate_queryset(queryset=queryset, request=request, view=self)
            ser = serializers.BookInfoSerializer2(instance=page_objs, many=True)  # 关联数据多条
            return Response(ser.data)

    7.2 测试过滤功能

     http://127.0.0.1:8000/book/book1/?btitle=西游记

    08.排序

    8.1 配置排序

    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import OrderingFilter
    
    class APIViewBookInfoViewSet(APIView):
        filter_backends = (DjangoFilterBackend,OrderingFilter)
        # 指定过滤字段, 不设置, 过滤功能不起效
        filter_fields = ('btitle', )  # ?username=tom&phone=&is_active=true
        # 5.1指定排序字段, 不设置, 排序功能不起效
        ordering_fields = ('id',)    # ?ordering=-id
    
        def filter_queryset(self, queryset):
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset

    8.2 测试排序功能

    http://127.0.0.1:8000/book/book1/?ordering=-id

  • 相关阅读:
    .net C# 利用Session防重复点击防重复提交
    子报表修改后需要重新导入,0.00显示.00的调整方法
    svn错误 svnserve.conf:12: Option expected解决办法
    mysql远程访问 登录ERROR 1130: is not allowed to connect to this MySQL server解决办法
    phpmyadmin新加用户登陆不了,测试解决方案。
    自己封装的php Curl并发处理,欢迎提出问题优化。
    js和php计算图片自适应宽高算法实现
    jquery获取浏览器宽高
    swftools中的pdf2swf转换Error overflow ID 65535 解决办法
    php 根据ip获取城市以及网络运营商名称(利用qqwry.dat)
  • 原文地址:https://www.cnblogs.com/xiaoxiamiaichiyu/p/14789383.html
Copyright © 2011-2022 走看看