Django之Rest_Framework http://www.cnblogs.com/wupeiqi/articles/7805382.html
1.认证功能
1.1 创建两张表
from django.db import models class UserInfo(models.Model): """ 用户表 """ user_type_id = ( (1,'普通用户'), (2,'VIP用户'), (3,'SVIP用户'), ) user_type = models.IntegerField(choices=user_type_id,max_length=32) username = models.CharField(verbose_name='用户名',max_length=32,unique=True) password = models.CharField(verbose_name='密码',max_length=64) class TokenInfo(models.Model): """ token表 """ user = models.OneToOneField(to='UserInfo') # 和用户表做一对一关联 token = models.CharField(verbose_name='Token',max_length=128)
1.2 编写用户登录认证,并保存token到数据库中
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import hashlib 2 import time 3 from django.shortcuts import render 4 from django.http import JsonResponse 5 from rest_framework.views import APIView 6 from api import models 7 8 def md5(user): 9 """ 10 通过MD5加密把时间戳变成token 11 :param user: 12 :return: 13 """ 14 ctime = str(time.time()) 15 md5_obj = hashlib.md5(bytes(user,encoding='utf-8')) 16 md5_obj.update(bytes(ctime,encoding='utf-8')) 17 return md5_obj.hexdigest() 18 19 class AuthView(APIView): 20 """ 21 API 22 """ 23 def post(self,request,*args,**kwargs): 24 """ 25 用户登录 26 :param request: 27 :param args: 28 :param kwargs: 29 :return: 30 """ 31 ret = {'code':1000,'msg':None} 32 try: 33 # 获取post提交过来的用户名和密码 34 user = request._request.POST.get('username') 35 pwd = request._request.POST.get('password') 36 37 # 从数据库中获取用户名密码的对象 38 user_obj = models.UserInfo.objects.filter(username=user,password=pwd).first() 39 40 # 判断用户名和密码 41 if not user_obj: 42 ret['code'] = 1001 43 ret['msg'] = '用户名密码错误' 44 45 # 为登录用户创建token 46 token = md5(user) 47 models.TokenInfo.objects.update_or_create(user=user_obj,defaults={'token':token}) 48 49 ret['token'] = token 50 except Exception as e: 51 ret['code'] = 1002 52 ret['msg'] = '认证失败' 53 54 return JsonResponse(ret)
1.3 完善登录认证功能
djangorestframework\api\utils\auth.py 下定义认证功能
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from api import models 2 from rest_framework import exceptions 3 from rest_framework.authentication import BaseAuthentication 4 class Authtication(BaseAuthentication): 5 """ 6 定义认证规则 7 """ 8 def authenticate(self, request): 9 token = request._request.GET.get('token') 10 token_obj = models.TokenInfo.objects.filter(token=token).first() 11 if not token: 12 raise exceptions.AuthenticationFailed('用户认证失败') 13 return (token_obj.user, token) 14 15 def authenticate_header(self,request): 16 pass
认证规则写完以后,添加url写其他功能
1.4 编写测试代码(模拟获取订单信息,按照restful规定写)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class OrderView(APIView): 2 """ 3 模拟订单的增删改查 4 """ 5 6 def get(self, request): 7 """ 8 get请求为查询订单 9 :param request: 10 :return: 11 """ 12 ret = {'code': 1000, 'msg': None, 'data': None} 13 try: 14 ret['data'] = ORDER_DICT 15 except Exception as e: 16 pass 17 return JsonResponse(ret)
1.5 设置全局认证方式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.Authtication'], # 用户认证 3 'UNAUTHENTICATED_USER':None, # 匿名用户 4 'UNAUTHENTICATED_TOKEN':None, # 匿名用户 5 }
1.6 url访问
127.0.0.1:8000/api/v1/auth/ # 发送post请求,生成当前用户的token 127.0.0.1:8000/api/v1/order/?token=bf7b137c8d33a9b90a2b64ee6fda0f49 #携带token发送get请求,先走认证功能,如果不携带token走到认证功能是则返回认证失败
2.权限
2.1 权限代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from rest_framework.permissions import BasePermission 2 3 class MainPermission(BasePermission): 4 """ 5 权限 6 """ 7 def has_permission(self, request, view): 8 9 # 用户user_type等于2时,有权限,其他则没有 10 if request.user.user_type == 2: 11 return True 12 return False
2.2 全局使用和局部使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # settings配置文件中 2 REST_FRAMEWORK = { 3 'DEFAULT_PERMISSION_CLASSES':['api.utils.permission.MainPermission'], 4 }
如果是局部使用的话则和认证的局部使用是一样的
permission_classes = [MainPermission,]
2.3 测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class OrderView(APIView): 2 """ 3 模拟订单的增删改查 4 """ 5 def get(self, request): 6 """ 7 get请求为查询订单 8 :param request: 9 :return: 10 """ 11 ret = {'code': 1000, 'msg': None, 'data': None} 12 try: 13 ret['data'] = ORDER_DICT 14 except Exception as e: 15 pass 16 return JsonResponse(ret)
2.4 url访问
127.0.0.1:8000/api/v1/order/?token=bf7b137c8d33a9b90a2b64ee6fda0f49 # get请求,如果token是user_type == 2的用户的,则有权限,其他则没有
3.节流(访问频率控制)
3.1 节流之自定义
3.1.1 访问控制代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from rest_framework.throttling import BaseThrottle 2 import time 3 4 VISIT_RECORD = {} # 真实环境中要放到redis中 5 6 class VisitThrottle(BaseThrottle): 7 """ 8 访问频率控制 9 """ 10 def __init__(self): 11 self.history = None 12 13 def allow_request(self, request, view): 14 15 # 获取client的ip地址 16 remote_addr = request.META.get('REMOTE_ADDR') 17 ctime = time.time() 18 19 # 判断获取到的ip地址是否在VISIT_RECORD字典中 20 if remote_addr not in VISIT_RECORD: 21 22 # 没有则创建,值为列表 23 VISIT_RECORD[remote_addr] = [ctime,] 24 return True 25 26 history = VISIT_RECORD.get(remote_addr) 27 self.history = history 28 29 # 如果列表中有值,且最后面的值大于当前时间-60,则将其删除 30 while history and history[-1] < ctime - 60: 31 history.pop() 32 # 如果列表总长度小于3,则把新访问的时间放到列表的第一位 33 if len(history) < 3: 34 history.insert(0,ctime) 35 return True 36 37 def wait(self): 38 """ 39 等待多时秒后才能访问 40 :return: 41 """ 42 ctime = time.time() 43 return 60-(ctime-self.history[-1])
3.1.2 全局应用(局部应用和认证和权限一样)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_CLASSES':['api.utils.throttle.VisitThrottle'], 3 }
3.1.3 测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class OrderView(APIView): 2 """ 3 模拟订单的增删改查 4 """ 5 6 def get(self, request): 7 """ 8 get请求为查询订单 9 :param request: 10 :return: 11 """ 12 ret = {'code': 1000, 'msg': None, 'data': None} 13 try: 14 ret['data'] = ORDER_DICT 15 except Exception as e: 16 pass 17 return JsonResponse(ret)
3.1.4 url访问
127.0.0.1:8000/api/v1/order/?token=bf7b137c8d33a9b90a2b64ee6fda0f49 # 可登录和有权限的用户 访问超过三次后,返回值为: { "detail": "请求超过了限速。 Expected available in 48 seconds." }
3.2.节流之rest_framework内置类
3.2.1 基于时间的访问频率
a.代码块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class VisitThrottle(SimpleRateThrottle): 2 scope = 'Luffy' # 设置配置文件中所需要的key 3 4 def get_cache_key(self, request, view): # 调用内置方法 5 return self.get_ident(request)
b.配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES':{ 3 'Luffy':'3/m', # 每分钟三次 4 } 5 }
3.2.2 基于username的访问频率
a.基于用户的访问控制
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserThrottle(SimpleRateThrottle): 2 scope = 'LuffyUser' 3 4 def get_cache_key(self, request, view): 5 return request.user.username
b.配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES':{ 3 'LuffyUser':'5/m', # 每分钟5次 4 } 5 }
PS:如果是基于时间访问和基于用户访问同时存在的话,那在配置文件中只设置为基于用户的访问控制就可以,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_CLASSES':['api.utils.throttle.UserThrottle'], 3 }
在自定义的认证类中设置基于频率的访问控制
class AuthView(APIView): """ API """ # 不需要被全局认证的则设置成空列表 authentication_classes = [] permission_classes = [] throttle_classes = [VisitThrottle,] ......
4.版本
4.1 自定义获取版本
访问的 url= 127.0.0.1:8000/api/users/?version=v2&token=bf7b137c8d33a9b90a2b64ee6fda0f49 # get请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class ParamVersion: 2 """ 3 获取版本号 4 """ 5 def determine_version(self,request,*args,**kwargs): 6 7 # 调用rest_framework内置方法query_params 8 version = request.query_params.get('version') 9 return version 10 11 12 class UserView(APIView): 13 """ 14 测试获取版本号 15 """ 16 versioning_class = ParamVersion 17 18 def get(self,request,*args,**kwargs): 19 print(request.version) 20 return HttpResponse('....')
4.2 使用内置方法获取版本
访问的 url= 127.0.0.1:8000/api/users/?version=v2&token=bf7b137c8d33a9b90a2b64ee6fda0f49 # get请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from rest_framework.versioning import QueryParameterVersioning 2 class UserView(APIView): 3 """ 4 测试获取版本号 5 """ 6 # 通过rest_framework内置方法可以直接获取到版本号 7 versioning_class = QueryParameterVersioning 8 9 def get(self,request,*args,**kwargs): 10 print(request.version) 11 return HttpResponse('....')
4.2.1 在配置文件中设置为可以获取默认版本
REST_FRAMEWORK = { 'DEFAULT_VERSION':'v1', # 默认不传参数所获取的版本 'ALLOWED_VERSIONS':['v1','v2','v3'], # 允许使用的版本 'VERSION_PARAM':'version', # get方式默认的传参方式 }
url访问 127.0.0.1:8000/api/users/?token=bf7b137c8d33a9b90a2b64ee6fda0f49 # 不传参数时,默认的就是获取到的版本就是v1
4.3 通过定义url获取版本号
urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view()), # (?P<version>[v1|v2]+)定义版本的正则表达式 ] REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning', # 获取到URLPathVersioning的全路径 }
4.3.1 测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserView(APIView): 2 """ 3 测试获取版本号 4 """ 5 def get(self,request,*args,**kwargs): 6 print(request.version) 7 return HttpResponse('....')
url访问 127.0.0.1:8000/api/v2/users/?token=bf7b137c8d33a9b90a2b64ee6fda0f49
5.解析器(对于解析器来说,主要是通过request.data来取值的)
5.1 配置文件settings中的配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 3 # JSONParser只支持json格式的数据,FormParser支持字符串格式的数据 4 'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'], 5 }
5.2 测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class ParserView(APIView): 2 3 def post(self,request,*args,**kwargs): 4 """ 5 1.获取请求头和请求体 6 2.根据用户的请求头和parser_classes = [JSONParser,FormParser]所 支持的请求头比较,符合那个请求用那个方法 7 3.通过request.data获取最终数据 8 """ 9 10 print(request.data) 11 print(request.data['name']) 12 return HttpResponse(self)
5.3 url配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 urlpatterns = [ 2 url(r'^(?P<version>[v1|v2]+)/parser/$', views.ParserView.as_view()), 3 ]
url访问 127.0.0.1:8000/api/v2/parser/?token=bf7b137c8d33a9b90a2b64ee6fda0f49
6.序列化
序列化分为两大功能:
a.将queryset数据类型序列化后返回给用户
b.对数据进行验证
6.1 单一表的操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import json 2 from rest_framework import serializers 3 4 class RolesSerializer(serializers.Serializer): 5 """ 6 自定义类,继承rest_framework内置序列化模块Serializer 7 """ 8 # 获取数据库中的表字段,且字段名是什么 就写什么 9 title = serializers.CharField() 10 11 class RolesView(APIView): 12 def get(self,request,*args,**kwargs): 13 14 # 方式一, 15 # 1.把queryset对象用list进行转换 16 # 2.通过json序列化把转换后的列表序列化 17 roles = list(models.Role.objects.all().values('id','title')) 18 ret = json.dumps(roles,ensure_ascii=False) 19 20 # 方式二 21 # 1.获取queryset对象 22 roles = models.Role.objects.all() 23 # 2.实例化自定义的类,instance=roles表示要被序列化的对象 ,many=True表示序列化多个对象 24 ser = RolesSerializer(instance=roles,many=True) 25 # 3.通过ser.data获取到所有数据,再通过json序列化 26 ret = json.dumps(ser.data,ensure_ascii=False) 27 28 # 方式三 29 # 1.获取单个对象 30 role = models.Role.objects.all().first() 31 # 2.在实例化自定义类的时候many就必须等于False 32 ser = RolesSerializer(instance=role,many=False) 33 ret = json.dumps(ser.data,ensure_ascii=False) 34 35 return HttpResponse(ret)
6.2 多功能表的操作
url配置 urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userinfo/$', views.UserInfoView.as_view()), ]
6.2.1 基于Serializer实现数据库字段的序列化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoSerializer(serializers.Serializer): 2 3 # 获取有关choices类型中数字所对应的中文值 4 usertype = serializers.CharField(source='get_user_type_display') 5 username = serializers.CharField() 6 password = serializers.CharField() 7 8 # 获取ForeignKey关联数据 9 gp = serializers.CharField(source='group.title') 10 11 # 获取ManyToManyField关联数据,需要自定义函数 12 role = serializers.SerializerMethodField() 13 14 def get_role(self,row): 15 ret = [] 16 roles_obj = row.roles.all() 17 for item in roles_obj: 18 ret.append(item.title) 19 return ret
6.2.2 基于ModelSerializer实现数据库字段的序列化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoSerializer(serializers.ModelSerializer): 2 # 自定义获取有关choice类型的数据中文值 3 usertype = serializers.CharField(source='get_user_type_display') 4 5 # 自定义获取ManyToManyField关联数据 6 role = serializers.SerializerMethodField() 7 8 class Meta: 9 model = models.UserInfo 10 # 将需要展示的字段放到列表里面 11 fields = ['id','username','password','usertype','role'] 12 13 # 如果需要全部字段,则: 14 # fields = "__all__" 15 16 def get_role(self,row): 17 ret = [] 18 roles_obj = row.roles.all() 19 for item in roles_obj: 20 ret.append(item.title) 21 return ret
6.2.3 基于ModelSerializer实现数据库字段的序列化自动连表操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoSerializer(serializers.ModelSerializer): 2 class Meta: 3 model = models.UserInfo 4 # 获取普通字段 5 fields = ['id','user_type','username','password','group','roles'] 6 7 depth = 1 # 取数据库中深层数据 建议层数范围是0-10,0为第一层
返回结果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 { 2 "id": 1, 3 "user_type": 1, 4 "username": "eric", 5 "password": "123123", 6 "group": { 7 "id": 1, 8 "title": "A" 9 }, 10 "roles": [ 11 { 12 "id": 1, 13 "title": "老师" 14 }, 15 { 16 "id": 2, 17 "title": "校长" 18 }, 19 { 20 "id": 3, 21 "title": "班主任" 22 } 23 ] 24 },
测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoView(APIView): 2 def get(self,reqeust,*args,**kwargs): 3 users = models.UserInfo.objects.all() 4 ser = UserInfoSerializer(instance=users,many=True) 5 ret = json.dumps(ser.data,ensure_ascii=False) 6 return HttpResponse(ret)
6.3 序列化之在返回的数据中生成url
url配置
urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userurl/(?P<pk1>\d+)/$', views.UserUrlView.as_view(),name='users'), url(r'^(?P<version>[v1|v2]+)/group/(?P<pk2>\d+)/$', views.GroupUrlView.as_view(),name='gp'), ]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoSerializer(serializers.ModelSerializer): 2 3 """ 4 通过ModelSerializer生产返回数据中的url 5 """ 6 7 # view_name='users' 中的users则是url中的name,pk1则是(?P<pk1>\d+)中的pk1 8 username = serializers.HyperlinkedIdentityField(view_name='user',lookup_url_kwarg='pk1') 9 10 # 如果有数据库中有ForeignKey就需要在实例化 HyperlinkedIdentityField的时候加上lookup_field='group_id' 11 group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id',lookup_url_kwarg='pk2') 12 class Meta: 13 model = models.UserInfo 14 # 获取普通字段 15 fields = ['id','user_type','username','password','group','roles'] 16 depth = 1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class UserInfoView(APIView): 2 """ 3 返回序列化后的数据 4 """ 5 def get(self,request,*args,**kwargs): 6 users = models.UserInfo.objects.all() 7 ser = UserInfoSerializer(instance=users,many=True,context={'request': request}) 8 ret = json.dumps(ser.data,ensure_ascii=False) 9 return HttpResponse(ret) 10 11 12 class GroupSerializer(serializers.ModelSerializer): 13 """ 14 通过生成后的url获取用户组的所需数据 15 """ 16 class Meta: 17 model = models.UserGroup 18 fields = '__all__' 19 20 class UserSerializer(serializers.ModelSerializer): 21 """ 22 通过生成后的url获取用户的所需数据 23 """ 24 class Meta: 25 model = models.UserInfo 26 fields = ['username'] 27 28 29 class UserUrlView(APIView): 30 """ 31 生成用户名对应的url 32 """ 33 def get(self,request,*args,**kwargs): 34 pk = kwargs.get('pk') 35 user_obj = models.UserInfo.objects.filter(pk=pk).first() 36 ser = UserSerializer(instance=user_obj,many=False) 37 38 ret = json.dumps(ser.data,ensure_ascii=False) 39 40 return HttpResponse(ret) 41 42 43 class GroupUrlView(APIView): 44 """ 45 生成用户组对应的url 46 """ 47 def get(self,request,*args,**kwargs): 48 pk = kwargs.get('pk') 49 group_obj = models.UserGroup.objects.filter(pk=pk).first() 50 ser = GroupSerializer(instance=group_obj,many=False,) 51 52 ret = json.dumps(ser.data,ensure_ascii=False) 53 return HttpResponse(ret)
返回结果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 { 2 "id": 1, 3 "user_type": 1, 4 "username": "http://127.0.0.1:8000/api/v2/userurl/1/", # 通过url可以获取到对应的数据 5 "password": "123123", 6 "group": "http://127.0.0.1:8000/api/v2/group/1/", 7 "roles": [ 8 { 9 "id": 1, 10 "title": "老师" 11 }, 12 { 13 "id": 2, 14 "title": "校长" 15 }, 16 { 17 "id": 3, 18 "title": "班主任" 19 } 20 ] 21 },
7.分页(三个方法)
7.1 分多少页,每页显示多少数据 (PageNumberPagination类)
7.1.1 定义一个获取数据库数据的serializer
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from rest_framework import serializers 2 from api import models 3 4 class PagerSerializer(serializers.ModelSerializer): 5 class Meta: 6 model = models.Role 7 fields = '__all__'
7.1.2 使用rest_framework内置方法
定义url
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 urlpatterns = [ 2 url(r'^admin/', admin.site.urls), 3 url(r'^(?P<version>[v1|v2]+)/pager/', views.PagerView.as_view()), 4 ]
展示数据视图
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from api.utils.serializsers.Pager import PagerSerializer 2 from rest_framework.response import Response 3 from rest_framework.pagination import PageNumberPagination 4 5 class PagerView(APIView): 6 def get(self,request,*args,**kwargs): 7 8 # 获取数据库所有数据 9 roles = models.Role.objects.all() 10 11 # 实例化PageNumberPagination 12 page = PageNumberPagination() 13 14 # 通过对象page调用PageNumberPagination内置方法paginate_queryset,参数为queryset=roles 为queryset对象 15 roles_data = page.paginate_queryset(queryset=roles,request=request,view=self) 16 # 将数据库的数据序列化 17 ser = PagerSerializer(instance=roles_data, many=True) 18 19 # 调用rest_framework的Response返回序列化后的数据 20 return Response(ser.data)
配置文件中:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 REST_FRAMEWORK = { 2 'PAGE_SIZE':3, # 全局配置每页显示的条数 3 }
7.1.3 自定义方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from api.utils.serializsers.Pager import PagerSerializer 2 from rest_framework.pagination import PageNumberPagination 3 4 class MyPageNumberPagination(PageNumberPagination): 5 6 # 设置每页显示几条数据 7 page_size = 2 8 9 # get传参的方式获取第几页数据的关键字 10 page_query_param = 'page' 11 12 # get传参的方式定义每页显示多少条数据的关键字 13 page_size_query_param = 'size' 14 15 # 每页最大显示数据条数 16 max_page_size = 4
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class PagerView(APIView): 2 def get(self,request,*args,**kwargs): 3 roles = models.Role.objects.all() 4 page = MyPageNumberPagination() 5 roles_data = page.paginate_queryset(queryset=roles,request=request,view=self) 6 ser = PagerSerializer(instance=roles_data, many=True) 7 8 # 通过get_paginated_response可以获取到上一页下一页等按钮 9 return page.get_paginated_response(ser.data)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 { 2 "count": 10, # 数据库数据总条数 3 "next": "http://127.0.0.1:8000/api/v2/pager/? page=3&token=006473eea82c8544d6199a095c0bffe4", # 表示下一页 4 "previous": "http://127.0.0.1:8000/api/v2/pager/? token=006473eea82c8544d6199a095c0bffe4", # 表示上一页 5 "results": [ 6 { 7 "id": 3, 8 "title": "班主任" 9 }, 10 { 11 "id": 4, 12 "title": "警察" 13 } 14 ] 15 }
7.2 指定索引位置,向后查看多少条数数据(LimitOffsetPagination)
7.2.1 继续使用定义好的serializer
djangorestframework\api\utils\serializsers\Pager.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from rest_framework import serializers 2 from api import models 3 4 class PagerSerializer(serializers.ModelSerializer): 5 class Meta: 6 model = models.Role 7 fields = '__all__'
7.2.2 使用内置方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from api.utils.serializsers.Pager import PagerSerializer 2 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination 3 class PagerView(APIView): 4 def get(self,request,*args,**kwargs): 5 roles = models.Role.objects.all() 6 7 # 实例化LimitOffsetPagination 8 page = LimitOffsetPagination() 9 roles_data = page.paginate_queryset(queryset=roles,request=request,view=self) 10 ser = PagerSerializer(instance=roles_data, many=True) 11 return page.get_paginated_response(ser.data)
7.2.3 自定义方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class MyLimitOffsetPagination(LimitOffsetPagination): 2 3 # 设置每页显示几条数据 4 default_limit = 2 5 6 # get传参的方式获取索引位置的关键字 7 limit_query_param = 'limit' 8 9 # get传参的方式定义每页向后显示多少条数据的关键字 10 offset_query_param = 'offset' 11 12 # 每页最大显示数据条数 13 max_limit = 5 14 15 16 class PagerView(APIView): 17 def get(self,request,*args,**kwargs): 18 roles = models.Role.objects.all() 19 20 # 实例化自定义的类 21 page = MyLimitOffsetPagination() 22 roles_data = page.paginate_queryset(queryset=roles,request=request,view=self) 23 ser = PagerSerializer(instance=roles_data, many=True) 24 # return Response(ser.data) 25 26 # 使用page.get_paginated_response可以在页面展示的时候显示上一页和下一页 27 return page.get_paginated_response(ser.data)
7.3 加密页码 CursorPagination
7.3.1 继续使用定义好的serializer
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 djangorestframework\api\utils\serializsers\Pager.py 2 from rest_framework import serializers 3 from api import models 4 5 class PagerSerializer(serializers.ModelSerializer): 6 class Meta: 7 model = models.Role 8 fields = '__all__'
7.3.2 自定义方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from api.utils.serializsers.Pager import PagerSerializer 2 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination 3 4 class MyCursorPagination(CursorPagination): 5 6 # get传参的方式获取第几页数据的关键字,但是不能那么传,会报错 7 cursor_query_param = 'cursor' 8 9 # 设置每页显示几条数据 10 page_size = 2 11 12 # 数据显示的排序方式 13 ordering = 'id' 14 15 class PagerView(APIView): 16 def get(self,request,*args,**kwargs): 17 roles = models.Role.objects.all() 18 page = MyCursorPagination() 19 roles_data = page.paginate_queryset(queryset=roles,request=request,view=self) 20 ser = PagerSerializer(instance=roles_data, many=True) 21 return page.get_paginated_response(ser.data)
8.视图
url设置
urlpatterns = [ # 'get': 'retrieve':表示get请求,'post':'create':表示post请求,'put':'update':表示批量修改,'patch':'partial_update':表示局部修改,'delete':'destroy':表示删除操作 url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>\d+)/$', views.ViewView.as_view({'get': 'retrieve','post':'create','put':'update','patch':'partial_update','delete':'destroy'})), ]
from rest_framework.viewsets import ModelViewSet from api.utils.serializsers.Pager import PagerSerializer class ViewView(ModelViewSet): # 获取要展示的数据的queryset对象 queryset = models.Role.objects.all() # 获取被序列化后的要展示的信息 serializer_class = PagerSerializer # 调用自定义的页码类,应该可以不用这个 pagination_class =MyCursorPagination
在自定义的视图中,继承ModelViewSet,但同时ModelViewSet又分别继承了六个类
class ModelViewSet(mixins.CreateModelMixin, # 创建数据,相当于post请求 mixins.RetrieveModelMixin, # 获取单一数据,相当于get mixins.UpdateModelMixin, # 更新数据,相当于put和patch mixins.DestroyModelMixin, # 删除数据,相当于delete mixins.ListModelMixin, # 获取多个数据,相当于get GenericViewSet): # 通过继承GenericViewSet 可以获取到一些需要被展示的数据
9.路由
在URL中自动生成路由
from rest_framework import routers router = routers.DefaultRouter() router.register(r'abc',views.ViewView) urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/', include(router.urls)), ]
结果:
^api/ ^(?P<version>[v1|v2]+)/ ^abc/$ [name='role-list'] ^api/ ^(?P<version>[v1|v2]+)/ ^abc\.(?P<format>[a-z0-9]+)/?$ [name='role-list'] ^api/ ^(?P<version>[v1|v2]+)/ ^abc/(?P<pk>[^/.]+)/$ [name='role-detail'] ^api/ ^(?P<version>[v1|v2]+)/ ^abc/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='role-detail']
自动生成了四个url,这四个url提供增删改查功能
10.渲染
配置文件中配置:
# JSONRenderer只显示json数据,BrowsableAPIRenderer通过浏览器渲染后的数据 REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer','rest_framework.renderers.BrowsableAPIRenderer'], }
访问之前的url就能看出效果