rest_framework
rest_framework 是基于restful 规范 开发的,帮助我们能快速开发符合restful规范的数据接口的一个app,记得在setting.py 的INSTALLED_APPS中进行app注册哦,
序列化
一、基础序列化
方式一:利用json模块下的dump,进行序列化
方式二:利用form组件下的model_to_dict方法将model对象转成字典,加入list序列化
方式三:利用Django原生的serializer进行序列化
1 # # 序列化 2 # class Book(APIView): 3 # def get(self,request): 4 # books = models.Book.objects.all() 5 # # # 方式一 6 # # # list(books) 7 # # # return HttpResponse(json.dumps(books)) 8 # # # 方式二 9 # # # from django.forms.models import model_to_dict 10 # # # tem =[] 11 # # # for obj in books: 12 # # # print(model_to_dict(obj)) 13 # # # return HttpResponse(json.dumps(tem)) 14 # # # 方式三 15 # # # from django.core import serializers 16 # # # data = serializers.serialize('json',books) 17 # # # return HttpResponse(data)
二、rest_framework 序列化
rest_framework 提供的序列化方法的使用方法和form组件十分类似,在学习的时候可以类比的进行学习。
序列化用到的相关类的继承关系及作用:
rest_framework 提供的序列化方法都在rest_framework.serializers类下;
1、serializers的使用:先创建一个继承serializers.Serializer序列化类用于对数据的序列化
1 from rest_framework import serializers 2 from api import models 3 4 class BookSerializers(serializers.Serializer): 5 nid = serializers.IntegerField() 6 name = serializers.CharField() 7 price = serializers.FloatField() 8 publisher = serializers.CharField(source="publisher.name") 9 #author = serializers.CharField(source="author.all") 10 11 author = serializers.SerializerMethodField() # 多对多取决于get_XXX()返回值 12 13 def get_author(self, obj): 14 temp = [] 15 for obj in obj.author.all(): 16 temp.append(obj.name) 17 return temp 18 19 20 ''' 21 序列化 BookSerializers(serializer.Serializer)的过程: 22 temp= [] 23 for obj in books: 24 temp.append( 25 'nid':obj.nid 26 'price':obj.price 27 'name':obj.name 28 'publisher':str(obj.publisher) #obj.publisher.name 29 'authors':get_authors(obj) 30 ) 31 '''
1 class Book(APIView): 2 def get(self,request): 3 books = models.Book.objects.all() 4 bs = serializers.BookSerializers(books,many=True) 5 return Response(bs.data)
2、ModelSerializers的使用:
1 class BookModelSerializer(serializers.ModelSerializer): 2 class Meta: 3 model = models.Book 4 fields = "__all__" # 默认全部序列化,但是想按照自己的来可以覆盖 5 #还有好像是 fields =("想要序列化的字段","...") 6 7 publisher = serializers.CharField(source="publisher.pk") 8 author = serializers.SerializerMethodField() # 多对多取决于get_XXX()返回值 9 def get_author(self, obj): 10 temp = [] 11 for obj in obj.author.all(): 12 temp.append(obj.nid) 13 return temp 14 15 #def create(self, validated_data): 16 # print(validated_data) 17 #按自己意愿覆盖时原来的create方法可能不支持需要重写
1 class BookViewSet(APIView): 2 def get(self, request, *args, **kwargs): 3 book_list = models.Book.objects.all() 4 # bs = serializers.BookSerializers(book_list, many=True) 5 bs = serializers.BookModelSerializers(book_list, many=True, context={'request': request}) 6 return Response(bs.data) 7 8 def post(self, request, *args, **kwargs): 9 # bs = serializers.BookSerializers(data=request.data, many=False) 10 bs = serializers.BookModelSerializers(data=request.data, many=False) 11 if bs.is_valid(): 12 print('123465', bs.validated_data) 13 # bs.save() 14 return Response(bs.data) 15 else: 16 return Response(bs.errors)
3、HyperlinkedIdentityField 超链接序列化:
1 class BookModelSerializers(serializers.ModelSerializer): 2 class Meta: 3 model = models.Book 4 fields = "__all__" 5 depth = 0 6 7 publisher = serializers.HyperlinkedIdentityField( 8 view_name="api:publisher_detail",#命名空间下的路由反向解析 9 lookup_field="publisher_id",#需要反序列化的ID,放进URL分组里,组成完整URL 10 lookup_url_kwarg="pk" #URL里面的分组 11 )
4、generics.ListCreateAPIView对请求方法进行封装,使代码变得更加简单简洁
1 from rest_framework import generics 2 from api import serializers 3 from api import models 4 5 class BookViewSet(generics.ListCreateAPIView):#类里已经封装好了请求方法对应要执行的函数 6 queryset = models.Book.objects.all() 7 serializer_class = serializers.BookModelSerializers
5、viewsets类下的ModelViewSet进一步对路由封装
1 from rest_framework.viewsets import ModelViewSet 2 from rest_framework.response import Response 3 from api import serializers,models 4 from rest_framework import serializers 5 6 class BookViewSet(ModelViewSet): 7 queryset = models.Book.objects.all() 8 serializer_class = serializers.BookModelSerializers
1 urlpatterns = [ 2 # re_path(r'^home/$',views.Home.as_view()), 3 re_path(r'books/$', views.BookViewSet.as_view({"get":"list"})), 4 re_path(r'books/(?P<pk>\d+)$', views.BookViewSet.as_view({"get":"retrieve"}), name="book_detail"), 5 6 # re_path(r'books/$', views.BookViewSet.as_view()), 7 # re_path(r'books/(?P<pk>\d+)$', views.BookDtailViewSet.as_view(), name="book_detail"), 8 re_path(r'publisher/$', views.PublisherViewSet.as_view()), 9 re_path(r'publisher/(?P<pk>\d+)$', views.PublisherDtailViewSet.as_view(), name="publisher_detail"), 10 ]
认证组件
rest_framework认证组件的初始化在APIView类下的dispatch()里
使用方法:
1 #认证类 2 class AuthToken(): 3 def authenticate(self,request): 4 nid = request.GET.get("nid") 5 name = request._request.GET.get("name",None) 6 print(name) 7 user = models.Author.objects.filter(name=name).first() 8 print(user) 9 if user: 10 return user.nid, user.name 11 else: 12 raise AuthenticationFailed("认证失败 ") 13 def authenticate_header(self,request): 14 pass
1 class PublisherDtailViewSet(APIView): 2 authentication_classes = [serializers.AuthToken,]#局部设置 3 4 def get(self, request, pk): 5 print("dididi",request.user) 6 print("didid",request.auth) 7 publisher = models.Publisher.objects.filter(pk=pk) 8 bs = serializers.PublisherModelSerializers(publisher, many=True) 9 return Response(bs.data)
全局配置源码一解:
在视图类下寻找authentication_class = [“认证类1”,“认证类2”]认证类列表,如实没有设置,则最终会寻找到APIView 类下的authentication_class = api_settings.DEFAULT_AUTHENTICATION_CLASS 执行 ,进入api_settings发现是APISettings类的实例,传参default=DEFAULT,DEFAULT为rest_framework所有数据的迷人配置,进去执行APISettings类下 __init__()方法,完成__init__()方法后没有发现发现任何有关全局配置的信息,有点萌,但是仔细看发现 APISettings 类下的__getattr__()方法,类的实例方法调用该类没有的属性时会触发次方法,APISettings类下没有DEFAULT_AUTHENTICATION_CLASS 属性,所以在执行authentication_class = api_settings.DEFAULT_AUTHENTICATION_CLASS触发__getattr__(),__getattr__()先去setting.py 文件下寻找REST_FRAMEWORK字典,没有就是{},取出认证类的路径,进行解析,拿到认证类执行。如果想某得是图形忽略认证只需要在视图类下authentication_class = [] ,就会先会被截胡。
权限组件
rest_framework认证组件的初始化在APIView类下的dispatch()里
全局配置和认证类是一样的
使用方法:
1 # 权限组件用到的权限类 2 from rest_framework.exceptions import PermissionDenied 3 4 5 class SVIPermision(): 6 def has_permission(self,request,*args,**kwargs): 7 permision_tyle = models.Author.objects.filter(name = request.user).first().permision_tyle 8 if not permision_tyle: 9 raise PermissionDenied("你没有权限") 10 elif permision_tyle == 1: 11 raise PermissionDenied("你权限不够") 12 else: 13 return True
1 class PublisherDtailViewSet(APIView): 2 authentication_classes = [serializers.AuthToken,] 3 permission_classes = [serializers.SVIPermision,] 4 def get(self, request, pk): 5 print("dididi",request.user) 6 print("didid",request.auth) 7 publisher = models.Publisher.objects.filter(pk=pk) 8 bs = serializers.PublisherModelSerializers(publisher, many=True) 9 return Response(bs.data)
频率组件
思想:设置间隔时间能访问的次数,对于匿名用户,获取远程IP,作为本地key,为它创建一个列表key:[],先清理列表中大于间隔时间的元素,计算列表元素个数,小于能访问的次数就将本次访问时间加入列表,否则限制访问。
对于登录用户则用用户名作为key。强制匿名用户登录是防止恶意访问的一种有效手段,但不可能真正做到限制访问(多账户分段访问)
1 # 频率组件 2 import time 3 4 Frequent_user_record = {} 5 from rest_framework.exceptions import Throttled 6 7 8 class Throttles(): 9 def __init__(self): 10 self.interval = 1 * 5 # 间隔1分钟 11 self.num = 2 # 可以访问2次 12 self.history = None 13 self.now = 0 14 15 def allow_request(self, request, *args, **kwargs): 16 self.now = time.time() 17 remote_addr = request._request.META.get("REMOTE_ADDR") 18 remote_addr_obj = Frequent_user_record.get(remote_addr, None) 19 if not remote_addr_obj: 20 Frequent_user_record[remote_addr] = [time.time(), ] 21 return True 22 self.history = Frequent_user_record[remote_addr] 23 24 while self.history and time.time() - self.history[-1] > self.interval: 25 Frequent_user_record[remote_addr].pop() 26 27 if len(self.history) < self.num: 28 Frequent_user_record[remote_addr].insert(0, self.now) 29 return True 30 else: 31 return False 32 33 def wait(self): 34 return self.interval - (self.now - self.history[-1])
1 class PublisherDtailViewSet(APIView): 2 authentication_classes = [serializers.AuthToken,] 3 # permission_classes = [serializers.SVIPermision,] 4 throttle_classes = [serializers.Throttles,] 5 def get(self, request, pk): 6 # print("dididi",request.user) 7 # print("didid",request.auth) 8 publisher = models.Publisher.objects.filter(pk=pk) 9 bs = serializers.PublisherModelSerializers(publisher, many=True) 10 return Response(bs.data)