一 认证
核心代码
class OrderView(APIView): authentication_classes = [Authentication,] def get(self,request,*args,**kwargs): pass
class Authentication(object): def authenticate(self,request): token = request._request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed('用户认证失败!') return (token_obj.user,token_obj) def authenticate_header(self,request): pass
源码流程:
1 dispatch
2 封装request
3 initial方法
4 perform_authentication方法
5 6 request.user
7 self._authenticate方法 返回值有三种情况,空,报错,(request.user,request.auth)
8 循环
1. 认证
a. 问题1:有些API需要用户登录成功之后,才能访问;有些无需登录就能访问。
b. 基本使用认证组件
解决:
a. 创建两张表
b. 用户登录(返回token并保存到数据库)
c. 认证流程原理
- 见图示
d. 再看一遍源码
1. 局部视图使用&全局使用
2. 匿名是request.user = None
e. 内置认证类
1. 认证类,必须继承:from rest_framework.authentication import BaseAuthentication
2. 其他认证类:BasicAuthentication
梳理:
1. 使用
- 创建类:继承BaseAuthentication; 实现:authenticate方法
- 返回值:
- None,我不管了,下一认证来执行。
- raise exceptions.AuthenticationFailed('用户认证失败') # from rest_framework import exceptions
- (元素1,元素2) # 元素1赋值给request.user; 元素2赋值给request.auth
- 局部使用
from rest_framework.authentication import BaseAuthentication,BasicAuthentication
class UserInfoView(APIView):
"""
订单相关业务
"""
authentication_classes = [BasicAuthentication,]
def get(self,request,*args,**kwargs):
print(request.user)
return HttpResponse('用户信息')
- 全局使用:
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
# "UNAUTHENTICATED_USER":lambda :"匿名用户"
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
}
2. 源码流程
- dispatch
- 封装request
- 获取定义的认证类(全局/局部),通过列表生成时创建对象。
- initial
- perform_authentication
request.user(内部循环....)
二 权限
问题:不用视图不用权限可以访问
基本使用:
class MyPermission(object):
def has_permission(self,request,view):
if request.user.user_type != 3:
return False
return True
class OrderView(APIView):
"""
订单相关业务(只有SVIP用户有权限)
"""
permission_classes = [MyPermission,]
def get(self,request,*args,**kwargs):
# request.user
# request.auth
self.dispatch
ret = {'code':1000,'msg':None,'data':None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
源码流程:
- ...
梳理:
1. 使用
- 类,必须继承:BasePermission,必须实现:has_permission方法
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
message = "必须是SVIP才能访问"
def has_permission(self,request,view):
if request.user.user_type != 3:
return False
return True
- 返回值:
- True, 有权访问
- False,无权访问
- 局部
class UserInfoView(APIView):
"""
订单相关业务(普通用户、VIP)
"""
permission_classes = [MyPermission1, ]
def get(self,request,*args,**kwargs):
return HttpResponse('用户信息')
- 全局
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission']
}
2. 源码流程
三 节流
问题:控制访问频率
import time
VISIT_RECORD = {}
class VisitThrottle(object):
"""60s内只能访问3次"""
def __init__(self):
self.history = None
def allow_request(self,request,view):
# 1. 获取用户IP
remote_addr = request.META.get('REMOTE_ADDR')
ctime = time.time()
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime,]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3:
history.insert(0,ctime)
return True
# return True # 表示可以继续访问
# return False # 表示访问频率太高,被限制
def wait(self):
"""
还需要等多少秒才能访问
:return:
"""
ctime = time.time()
return 60 - (ctime - self.history[-1])
class AuthView(APIView):
"""
用于用户登录认证
"""
authentication_classes = []
permission_classes = []
throttle_classes = [VisitThrottle,]
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = "用户名或密码错误"
# 为登录用户创建token
token = md5(user)
# 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
源码流程:
...
内置控制频率类:
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope = "Luffy"
def get_cache_key(self, request, view):
return self.get_ident(request)
class UserThrottle(SimpleRateThrottle):
scope = "LuffyUser"
def get_cache_key(self, request, view):
return request.user.username
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
# "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication', ],
# "UNAUTHENTICATED_USER":lambda :"匿名用户"
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
"DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'],
"DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
"DEFAULT_THROTTLE_RATES":{
"Luffy":'3/m',
"LuffyUser":'10/m',
}
}
四 版本
1 127.0.0.1:8000/api/users/?version=xx 的样式,在url中通过get传参
1)自定义
class MyVersion(object): def determine_version(self,request,*args,**kwargs): return request._request.GET.get('version') class UserView(APIView): versioning_class = MyVersion def get(self,request,*args,**kwargs): print(request.version) return HttpResponse('用户列表')
2)内置类 QueryParameterVersioning
from rest_framework.views import APIView from rest_framework.versioning import QueryParameterVersioning # class MyVersion(object): # def determine_version(self,request,*args,**kwargs): # return request._request.GET.get('version') class UserView(APIView): versioning_class = QueryParameterVersioning def get(self,request,*args,**kwargs): print(request.version) return HttpResponse('用户列表')
全局设置
REST_FRAMEWORK = { "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', }
2 127.0.0.1:8000/api/v1/users/ 在url中传参,推荐
urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$',views.UserView.as_view()), ]
from rest_framework.versioning import URLPathVersioning class UserView(APIView): def get(self,request,*args,**kwargs): print(request.version) return HttpResponse('用户列表')
REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', }
总结: 使用: 配置文件: REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', } 路由系统: urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), ] urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'), ] 视图: class UsersView(APIView): def get(self,request,*args,**kwargs): # 1. 获取版本 print(request.version) # 2. 获取处理版本的对象 print(request.versioning_scheme) # 3. 反向生成URL(rest framework) u1 = request.versioning_scheme.reverse(viewname='uuu',request=request) print(u1) # 4. 反向生成URL u2 = reverse(viewname='uuu',kwargs={'version':2}) print(u2) return HttpResponse('用户列表')
五 解析器 对请求体数据进行解析
铺垫
request.POST中有值的两个条件
1 请求头要求:Content-Type: application/x-www-form-urlencoded
2 数据体要求:name=alex&age=18&gender=男
如
a:form表单提交,默认符合
b:ajax提交
$.ajax({ url:... type:POST, data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男 }) 情况一: $.ajax({ url:... type:POST, headers:{'Content-Type':"application/json"} data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男 }) # body有值;POST无 情况二: $.ajax({ url:... type:POST, headers:{'Content-Type':"application/json"} data:JSON.stringfy({name:alex,age=18}) # {name:alex,age:18...} }) # body有值;POST无 # json.loads(request.body)
总结: 使用: 配置: REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'] } 使用: class ParserView(APIView): # parser_classes = [JSONParser,FormParser,] """ JSONParser:表示只能解析content-type:application/json头 JSONParser:表示只能解析content-type:application/x-www-form-urlencoded头 """ def post(self,request,*args,**kwargs): """ 允许用户发送JSON格式数据 a. content-type: application/json b. {'name':'alex',age:18} :param request: :param args: :param kwargs: :return: """ """ 1. 获取用户请求 2. 获取用户请求体 3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较 4. JSONParser对象去请求体 5. request.data """ print(request.data) return HttpResponse('ParserView') 源码流程 & 本质: a. 本质 请求头 :... 状态码: ... 请求方法:... b. 源码流程 - dispatch: request封装 - request.data
六 序列化
序列化的两个作用:
1) 序列化
2 )请求数据校验
作用 1
from rest_framework import serializers class RoleSerialize(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField() class RoleView(APIView): # 方式一 比较low的方法 # def get(self,request,*args,**kwargs): # roles = models.Role.objects.all().values('id','title') # roles = list(roles) # return HttpResponse(json.dumps(roles)) # 方式二 def get(self,request,*args,**kwargs): roles = models.Role.objects.all() ser = RoleSerialize(instance=roles,many=True) print(ser.data) return HttpResponse(json.dumps(ser.data))
进阶1 关于choices
Model:
class UserInfo(models.Model): user_type_choices = ( (1,'NORM'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices,default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) usergroup = models.ForeignKey(to='UserGroup') roles = models.ManyToManyField('Role')
CBV:
class UserinfoSerialize(serializers.Serializer): user_type = serializers.CharField(source='get_user_type_display') # user_type字典 前面加get_,后面加_display username = serializers.CharField() class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
进阶二,关于外键
model:
class UserInfo(models.Model): user_type_choices = ( (1,'NORM'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices,default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) usergroup = models.ForeignKey(to='UserGroup') roles = models.ManyToManyField('Role')
class UserGroup(models.Model): title = models.CharField(max_length=32)
视图:
class UserinfoSerialize(serializers.Serializer): user_type = serializers.CharField(source='get_user_type_display') username = serializers.CharField() group = serializers.CharField(source='usergroup.title') #通过.调用 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
进阶三 关于多对多
model
class UserInfo(models.Model): user_type_choices = ( (1,'NORM'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices,default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) usergroup = models.ForeignKey(to='UserGroup') roles = models.ManyToManyField('Role')
class Role(models.Model): title = models.CharField(max_length=32)
视图:
class UserinfoSerialize(serializers.Serializer): user_type = serializers.CharField(source='get_user_type_display') username = serializers.CharField() group = serializers.CharField(source='usergroup.title') roles = serializers.SerializerMethodField() #自定义显示 def get_roles(self,row): #row 代表当前行的对象, roles_list = row.roles.all() ret = [] for item in roles_list: ret.append({'id':item.id,'title':item.title}) return ret #返回啥,页面显示啥 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
进阶四。每个字段都写,很难受,简单的做法
class UserinfoSerialize(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = '__all__' class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
但是,显示也简单了
[{"id": 1, "user_type": 1, "username": "loda", "password": "123", "usergroup": 2, "roles": [1]}, {"id": 2, "user_type": 1, "username": "s4", "password": "123", "usergroup": 2, "roles": [2, 3]}, {"id": 3, "user_type": 1, "username": "bulldog", "password": "123", "usergroup": 2, "roles": [3]}, {"id": 4, "user_type": 2, "username": "miracle", "password": "123", "usergroup": 1, "roles": [1, 2]}, {"id": 5, "user_type": 2, "username": "krokky", "password": "123", "usergroup": 1, "roles": [1, 3]}, {"id": 6, "user_type": 2, "username": "mind_contrlo", "password": "123", "usergroup": 1, "roles": [3]}]
进阶五 最终版本 混合使用
class UserinfoSerialize(serializers.ModelSerializer): roles = serializers.SerializerMethodField() # 自定义显示 def get_roles(self,row): #row 代表当前行的对象, roles_list = row.roles.all() ret = [] for item in roles_list: ret.append({'id':item.id,'title':item.title}) return ret #返回啥,页面显示啥 class Meta: model = models.UserInfo # fields = '__all__' fields = ['username','password','roles'] class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
显示:
[{"username": "loda", "password": "123", "roles": [{"id": 1, "title": "carry"}]}, {"username": "s4", "password": "123", "roles": [{"id": 2, "title": "mid"}, {"id": 3, "title": "support"}]}, {"username": "bulldog", "password": "123", "roles": [{"id": 3, "title": "support"}]}, {"username": "miracle", "password": "123", "roles": [{"id": 1, "title": "carry"}, {"id": 2, "title": "mid"}]}, {"username": "krokky", "password": "123", "roles": [{"id": 1, "title": "carry"}, {"id": 3, "title": "support"}]}, {"username": "mind_contrlo", "password": "123", "roles": [{"id": 3, "title": "support"}]}]
进阶六: 自动序列化连表 depth
视图:
class UserinfoSerialize(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = '__all__' depth = 1 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
输出: 完美!
[{"id": 1, "user_type": 1, "username": "loda", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 1, "title": "carry"}]}, {"id": 2, "user_type": 1, "username": "s4", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 2, "title": "mid"}, {"id": 3, "title": "support"}]}, {"id": 3, "user_type": 1, "username": "bulldog", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 3, "title": "support"}]}, {"id": 4, "user_type": 2, "username": "miracle", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 1, "title": "carry"}, {"id": 2, "title": "mid"}]}, {"id": 5, "user_type": 2, "username": "krokky", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 1, "title": "carry"}, {"id": 3, "title": "support"}]}, {"id": 6, "user_type": 2, "username": "mind_contrlo", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 3, "title": "support"}]}]
总结:
1. 写类 class RolesSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField() class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo # fields = "__all__" fields = ['id','username','password',] 2. 字段 a. title = serializers.CharField(source="xxx.xxx.xx.xx") b. title = serializers.SerializerMethodField() class UserInfoSerializer(serializers.ModelSerializer): rls = serializers.SerializerMethodField() # 自定义显示 class Meta: model = models.UserInfo fields = ['id','username','password','rls',] # 自定义方法 def get_rls(self, row): role_obj_list = row.roles.all() ret = [] for item in role_obj_list: ret.append({'id':item.id,'title':item.title}) return ret c. 自定义类 3. 自动序列化连表 class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo # fields = "__all__" fields = ['id','username','password','group','roles'] depth = 1 # 0 ~ 10 4. 生成链接 class UserInfoSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx') class Meta: model = models.UserInfo # fields = "__all__" fields = ['id','username','password','group','roles'] depth = 0 # 0 ~ 10 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users,many=True,context={'request': request}) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret)
作用2 请求数据校验
class UserGroupSerialize(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'}) class UserGroupView(APIView): def post(self,request,*args,**kwargs): ser = UserGroupSerialize(data=request.data) if ser.is_valid(): print(ser.validated_data['title']) else: print(ser.errors) return HttpResponse('xxx')
钩子函数
def validate_字段名(self,value):
if True:
return value
else:
raise ..
class RoleSerialize(serializers.Serializer): title = serializers.CharField(error_messages={'required':'不能为空!'}) def validate_title(self,value): print(value) if 1: raise exceptions.ValidationError('shabi') else: return value class RoleView(APIView): # 方式一 比较low的方法 # def get(self,request,*args,**kwargs): # roles = models.Role.objects.all().values('id','title') # roles = list(roles) # return HttpResponse(json.dumps(roles)) # 方式二 def post(self,request,*args,**kwargs): roles = models.Role.objects.all() # ser = RoleSerialize(instance=roles,many=True) ser = RoleSerialize(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) print(ser.errors['title']) # print(ser.data) return HttpResponse('xxx')
七 分页
第一种 看第n页,每页显示n条数据。
啥都不干的最开始的代码。
model
class UserInfo(models.Model): user_type_choices = ( (1,'NORM'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices,default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) usergroup = models.ForeignKey(to='UserGroup') roles = models.ManyToManyField('Role')
视图 :单纯的将序列化后的数据返回。
from rest_framework import serializers from api import models class UserinfoSerialize(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = '__all__' depth = 1
class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) return HttpResponse(json.dumps(ser.data))
路由
url(r'^(?P<version>[v1|v2]+)/users/$',views.UserInfoView.as_view()),
通过postman,显示如下。很难看。
[{"id": 1, "user_type": 1, "username": "loda", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 1, "title": "carry"}]}, {"id": 2, "user_type": 1, "username": "s4", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 2, "title": "mid"}, {"id": 3, "title": "support"}]}, {"id": 3, "user_type": 1, "username": "bulldog", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": [{"id": 3, "title": "support"}]}, {"id": 4, "user_type": 2, "username": "miracle", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 1, "title": "carry"}, {"id": 2, "title": "mid"}]}, {"id": 5, "user_type": 2, "username": "krokky", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 1, "title": "carry"}, {"id": 3, "title": "support"}]}, {"id": 6, "user_type": 2, "username": "mind_contrlo", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": [{"id": 3, "title": "support"}]}, {"id": 7, "user_type": 2, "username": "akke", "password": "123", "usergroup": {"id": 2, "title": "allience"}, "roles": []}, {"id": 8, "user_type": 3, "username": "matubman", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": []}, {"id": 9, "user_type": 3, "username": "gh", "password": "123", "usergroup": {"id": 1, "title": "liquid"}, "roles": []}, {"id": 10, "user_type": 1, "username": "hao", "password": "123", "usergroup": {"id": 3, "title": "newbee"}, "roles": []}, {"id": 11, "user_type": 2, "username": "mu", "password": "123", "usergroup": {"id": 3, "title": "newbee"}, "roles": []}, {"id": 12, "user_type": 3, "username": "xiao8", "password": "123", "usergroup": {"id": 3, "title": "newbee"}, "roles": []}, {"id": 13, "user_type": 1, "username": "sansheng", "password": "123", "usergroup": {"id": 3, "title": "newbee"}, "roles": []}, {"id": 14, "user_type": 2, "username": "banana", "password": "123", "usergroup": {"id": 3, "title": "newbee"}, "roles": []}]
运用渲染 进阶1 :
1 在settings.py 的 installed_apps里 注册rest_framework,
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'api.apps.ApiConfig', 'rest_framework', ]
2 导入Response,返回时甚至连都不需要json,都帮你做好了。
from rest_framework.response import Response class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() ser = UserinfoSerialize(instance=users,many=True) # return HttpResponse(json.dumps(ser.data)) return Response(ser.data)
改完后,页面显示如下。
牛不牛逼!
进阶2
使用内置的分页
from api.utils.serializer.userinfo import UserinfoSerialize from rest_framework.response import Response from rest_framework.pagination import PageNumberPagination class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() page = PageNumberPagination() #实例化 #返回 分页后的对象,即page_users,而不是所有对象,users page_users = page.paginate_queryset(queryset=users,request=request,view=self) #queryset=从数据库拿到的queryset类型数据,view=当前视图的对象 ser = UserinfoSerialize(instance=page_users,many=True) # return HttpResponse(json.dumps(ser.data)) return Response(ser.data)
内置,可以在url加?page=x,调到某一页。
进阶3 基于PageNumberPagination的基础上自定义分页
from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination): page_size = 3 page_query_param = 'page' page_size_query_param = 'size' max_page_size = 10 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() page = MyPageNumberPagination() #实例化 #返回 分页后的对象,即page_users,而不是所有对象,users page_users = page.paginate_queryset(queryset=users,request=request,view=self) #queryset=从数据库拿到的queryset类型数据,view=当前视图的对象 ser = UserinfoSerialize(instance=page_users,many=True) # return HttpResponse(json.dumps(ser.data)) return Response(ser.data)
可以实现内置分页类,并不能实现的在url后面加size参数的功能。另外,尽管全局设置为page=3,当前引用的自定义类,page=2,也是以引用的自定义的分页类为准。
进阶四
返回更为详细的数据
视图
class MyPageNumberPagination(PageNumberPagination): page_size = 3 page_query_param = 'page' page_size_query_param = 'size' max_page_size = 10 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() page = MyPageNumberPagination() #实例化 #返回 分页后的对象,即page_users,而不是所有对象,users page_users = page.paginate_queryset(queryset=users,request=request,view=self) #queryset=从数据库拿到的queryset类型数据,view=当前视图的对象 ser = UserinfoSerialize(instance=page_users,many=True) # return HttpResponse(json.dumps(ser.data)) # return Response(ser.data) return page.get_paginated_response(data=ser.data) #!!
访问成功后显示:
其中,next,previous,都是超链接。
第二种 在第n位置,向后查看n条数据
LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination class MyPageNumberPagination(LimitOffsetPagination): limit_query_param = 'limit' offset_query_param = 'offset' max_limit = 5 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() page = MyPageNumberPagination() #实例化 #返回 分页后的对象,即page_users,而不是所有对象,users page_users = page.paginate_queryset(queryset=users,request=request,view=self) #queryset=从数据库拿到的queryset类型数据,view=当前视图的对象 ser = UserinfoSerialize(instance=page_users,many=True) # return HttpResponse(json.dumps(ser.data)) # return Response(ser.data) return page.get_paginated_response(data=ser.data)
样式:
第三种 加密分页 上一页,下一页
class MyPageNumberPagination(CursorPagination): cursor_query_param = 'cursor' page_size = 4 # invalid_cursor_message = _('Invalid cursor') ordering = 'id' page_size_query_param = 'size' max_page_size = 10 class UserInfoView(APIView): def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() page = MyPageNumberPagination() #实例化 #返回 分页后的对象,即page_users,而不是所有对象,users page_users = page.paginate_queryset(queryset=users,request=request,view=self) #queryset=从数据库拿到的queryset类型数据,view=当前视图的对象 ser = UserinfoSerialize(instance=page_users,many=True) # return HttpResponse(json.dumps(ser.data)) # return Response(ser.data) return page.get_paginated_response(data=ser.data)
页面显示:
注意,这一种分页,必须使用page.get_paginated_response。因为在url中cursor='' 是什么你是不知道的,只能点上一页,下一页。
八 视图
视图的继承关系
GenericViewSet 实现了 as_view({'get':'xx'...})
视图:
from rest_framework.viewsets import ModelViewSet class UserInfoView(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = UserinfoSerialize pagination_class = PageNumberPagination
路由:
url(r'^(?P<version>[v1|v2]+)/users/$',views.UserInfoView.as_view({'post':'create','get':'list'})), url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>d+)/$',views.UserInfoView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'})),
总结:
a. 增删改查 ModelViewSet
b. 增删 CreateModelMixin,DestroyModelMixin GenericViewSet
c. 复杂逻辑 GenericViewSet 或 APIView
九 路由
a.
url(r'^(?P<version>[v1|v2]+)/parser/$', views.ParserView.as_view()),
b.
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
c.
# http://127.0.0.1:8000/api/v1/v1/?format=json
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
# http://127.0.0.1:8000/api/v1/v1.json
url(r'^(?P<version>[v1|v2]+)/v1.(?P<format>w+)$', views.View1View.as_view({'get': 'list','post':'create'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>d+).(?P<format>w+)$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
d.
from api import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'users', views.UserInfoView)
router.register(r'roles', views.RolesView)
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
]
十 渲染
局部渲染
class TestView(APIView): # renderer_classes = [JSONRenderer,BrowsableAPIRenderer] def get(self, request, *args, **kwargs): ...
全局渲染
REST_FRAMEWORK = { "DEFAULT_RENDERER_CLASSES":[ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ] }