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.\r\nhost:11.11.11.11\r\nContent-Type:url-formendo.... \r\n\r\nuser=alex&age=123
		POST /index/ http1.1.\r\nhost:11.11.11.11\r\nContent-Type:application/json\r\n\r\n{....}
- 分页
	- 对从数据库中获取到的数据进行分页处理: 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)
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类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。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"),
views.py:
 
1 class BookViewSet(viewsets.ModelViewSet): 2 queryset = Book.objects.all() 3 serializer_class = BookSerializers
认证与权限组件
认证组件
局部视图认证
在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)
在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})
全局视图认证组件
settings.py配置如下:
 
1 REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",] 3 }
权限组件
局部视图权限
在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
在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
全局视图权限
settings.py配置如下:
 
1 REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], 3 "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",] 4 }
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])
在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
全局视图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)
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
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)
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)
偏移分页
from rest_framework.pagination import LimitOffsetPagination

 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号