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
来源:https://www.cnblogs.com/zhaohuhu/p/9134386.html
