zoukankan      html  css  js  c++  java
  • Django--restframework

    Django--restframework

    一 . rest framework框架的认识

    • 它是基于Django的,帮助我们快速开发符合RESTful规范的接口框架

    • 安装 pip

    二 . 什么是RESTful风格

    三 . 基于Django实现

    urls.py

    urlpatterns = [
        path('index/', views.TestView.as_view()),  # 函数视图
    ]
    

    views.py

    from django.forms import model_to_dict
    from django.http import HttpResponse, JsonResponse
    from django.views import View
    
    class TestView(View):
        def get(self, request):
            data = request.GET.get('name')  # View获取前端传递的GET请求name参数
            return HttpResponse(data)
    
        def post(self, request):
            data = request.POST.get('username')  # View获取前端传递的POST请求username参数
            return HttpResponse(data)
    
    class TestView(View):
         #基于django的序列化 for循环
        def get(self, request):
            queryset = User.objects.all()
            print(queryset)
            list = []
            for i in queryset:
                list.append(model_to_dict(i))  # model对象转换成dict
                # list.append({
                #     "name": i.name,
                #     "age": i.age,
                #     "home": i.home
                # })
                print(list)
            # In order to allow non-dict objects to be serialized set the safe parameter to False.
            # return JsonResponse(list)——》一定要加上:safe=False
            return JsonResponse(list, safe=False)
    
    

    四 . 基于Django Rest Framework框架实现

    DRF框架之视图集APIView:https://www.cnblogs.com/tjw-bk/p/13886536.html

    models.py

    from django.db import models
    
    # 角色表
    class Role(models.Model):
        role_name = models.CharField(max_length=32, verbose_name='角色')
    
        class Meta:
            db_table = 'tb_role'
            verbose_name = '角色'
            verbose_name_plural = verbose_name
    #用户表
    class User(models.Model):
        name = models.CharField(max_length=12, verbose_name='姓名')
        age = models.IntegerField(verbose_name='年龄')
        home = models.CharField(max_length=255, null=True, verbose_name='家乡')
        role = models.ManyToManyField(Role)
        class_room = models.ForeignKey(to='ClassRoom', on_delete=models.CASCADE, null=True)
    
        class Meta:
            db_table = 'tb_user'
            verbose_name = '用户'
            verbose_name_plural = verbose_name
    
    #班级表
    class ClassRoom(models.Model):
        classroom = models.CharField(max_length=20, verbose_name='班级')
        address = models.CharField(max_length=32, verbose_name='地址')
    
        class Meta:
            db_table = 'tb_clasroom'
            verbose_name = '班级'
            verbose_name_plural = verbose_name
    
    

    urls.py

    # 子路由文件
    from django.urls import include, path
    from user import views
    from rest_framework.routers import SimpleRouter, DefaultRouter
    
    # 自动生成路由方法,必须使用视图集
    # router=SimpleRouter() #没有根路由 /user/无法识别 生产环境使用
    router = DefaultRouter()  # 有根路由 # 开发环境用,有主界面
    router.register(r'user2', views.UserModelViewSet)  # 配置路由
    
    urlpatterns = [
        path('user/', views.UserView.as_view()),
        path('',include(router.urls))
    ]
    
    

    自定义序列化页面serializers.py

    from rest_framework import serializers
    from .models import *
    
    
    class UserSerializers(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = "__all__"
            depth = 1  # 外键序列化
    

    1. 分页

    1.1 PageNumberPagination

    前端访问网址形式:

    GET http://192.168.56.100:8888/user/user2?page=1
    

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

    • page_size_query_param = 'page_size' 前端发送的每页数目关键字名,默认为None
    • max_page_size = 4 前端最多能设置的每页数量
    • page_size = 2 每页数目
    • page_query_param = 'page' 前端发送的页数关键字名,默认为"page"
    1.2 可在setting配置全局分页器
    • INSTALLED_APPS = [
          'rest_framework', #需要注册应用
      ]
      
    • REST_FRAMEWORK = {
           # 分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页
          'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
          # 每页返回数量
          'PAGE_SIZE': 10,  # 默认 None
      }
      
    1.3 views.py
    from rest_framework.viewsets import ModelViewSet
    from rest_framework.pagination import PageNumberPagination	#导包 
    
    #自定义分页类
    class PageNumberPagination2(PageNumberPagination):
        page_size_query_param = 'page_size'
        max_page_size = 4
        page_size = 2
        page_query_param = 'page'
    
    '''
    手写分页
           def get(self, request):
                # 手写页面器
                num = request.GET.get('num', 1)
                num = int(num)
    
                queryset = Goods.objects.all()
                paginator = Paginator(queryset, 1)
    
                onepage = paginator.get_page(num)
    
                resp = {}
                resp['data'] = GoodsSer(onepage, many=True).data
                resp['next_page'] = num + 1
                resp['prev_page'] = num - 1
                resp['page_range'] = [i for i in paginator.page_range]
                return Response(resp)
    '''
    
    class UserModelViewSet(ModelViewSet):
        #设置查询集
        queryset = User.objects.all()
    	#设置序列化器类
        serializer_class = UserSerializers
    	#设置分页器
        pagination_class = PageNumberPagination2 	#使用自定义分页器
    	#pagination_class = PageNumberPagination		 #使用全局分页器
         
    #http://192.168.56.100:8888/user/user2?page=2
    
    1.4 使用postman测试

    2.排序

    • 对于列表数据 rest framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照字段进行排序。
    2.1 在setting.py中配置全局排序
    • INSTALLED_APPS = [
          'rest_framework', #需要注册应用
      ]
      
    • REST_FRAMEWORK = {
           #过滤排序(全局):Filtering 过滤排序
          'SEARCH_PARAM': 'search',
          'ORDERING_PARAM': 'ordering',
          'NUM_PROXIES': None,
      }
      
    2.2 使用方法:

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

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

    示例:

    views.py

    from rest_framework.viewsets import ModelViewSet
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import OrderingFilter
    
    class UserModelViewSet(ModelViewSet):
        # queryset = User.objects.all().order_by('id')
        queryset = User.objects.all()
        serializer_class = UserSerializers
        pagination_class = PageNumberPagination
    
        filter_backends = [OrderingFilter,]
        
        # 排序
        ordering_fields = ('id', 'age', 'class_room') #需要排序的字段
    
    #http://192.168.56.100:8888/user/user2?ordering=-age 使用age字段从大到小排序
    #http://192.168.56.100:8888/user/user2?ordering=age  使用age字段从小到大排序
    
    2.3 使用postman测试

    3.过滤

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

    pip install django_filters
    
    3.1 在setting.py中配置
    • INSTALLED_APPS = [
          'django_filters',
          'rest_framework',
      ]
      
    • REST_FRAMEWORK = {
           # 过滤器后端
          'DEFAULT_FILTER_BACKENDS': [
              'django_filters.rest_framework.DjangoFilterBackend',
              # 'django_filters.rest_framework.backends.DjangoFilterBackend', 包路径有变化
          ],
      }
      
    3.2 views.py
    from rest_framework.viewsets import ModelViewSet
    from django_filters.rest_framework import DjangoFilterBackend
    
    
    class UserModelViewSet(ModelViewSet):
        # queryset = User.objects.all().order_by('id')
        queryset = User.objects.all()
        serializer_class = UserSerializers
        pagination_class = PageNumberPagination
    
        # 过滤
        filter_backends = [OrderingFilter, DjangoFilterBackend]
        filter_fields = ('name', 'age')	#参加过滤的字段
    
    #http://192.168.56.100:8888/user/user2?name=马六
    
    3.3 使用postman测试

    4.限流 Throttling

    可以对接口访问的频次进行限制,以减轻对服务器的压力

    4.1 在setting.py中配置
    • INSTALLED_APPS = [
          'rest_framework',
      ]
      
    • REST_FRAMEWORK = {
               # 3.限流(防爬虫)
          'DEFAULT_THROTTLE_CLASSES': [
              'rest_framework.throttling.AnonRateThrottle',
              'rest_framework.throttling.UserRateThrottle',
          ],
          # 3.1限流策略
          'DEFAULT_THROTTLE_RATES': {
              'user': '1/hour',  # 认证用户每小时100次
              'anon': '3/day',  # 未认证用户每天能访问3次
          },
          'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
          'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
          'DEFAULT_VERSIONING_CLASS': None,
      }
      

    DEFAULT_THROTTLE_RATES 可以使用 second,minute,hour或day来指明周期。

    4.2 views.py
    from rest_framework.throttling import AnonRateThrottle,UserRateThrottle
    from rest_framework.viewsets import ModelViewSet
    
    class UserModelViewSet(ModelViewSet):
        # queryset = User.objects.all().order_by('id')
        queryset = User.objects.all()
        serializer_class = UserSerializers
        
        #限流自定义限流类
        throttle_classes = [AnonRateThrottle]
         
        #超出限定的次数会报错
    	# "detail": "Request was throttled. Expected available in 86398 seconds."
    	
        
    
    4.3 使用postman测试

    5. 序列化

    详情看我之前的博客:https://www.cnblogs.com/tjw-bk/p/13805532.html

    6.认证

    认证即需要知道是谁在访问服务器,需要有一个合法身份。认证的方式可以有很多种,例如session+cookie、token等,这里以token为例。如果请求中没有token,我们认为这是未登录状态,有些接口要求必须登录才能访问,如果未登录,我们可以一些处理(比如重定向登录页、返回错误信息等)

    • 局部认证:

    url.py

    from django.conf.urls import url, include
    from DemoApp.views import TestView
      
    urlpatterns = [
        url(r'^test/', TestView.as_view()),
    ]
    

    功能代码:utils/auth.py

    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed,ValidationError
    from DemoApp.models import User
    
    class MyAuth(BaseAuthentication):
        def authenticate(self, request):
            "认证逻辑"
            # 做认证,判断是否登陆。首先拿到token,在数据库里去判断
            token = request.query_params.get("token","")
            if not token:
                raise AuthenticationFailed("没有token")
            try:
                user = User.objects.filter(token=token).first()
                if not user:
                    pass
                    raise AuthenticationFailed("无效的token")
            except Exception as e:
                msg = "无效的token" if hasattr(e, "messages") else "非法的token"
                raise AuthenticationFailed(msg)
    
            return (user, token) # 返回值是一个元素,分别对应视图中request的user,auth
    

    views.py

    class TestView(APIView):
        authentication_classes = [MyAuth, ]  # 局部认证
    
        def get(self, request, *args, **kwargs):
            "通过认证后进入views类进行业务处理"
            print(request.user)
            print(request.auth)
            pass
    

    在上述代码中,实现了TestView视图类的认证功能。如果认证成功,向视图类中的request对象中返回requset.user和request.auth;如果认证失败,触发异常,不会进入视图处理,直接返回前端认证失败的结果。在实际的业务中这样并不合适,我们可以将其替代成重定向操作。

    • 全局认证
    • 将视图类中的authentication_classes属性删除
    • settings.py配置文件中 RESTFRAMEWORK 添加配置
    6.1 在setting.py中配置
    • INSTALLED_APPS = [
          'rest_framework',
      ]
      
    • REST_FRAMEWORK = {
           # 1.认证器(全局)
          'DEFAULT_AUTHENTICATION_CLASSES': [
              'rest_framework_jwt.authentication.JSONWebTokenAuthentication',  # 在DRF中配置JWT认证
              'rest_framework.authentication.SessionAuthentication',  # 使用session时的认证器
              'rest_framework.authentication.BasicAuthentication'  # 提交表单时的认证器
          ],
      }
      

    如果在全局认证下,有些接口不想加上认证,可以在这个类的属性 authentication_classes = [ ] 即可。

    除了上述自己实现的认证类,REST Framework为我们了四种认证类:(直接在视图类中使用即可)

    from rest_framework.authentication import BaseAuthentication,SessionAuthentication  ......
    1.BasicAuthentication       基于用户名密码
    2.SessionAuthentication     基于session
    3.TokenAuthentication       基于token,与示例中类似
    4.RemoteUserAuthentication  
    
    6.2 views.py
    from rest_framework.authentication import BasicAuthentication, SessionAuthentication
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    
    class CourseViewSet(viewsets.ModelViewSet):
        # 1.认证:自定义认证类,自定义会覆盖全局配置
        authentication_classes = (BasicAuthentication, SessionAuthentication, JSONWebTokenAuthentication)
         
    

    7.权限

    根据不同权限用户对于api的访问频次,其他限制等等

    7.1 在setting.py中配置
    • INSTALLED_APPS = [
          'rest_framework',
      ]
      
    • REST_FRAMEWORK = {
          # 2.权限配置(全局): 顺序靠上的严格
          'DEFAULT_PERMISSION_CLASSES': [
              # 'rest_framework.permissions.IsAdminUser',  # 管理员可以访问
              'rest_framework.permissions.IsAuthenticated',  # 认证用户可以访问
              # 'rest_framework.permissions.IsAuthenticatedOrReadOnly',  # 认证用户可以访问, 否则只能读取
              'rest_framework.permissions.AllowAny',  # 所有用户都可以访问
          ],
      }
      
    7.2 views.py
    from rest_framework.permissions import AllowAny, IsAuthenticated
    
    class CourseTagViewSet(viewsets.ModelViewSet):
        queryset = CourseTag.objects.all()
        serializer_class = CourseTagSer
    
        # 2.权限:自定义权限类
        # permission_classes = (AllowAny,)
        permission_classes = (IsAuthenticated,)
        
    
    7.3 使用postman测试

    8.版本

    参考博客:https://openapi.alipay.com/gateway.do?
    https://www.jb51.net/article/166249.htm

    从小白到大神的蜕变~~
  • 相关阅读:
    SecureRandom
    《Head First 设计模式》[02] 观察者模式
    《MySQL必知必会》[07] 管理事务处理
    《MySQL必知必会》[06] 触发器
    《MySQL必知必会》[05] 存储过程和游标
    Centos7安装Nginx
    IDEA配置Tomcat
    Java小功能大杂烩
    Java处理中文乱码问题
    Java邮件发送
  • 原文地址:https://www.cnblogs.com/tjw-bk/p/13952297.html
Copyright © 2011-2022 走看看