• REST framework框架的基本组件


    restful规范

    1.根据method不同,进行不同操作
    2.面向资源编程
    3.体现版本
    4.体现是API
    5.最好用https
    6.响应式设置状态码
    7.条件 ?id=1
    8.返回值
    9.返回错误信息
    10.Hypermedia API

    REST framework框架

    1.路由
    2.视图
    3.权限
    4.认证
    5.访问频率限制
    6.序列化
    7.分页
    8.解析器
    9.渲染器
    10.版本

    我对 django rest framework框架的认识!

    - 路由,

    - 可以通过as_view传参数,根据请求方式不同执行相应的方法
    - 可以在url中设置一个结尾,类似于: .json

    - 视图,

    - 帮助开发者提供了一些类,并在类中提供了多个方法以供我们使用。

    - 版本,

    - 在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不同做不同处理

    - 认证,

    - 写一个类并注册到认证类,在类的的authticate方法中编写认证逻辑。
    - 认证成功(user,auth)
    - raise AuthticateFaild(....)
    - None

    - 权限

    - 写一个类并注册到权限类,在类的的has_permission方法中编写认证逻辑。
    - True
    - False

    - 频率限制

    - 写一个类并注册到频率类,在类的的 allow_request/wait 方法中编写认证逻辑。

    allow_request
    - True
    - False 如果返回False,那么就要执行wait

    - 解析器,

    - 根据ContentType请求头,选择不同解析器对 请求体中的数据进行解析。

    POST /index/ http1.1. host:11.11.11.11 Content-Type:url-formendo.... user=alex&age=123
    POST /index/ http1.1. host:11.11.11.11 Content-Type:application/json {....}

    - 分页

    - 对从数据库中获取到的数据进行分页处理: SQL -> limit offset
    - 根据页码:http://www.luffycity.com/api/v1/student/?page=1&size=10
    - 根据索引:http://www.luffycity.com/api/v1/student/?offset=60&limit=10
    - 根据加密:http://www.luffycity.com/api/v1/student/?page=erd8

    页码越大速度越慢,为什么以及如何解决?
    原因:页码越大向后需要扫描的行数越多,因为每次都是从0开始扫描。
    解决:
    - 限制显示的页数
    - 记录当前页数据ID最大值和最小值,再次分页时,根据ID现行筛选,然后再分页。

    - 序列化

    - 对queryset序列化以及对请求数据格式校验。

    - 渲染器

    - 根据URL中传入的后缀,决定在数据如何渲染到到页面上。

    视图三部曲

    使用混合(mixins)

     1 from rest_framework.views import APIView
     2 from rest_framework.response import Response
     3 from .models import *
     4 from django.shortcuts import HttpResponse
     5 from django.core import serializers
     6 
     7 
     8 from rest_framework import serializers
     9 
    10 
    11 class BookSerializers(serializers.ModelSerializer):
    12       class Meta:
    13           model=Book
    14           fields="__all__"
    15           #depth=1
    16 
    17 
    18 class PublshSerializers(serializers.ModelSerializer):
    19 
    20       class Meta:
    21           model=Publish
    22           fields="__all__"
    23           depth=1
    24 
    25 
    26 class BookViewSet(APIView):
    27 
    28     def get(self,request,*args,**kwargs):
    29         book_list=Book.objects.all()
    30         bs=BookSerializers(book_list,many=True,context={'request': request})
    31         return Response(bs.data)
    32 
    33 
    34     def post(self,request,*args,**kwargs):
    35         print(request.data)
    36         bs=BookSerializers(data=request.data,many=False)
    37         if bs.is_valid():
    38             print(bs.validated_data)
    39             bs.save()
    40             return Response(bs.data)
    41         else:
    42             return HttpResponse(bs.errors)
    43 
    44 
    45 class BookDetailViewSet(APIView):
    46 
    47     def get(self,request,pk):
    48         book_obj=Book.objects.filter(pk=pk).first()
    49         bs=BookSerializers(book_obj,context={'request': request})
    50         return Response(bs.data)
    51 
    52     def put(self,request,pk):
    53         book_obj=Book.objects.filter(pk=pk).first()
    54         bs=BookSerializers(book_obj,data=request.data,context={'request': request})
    55         if bs.is_valid():
    56             bs.save()
    57             return Response(bs.data)
    58         else:
    59             return HttpResponse(bs.errors)
    60 
    61 
    62 class PublishViewSet(APIView):
    63 
    64     def get(self,request,*args,**kwargs):
    65         publish_list=Publish.objects.all()
    66         bs=PublshSerializers(publish_list,many=True,context={'request': request})
    67         return Response(bs.data)
    68 
    69 
    70     def post(self,request,*args,**kwargs):
    71 
    72         bs=PublshSerializers(data=request.data,many=False)
    73         if bs.is_valid():
    74             # print(bs.validated_data)
    75             bs.save()
    76             return Response(bs.data)
    77         else:
    78             return HttpResponse(bs.errors)
    79 
    80 
    81 class PublishDetailViewSet(APIView):
    82 
    83     def get(self,request,pk):
    84 
    85         publish_obj=Publish.objects.filter(pk=pk).first()
    86         bs=PublshSerializers(publish_obj,context={'request': request})
    87         return Response(bs.data)
    88 
    89     def put(self,request,pk):
    90         publish_obj=Publish.objects.filter(pk=pk).first()
    91         bs=PublshSerializers(publish_obj,data=request.data,context={'request': request})
    92         if bs.is_valid():
    93             bs.save()
    94             return Response(bs.data)
    95         else:
    96             return HttpResponse(bs.errors)
    使用混合mixins

    mixin类编写视图

     1 from rest_framework import mixins
     2 from rest_framework import generics
     3 
     4 class BookViewSet(mixins.ListModelMixin,
     5                   mixins.CreateModelMixin,
     6                   generics.GenericAPIView):
     7 
     8     queryset = Book.objects.all()
     9     serializer_class = BookSerializers
    10 
    11     def get(self, request, *args, **kwargs):
    12         return self.list(request, *args, **kwargs)
    13 
    14     def post(self, request, *args, **kwargs):
    15         return self.create(request, *args, **kwargs)
    16 
    17 
    18 
    19 class BookDetailViewSet(mixins.RetrieveModelMixin,
    20                     mixins.UpdateModelMixin,
    21                     mixins.DestroyModelMixin,
    22                     generics.GenericAPIView):
    23     queryset = Book.objects.all()
    24     serializer_class = BookSerializers
    25 
    26     def get(self, request, *args, **kwargs):
    27         return self.retrieve(request, *args, **kwargs)
    28 
    29     def put(self, request, *args, **kwargs):
    30         return self.update(request, *args, **kwargs)
    31 
    32     def delete(self, request, *args, **kwargs):
    33         return self.destroy(request, *args, **kwargs)
    使用mixin

    使用通用的基于类的视图

    通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

     1 from rest_framework import mixins
     2 from rest_framework import generics
     3 
     4 class BookViewSet(generics.ListCreateAPIView):
     5 
     6     queryset = Book.objects.all()
     7     serializer_class = BookSerializers
     8 
     9 class BookDetailViewSet(generics.RetrieveUpdateDestroyAPIView):
    10     queryset = Book.objects.all()
    11     serializer_class = BookSerializers
    12 
    13 class PublishViewSet(generics.ListCreateAPIView):
    14 
    15     queryset = Publish.objects.all()
    16     serializer_class = PublshSerializers
    17 
    18 class PublishDetailViewSet(generics.RetrieveUpdateDestroyAPIView):
    19     queryset = Publish.objects.all()
    20     serializer_class = PublshSerializers
    使用通用类

    使用viewsets.ModelViewSet

    urls.py:

    1 url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
    2     url(r'^books/(?P<pk>d+)$', views.BookViewSet.as_view({
    3                 'get': 'retrieve',
    4                 'put': 'update',
    5                 'patch': 'partial_update',
    6                 'delete': 'destroy'
    7             }),name="book_detail"),
    urls

    views.py:

    1 class BookViewSet(viewsets.ModelViewSet):
    2     queryset = Book.objects.all()
    3     serializer_class = BookSerializers
    views

    认证与权限组件

    认证组件

    局部视图认证

    在app01.service.auth.py:

    通过用户的token值做认证

    1 class Authentication(BaseAuthentication):
    2 
    3     def authenticate(self,request):
    4         token=request._request.GET.get("token")
    5         token_obj=UserToken.objects.filter(token=token).first()
    6         if not token_obj:
    7             raise exceptions.AuthenticationFailed("验证失败!")
    8         return (token_obj.user,token_obj)
    View Code

    在views.py:

     1 def get_random_str(user):
     2     import hashlib,time
     3     ctime=str(time.time())
     4 
     5     md5=hashlib.md5(bytes(user,encoding="utf8"))
     6     md5.update(bytes(ctime,encoding="utf8"))
     7 
     8     return md5.hexdigest()
     9 
    10 
    11 from app01.service.auth import *
    12 
    13 from django.http import JsonResponse
    14 class LoginViewSet(APIView):
    15     authentication_classes = [Authentication,]
    16     def post(self,request,*args,**kwargs):
    17         res={"code":1000,"msg":None}
    18         try:
    19             user=request._request.POST.get("user")
    20             pwd=request._request.POST.get("pwd")
    21             user_obj=UserInfo.objects.filter(user=user,pwd=pwd).first()
    22             print(user,pwd,user_obj)
    23             if not user_obj:
    24                 res["code"]=1001
    25                 res["msg"]="用户名或者密码错误"
    26             else:
    27                 token=get_random_str(user)
    28                 UserToken.objects.update_or_create(user=user_obj,defaults={"token":token})
    29                 res["token"]=token
    30 
    31         except Exception as e:
    32             res["code"]=1002
    33             res["msg"]=e
    34 
    35         return JsonResponse(res,json_dumps_params={"ensure_ascii":False})
    views

    全局视图认证组件

    settings.py配置如下:

    1 REST_FRAMEWORK={
    2     "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
    3 }
    settings

    权限组件

    局部视图权限

    在app01.service.permissions.py中:

    1 from rest_framework.permissions import BasePermission
    2 class SVIPPermission(BasePermission):
    3     message="SVIP才能访问!"
    4     def has_permission(self, request, view):
    5         if request.user.user_type==3:
    6             return True
    7         return False
    View Code

    在views.py:

    1 from app01.service.permissions import *
    2 
    3 class BookViewSet(generics.ListCreateAPIView):
    4     permission_classes = [SVIPPermission,]
    5     queryset = Book.objects.all()
    6     serializer_class = BookSerializers
    views

    全局视图权限

    settings.py配置如下:

    1 REST_FRAMEWORK={
    2     "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    3     "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
    4 }
    settings

     

    throttle(访问频率)组件

    局部视图throttle

    在app01.service.throttles.py中:

     1 from rest_framework.throttling import BaseThrottle
     2 
     3 VISIT_RECORD={}
     4 class VisitThrottle(BaseThrottle):
     5 
     6     def __init__(self):
     7         self.history=None
     8 
     9     def allow_request(self,request,view):
    10         remote_addr = request.META.get('REMOTE_ADDR')
    11         print(remote_addr)
    12         import time
    13         ctime=time.time()
    14 
    15         if remote_addr not in VISIT_RECORD:
    16             VISIT_RECORD[remote_addr]=[ctime,]
    17             return True
    18 
    19         history=VISIT_RECORD.get(remote_addr)
    20         self.history=history
    21 
    22         while history and history[-1]<ctime-60:
    23             history.pop()
    24 
    25         if len(history)<3:
    26             history.insert(0,ctime)
    27             return True
    28         else:
    29             return False
    30 
    31     def wait(self):
    32         import time
    33         ctime=time.time()
    34         return 60-(ctime-self.history[-1])
    throttles

    在views.py中:

    1 from app01.service.throttles import *
    2 
    3 class BookViewSet(generics.ListCreateAPIView):
    4     throttle_classes = [VisitThrottle,]
    5     queryset = Book.objects.all()
    6     serializer_class = BookSerializers
    views

    全局视图throttle

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
    }

    内置throttle类

    在app01.service.throttles.py修改为:

    1 class VisitThrottle(SimpleRateThrottle):
    2 
    3     scope="visit_rate"
    4     def get_cache_key(self, request, view):
    5 
    6         return self.get_ident(request)
    throttles

    settings.py设置:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
        "DEFAULT_THROTTLE_RATES":{
            "visit_rate":"5/m",
        }
    }

    解析器

    request类

    django的request类和rest-framework的request类的源码解析

    局部视图

    from rest_framework.parsers import JSONParser,FormParser
    class PublishViewSet(generics.ListCreateAPIView):
        parser_classes = [FormParser,JSONParser]
        queryset = Publish.objects.all()
        serializer_class = PublshSerializers
        def post(self, request, *args, **kwargs):
            print("request.data",request.data)
            return self.create(request, *args, **kwargs)

    全局视图

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
        "DEFAULT_THROTTLE_RATES":{
            "visit_rate":"5/m",
        },
        "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
    }

    序列化

    ser = ServerSerializer(instance=queryset, many=True)
    #instance接受queryset对象或者单个model对象,当有多条数据时候,使用many=True,单个对象many=False

    看序列化代码

    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    from app01 import models
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    
    class BookSerializers(serializers.Serializer):
        #我们先序列化写两个字段的数据,别忘了这里面的字段和model表中的字段变量名要一样
        title = serializers.CharField(max_length=32)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
    
        #一对多的处理
        # publish = serializers.CharField(max_length=32)  #返回对象
        publish_email = serializers.CharField(max_length=32, source='publish.email')  # source指定返回的多对一的那个publish对象的email数据,并且我们现在找到书籍的email,所以前面的字段名称就可以不和你的publish对应好了,随便取名字
        publish_name = serializers.CharField(max_length=32, source='publish.name')  # source指定返回的多对一的那个publish对象的其他字段数据,可以接着写字段,也就是说关联的所有的字段的数据都可以写在这里进行序列化
    
        #对多对的处理
        # authors = serializers.CharField(max_length=32) #bookobj.authors拿到的类似于一个models.Authors.object,打印的时候这是个None
        # authors = serializers.CharField(max_length=32,source="authors.all") #这样写返回的是queryset类型的数据,这样给前端肯定是不行的,所以按照下面的方法写
        authors = serializers.SerializerMethodField() #序列化方法字段,专门给多对多字段用的,然后下面定义一个方法,方法名称写法是这样的get_字段名,名字必须是这样
        def get_authors(self,obj): #参数写一个obj,这个obj是一个一个的书籍对象,然后我们通过书籍对象来返回对应的数据
            # author_list_values = obj.authors.all().values() #返回这样类型的数据也行,那么具体你要返回什么结构的数据,需要和前端人员沟通清楚,然后这里对数据进行加工
            #假如加工成的数据是这种类型的[ {},{} ],就可以按照下面的逻辑来写,我简单写的,肯定有更好的逻辑来加工这些数据
            author_list_values = []
            author_dict = {}
            author_list = obj.authors.all()
            for i in author_list:
                author_dict['name'] = i.name
                author_list_values.append(author_dict)
            return author_list_values
    
    
    class BookView(APIView):
        def get(self,request):
            book_obj_list = models.Book.objects.all()
            s_books = BookSerializers(book_obj_list,many=True)
            return Response(s_books.data)
    
        def post(self,request):
            pass
    

    serializer在内部就做了这点事儿,伪代码昂

    创建一个序列化类

    简单使用

    开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。

    models部分:

     1 from django.db import models
     2 
     3 # Create your models here.
     4 
     5 
     6 class Book(models.Model):
     7     title=models.CharField(max_length=32)
     8     price=models.IntegerField()
     9     pub_date=models.DateField()
    10     publish=models.ForeignKey("Publish")
    11     authors=models.ManyToManyField("Author")
    12     def __str__(self):
    13         return self.title
    14 
    15 class Publish(models.Model):
    16     name=models.CharField(max_length=32)
    17     email=models.EmailField()
    18     def __str__(self):
    19         return self.name
    20 
    21 class Author(models.Model):
    22     name=models.CharField(max_length=32)
    23     age=models.IntegerField()
    24     def __str__(self):
    25         return self.name
    models 

    views部分:

     1 from rest_framework.views import APIView
     2 from rest_framework.response import Response
     3 from .models import *
     4 from django.shortcuts import HttpResponse
     5 from django.core import serializers
     6 
     7 
     8 from rest_framework import serializers
     9 
    10 class BookSerializers(serializers.Serializer):
    11     title=serializers.CharField(max_length=32)
    12     price=serializers.IntegerField()
    13     pub_date=serializers.DateField()
    14     publish=serializers.CharField(source="publish.name")
    15     #authors=serializers.CharField(source="authors.all")
    16     authors=serializers.SerializerMethodField()
    17     def get_authors(self,obj):
    18         temp=[]
    19         for author in obj.authors.all():
    20             temp.append(author.name)
    21         return temp
    22 
    23 
    24 class BookViewSet(APIView):
    25 
    26     def get(self,request,*args,**kwargs):
    27         book_list=Book.objects.all()
    28         # 序列化方式1:
    29         # from django.forms.models import model_to_dict
    30         # import json
    31         # data=[]
    32         # for obj in book_list:
    33         #     data.append(model_to_dict(obj))
    34         # print(data)
    35         # return HttpResponse("ok")
    36 
    37         # 序列化方式2:
    38         # data=serializers.serialize("json",book_list)
    39         # return HttpResponse(data)
    40 
    41         # 序列化方式3:
    42         bs=BookSerializers(book_list,many=True)
    43         return Response(bs.data)
    views

    ModelSerializer

    class BookSerializers(serializers.ModelSerializer):
          class Meta:
              model=Book
              fields="__all__"
              depth=1

    提交post请求

      def post(self,request,*args,**kwargs):
           
            bs=BookSerializers(data=request.data,many=False)
            if bs.is_valid():
                # print(bs.validated_data)
                bs.save()
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)

    重写save中的create方法

    class BookSerializers(serializers.ModelSerializer):
    
          class Meta:
              model=Book
              fields="__all__"
              # exclude = ['authors',]
              # depth=1
    
          def create(self, validated_data):
            
              authors = validated_data.pop('authors')
              obj = Book.objects.create(**validated_data)
              obj.authors.add(*authors)
              return obj

    单条数据的get和put请求

    class BookDetailViewSet(APIView):
    
        def get(self,request,pk):
            book_obj=Book.objects.filter(pk=pk).first()
            bs=BookSerializers(book_obj)
            return Response(bs.data)
    
        def put(self,request,pk):
            book_obj=Book.objects.filter(pk=pk).first()
            bs=BookSerializers(book_obj,data=request.data)
            if bs.is_valid():
                bs.save()
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)

    超链接API:Hyperlinked

    class BookSerializers(serializers.ModelSerializer):
          publish= serializers.HyperlinkedIdentityField(
                         view_name='publish_detail',
                         lookup_field="publish_id",
                         lookup_url_kwarg="pk")
          class Meta:
              model=Book
              fields="__all__"
              #depth=1
    

    urls部分:

    urlpatterns = [
        url(r'^books/$', views.BookViewSet.as_view(),name="book_list"),
        url(r'^books/(?P<pk>d+)$', views.BookDetailViewSet.as_view(),name="book_detail"),
        url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),
        url(r'^publishers/(?P<pk>d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"),
    ]

    分页

    简单分页

     1 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
     2 
     3 class PNPagination(PageNumberPagination):
     4         page_size = 1
     5         page_query_param = 'page'
     6         page_size_query_param = "size"
     7         max_page_size = 5
     8 
     9 class BookViewSet(viewsets.ModelViewSet):
    10 
    11     queryset = Book.objects.all()
    12     serializer_class = BookSerializers
    13     def list(self,request,*args,**kwargs):
    14 
    15         book_list=Book.objects.all()
    16         pp=LimitOffsetPagination()
    17         pager_books=pp.paginate_queryset(queryset=book_list,request=request,view=self)
    18         print(pager_books)
    19         bs=BookSerializers(pager_books,many=True)
    20 
    21         #return Response(bs.data)
    22         return pp.get_paginated_response(bs.data)
    views

    偏移分页

    from rest_framework.pagination import LimitOffsetPagination
  • 相关阅读:
    setUP和tearDown,setUpClass和tearDownClass
    执行代码提示:Ran 0 tests in 0.000s
    Python自动化测试执行用例
    Python+webdriver自动化脚本的封装调用
    SQL之INDEX
    SQL之WHERE,GROUP,HAVING,ORDER BY
    SQL之LIMIT
    python基础之字符编码、文件处理
    python基础之列表、元组、字典、布尔值、集合
    python基础之if条件判断、while循环及数据类型
  • 原文地址:https://www.cnblogs.com/zhaohuhu/p/9134386.html
Copyright © 2020-2023  润新知