一、什么是restful?
REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”、
REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
二、restful API设计(规范)
一、API与用户的通信协议,总是使用HTTPS协议 二、域名 https:api.zhangjianping.com 尽量将API部署在专用的域名(不存在跨域问题) https:zhangjianping.org/api 简单的API 三、版本 URL: https:api.zhangjianping.com/v1 请求头 跨域时,引发发送多次请求 四、路径,网络上的东西都是资源,均使用名词去表示 五、method GET:从服务器取出资源(一项或者是多项) POST:在服务器新建一个资源 PUT:在服务器更新资源(客户端提供改变后的完整资源) PATCH:在服务器更新资源(客户端提供改变的属性) DELETE:从服务器删除资源 六、过滤 通过在url上传参的形式传递搜索条件 七、状态码 八、错误处理 九、返回结果
十、Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
三、基于Django实现
路由系统:
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/$',views.User.as_view()), ]
CBV视图:
from django.http import JsonResponse from django.views import View class User(View): def get(self,request,*args,**kwargs): result = { "status":True, "data":"response data" } return JsonResponse(result,status=200) def post(self,request,*args,**kwargs): result = { "status":True, "data":"response data" } return JsonResponse(result,status=200)
四、基于Django-Rest-Framework框架实现
1、基本流程
路由系统:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^test/$',views.TestView.as_view()) ]
CBV视图:
from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def dispath(self,request,*args,**kwargs):
"""请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发不同的函数来处理""" return super().dispatch(request,*args,**kwargs) def get(self,request,*args,**kwargs): return Response("GET请求,响应内容") def post(self,request,*args,**kwargs): return Response("POST请求,响应内容") def put(self,request,*args,**kwargs): return Response("PUT请求,响应内容")
以上这段代码就是rest framework框架的基本流程,重要的功能都是在APIView中的dispatch中触发的
当你运行上段代码会报错:
你使用的是restframework,但是模板用的却是Django的,所以报错在所难免,解决的办法就是在配置文件中注册
2、认证和授权
路由系统
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^test/$',views.TestView.as_view()) ]
CBV视图:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions token_list = [ "zhangjianping", #可以授权的数据 ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): ''' 用户认证,认证成功后返回元组 :param request: :return: ''' val = request.query_params.get("token") #get请求从网址栏获取到的数据 if val not in token_list: #判断当前url是否可以授权访问 raise exceptions.AuthenticationFailed("用户认证失败") return ("登录用户,","用户token") def authenticate_header(self, request): pass class TestView(APIView): ''' 调用这个函数的时候,会自动触发authentication_classes的运行,所以会先执行上边的类 ''' authentication_classes = [TestAuthentication,] permission_classes = [] def get(self,request,*args,**kwargs): print("====request.user====",request.user) #当前登录的用户 print("====request.auth====",request.auth) #获取到的用户token return Response("GET请求,响应内容") def post(self,request,*args,**kwargs): return Response("POST请求,响应内容") def put(self,request,*args,**kwargs): return Response("PUT请求,响应内容")
3、用户登录
路由系统:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^auth/$',views.AuthView.as_view()), ]
model表操作:
from django.db import models class UserInfo(models.Model): username = models.CharField(max_length=16) password = models.CharField(max_length=16) token = models.CharField(max_length=64,null=True)
CBV视图:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions import time,hashlib from app01 import models class AuthView(APIView): authentication_classes = [] def get(self,request): ret = {"code":1000,"msg":None} user = request.query_params.get("user") pwd = request.query_params.get("pwd") obj = models.UserInfo.objects.filter(username=user,password=pwd).first() if not obj: #如果没有获取到用户信息执行 ret["code"] = 1001 ret["msg"] = "用户名或密码错误" return Response(ret) ctime = time.time() #得到一个时间戳 key = "%s|%s"%(user,ctime) #类似于加密盐 m = hashlib.md5() m.update(key.encode("utf-8")) token = m.hexdigest() #token经过MD5加密处理 obj.token = token #数据库的空字符串,颁发授权信息 ret["token"] = token #写入数据表 return Response(ret)
4、限制访问频率
路由系统
from django.conf.urls import url from django.contrib import admin from app01 import views from app02 import views as app02_view from app03 import views as app03_view urlpatterns = [ rl(r'^salary/', app02_view.SalaryView.as_view()), url(r'^limit/', app03_view.LimitView.as_view()), ]
#配置文件
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ # "app02.utils.MyAuthentication", ], 'DEFAULT_PERMISSION_CLASSES':[ ], 'DEFAULT_THROTTLE_RATES':{ 'wdp':'2/minute' #每分钟两次 } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': 'cache', 数据默认报错在缓存 } }
#生写,自己实现 -----CBV视图 from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import BaseThrottle,SimpleRateThrottle from rest_framework import exceptions RECORD = { } class MyThrottle(BaseThrottle): def allow_request(self,request,view): """ # 返回False,限制 # 返回True,通行 :param request: :param view: :return: """ """ a. 对匿名用户进行限制:每个用户1分钟允许访问10次 - 获取用户IP request 1.1.1.1 """ import time ctime = time.time() #获取当前时间 ip = self.get_ident(request) #获取IP if ip not in RECORD: #IP没有在新建的那个字典 RECORD[ip] = [ctime,] #将当前的IP作为key,时间作为value列表 else: # [4507862389234,3507862389234,2507862389234,1507862389234,] time_list = RECORD[ip] #如果在的话获取IP时间列表 while True: val = time_list[-1] #取出最后一个值 if (ctime-60) > val: #如果当前的时间-60秒>取出的最后一个值 time_list.pop() #就将这个值取出来 else: break if len(time_list) > 10: #一分钟访问次数超过10次,return False return False time_list.insert(0,ctime) #将当前时间插入到第一个位置 return True def wait(self,request): """ :return: 返回需要等待的时间 """ import time ctime = time.time() first_in_time = RECORD[self.get_ident(request)][-1] wt = 60 - (ctime - first_in_time) #等待的时间 return wt class LimitView(APIView): authentication_classes = [] permission_classes = [] throttle_classes=[MyThrottle,] def get(self,request,*args,**kwargs): # self.dispatch return Response('控制访问频率示例') def throttled(self, request, wait): """ If request is throttled, determine what kind of exception to raise. """ class MyThrottled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = 'Expected available in {wait} second.' extra_detail_plural = '还需要再等待{wait}' raise MyThrottled(wait)
CBV路由系统
class MySimpleRateThrottle(SimpleRateThrottle): scope = "wdp" def get_cache_key(self, request, view): return self.get_ident(request) class LimitView(APIView): authentication_classes = [] permission_classes = [] throttle_classes=[MySimpleRateThrottle,] def get(self,request,*args,**kwargs): # self.dispatch return Response('控制访问频率示例') def throttled(self, request, wait): """ If request is throttled, determine what kind of exception to raise. """ class MyThrottled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = 'Expected available in {wait} second.' extra_detail_plural = '还需要再等待{wait}' raise MyThrottled(wait)
认证、权限+访问控制的实现
from django.conf.urls import url from django.contrib import admin from app04 import views as app04_view urlpatterns = [ url(r'^index/', app04_view.IndexView.as_view()), url(r'^manage/', app04_view.ManageView.as_view()), ]
setting配置
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ #认证控制 # "app02.utils.MyAuthentication", ], 'DEFAULT_PERMISSION_CLASSES':[ #权限控制 ], 'DEFAULT_THROTTLE_RATES':{ 'wdp_anon':'5/minute', #匿名用户配置 'wdp_user':'10/minute', #正常用户配置 } } CACHES = { #缓存配置 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': 'cache', } }
CBV视图
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import BaseThrottle,SimpleRateThrottle from rest_framework.authentication import BaseAuthentication from app02 import models class MyAuthentication(BaseAuthentication): """ 用户认证类,获取url传过来的数据 """ def authenticate(self, request): token = request.query_params.get('token') obj = models.UserInfo.objects.filter(token=token).first() if obj: return (obj.username,obj) return None def authenticate_header(self, request): pass class MyPermission(object): message = "无权访问" def has_permission(self,request,view): if request.user: return True return False class AdminPermission(object): message = "无权访问" def has_permission(self,request,view): if request.user == 'alex': return True return False class AnonThrottle(SimpleRateThrottle): """ 针对匿名用户的配置 """ scope = "wdp_anon" #配置文件中的值 def get_cache_key(self, request, view): # 返回None,表示我不限制 # 登录用户我不管 if request.user: #正常登陆的用户不做限制 return None # 匿名用户 #匿名用户做限制 return self.get_ident(request) class UserThrottle(SimpleRateThrottle): """ 针对已经登陆的用户所做的配置 """ scope = "wdp_user" #配置文件获取 def get_cache_key(self, request, view): # 登录用户 if request.user: return request.user # 匿名用户我不管 return None # 无需登录就可以访问 class IndexView(APIView): authentication_classes = [MyAuthentication,] #用户认证 permission_classes = [] #无需登陆就可以访问的页面不需要权限的控制 throttle_classes=[AnonThrottle,UserThrottle,] #限流 def get(self,request,*args,**kwargs): # self.dispatch return Response('无需登陆访问首页')
def throttled(self, request, wait):
"""自定义返回的文本信息"""
class MyThrottled(exceptions.Throttled):
default_detail = '请求被限制.'
extra_detail_singular = 'Expected available in {wait} second.'
extra_detail_plural = '还需要再等待{wait}'
raise MyThrottled(wait)
# 需登录就可以访问 class ManageView(APIView): authentication_classes = [MyAuthentication,] permission_classes = [MyPermission,] #需要登陆访问的页面做了权限的控制 throttle_classes=[AnonThrottle,UserThrottle,] def get(self,request,*args,**kwargs): # self.dispatch return Response('需要登陆访问首页')
5、版本限制
URL做版本限制
urlpatterns = [ url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')), ] urlpatterns = [ url(r'^users/', views.UsersView.as_view(),name='u'), ]
class UsersView(APIView): # 基于url传参 # versioning_class = QueryParameterVersioning get视图中直接采用request.version就可以取值 # 基于URL http://127.0.0.1:8001/api/v2/users/ # versioning_class = URLPathVersioning # 基于子域名 http://v1.luffy.com/users/ # versioning_class = HostNameVersioning #上边的这些配置是基于局部配置,用的更多的是全局的配置,所以只介绍全局配置
def get(self,request,*args,**kwargs): self.dispatch print(request.version) # QueryParameterVersioning().detemiin_version() print(request.versioning_scheme) # QueryParameterVersioning() # 当前版本一样的URL url = request.versioning_scheme.reverse(viewname='u',request=request) print(url) # 当前版本不一样的URL from django.urls import reverse url = reverse(viewname='u',kwargs={'version':'v2'}) print(url) return Response('...')
REST_FRAMEWORK = { 'VERSION_PARAM':'version', #固定的名字 'DEFAULT_VERSION':'v1', #默认版本号 'ALLOWED_VERSIONS':['v1','v2'], #可以使用的版本号 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning" #版本由url控制 }
hostname做版本控制
urlpatterns = [ url(r'^api/', include('api.urls')), ] urlpatterns = [ url(r'^users/', views.UsersView.as_view(),name='u'), ]
class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch print(request.version) # QueryParameterVersioning().detemiin_version() print(request.versioning_scheme) # QueryParameterVersioning()
REST_FRAMEWORK = { 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v1', 'ALLOWED_VERSIONS':['v1','v2'], 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning" #根据域名做版本控制 } 根据hostname做版本限制需要配置域名,这里我们直接修改电脑的host文件做测试(Windows系统的 C:WindowsSystem32driversetc;mac本或者Linux的在
# vim /etc/hosts) 直接做以下配置: 127.0.0.1 v1.qqq.com 127.0.0.1 v2.qqq.com
6、解析器
请求的数据进行解析:请求体进行解析。表示服务端可以解析的数据格式的种类。 Content-Type: application/url-encoding..... request.body request.POST Content-Type: application/json..... request.body request.POST 假如客户端发送的数据是: Content-Type: application/json '{"name":"alex","age":123}' 那么服务端接受的是: 读取客户端发送的Content-Type的值 application/json parser_classes = [JSONParser,] media_type_list = ['application/json',] 如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据 如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据
单视图: class UsersView(APIView): parser_classes = [JSONParser,] 全局配置: REST_FRAMEWORK = { 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v1', 'ALLOWED_VERSIONS':['v1','v2'], # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning" 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser', #解析jsonparser 'rest_framework.parsers.FormParser', #解析formparser ] }
7、序列化操作
#需要导入的包和模块 from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BasicAuthentication from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning,HostNameVersioning from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer from rest_framework.parsers import JSONParser,FormParser from rest_framework.request import Request from rest_framework import serializers from . import models #数据表
数据库表
from django.db import models # Create your models here. class Menu(models.Model): name = models.CharField(max_length=32) class Group(models.Model): title = models.CharField(max_length=32) mu = models.ForeignKey(to="Menu",default=1) class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) group = models.ForeignKey(to='Group') roles = models.ManyToManyField(to='Role') class Role(models.Model): name = models.CharField(max_length=32)
a、基本操作
class UsersSerializer(serializers.Serializer): name = serializers.CharField() pwd = serializers.CharField() class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 # user_list = models.UserInfo.objects.all() # ser = UsersSerializer(instance=user_list,many=True) # return Response(ser.data) # 方式二之单对象 user = models.UserInfo.objects.all().first() ser = UsersSerializer(instance=user, many=False) return Response(ser.data)
b、跨表操作
class UsersSerializer(serializers.Serializer): name = serializers.CharField() pwd = serializers.CharField() group_id = serializers.CharField() xxxx = serializers.CharField(source="group.title") x1 = serializers.CharField(source="group.mu.name") class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() ser = UsersSerializer(instance=user_list,many=True) return Response(ser.data)
c、复杂的序列化
操作一
class MyCharField(serializers.CharField): def to_representation(self, value): data_list = [] for row in value: data_list.append(row.name) return data_list class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source="group.title") # obj.group.title x1 = serializers.CharField(source="group.mu.name") # obj.mu.name # x2 = serializers.CharField(source="roles.all") # obj.mu.name x2 = MyCharField(source="roles.all") # obj.mu.name
操作二
class MyCharField(serializers.CharField): def to_representation(self, value): return {'id':value.pk, 'name':value.name} class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source="group.title") # obj.group.title x1 = serializers.CharField(source="group.mu.name") # obj.mu.name # x2 = serializers.CharField(source="roles.all") # obj.mu.name x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
操作三
class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source="group.title") # obj.group.title x1 = serializers.CharField(source="group.mu.name") # obj.mu.name # x2 = serializers.CharField(source="roles.all") # obj.mu.name # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name x2 = serializers.SerializerMethodField() def get_x2(self,obj): obj.roles.all() role_list = obj.roles.filter(id__gt=1) data_list = [] for row in role_list: data_list.append({'pk':row.pk,'name':row.name}) return data_list
以上三种方式都是使用相同的视图
class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() # [obj1,obj2,obj3] ser = UsersSerializer(instance=user_list,many=True) return Response(ser.data)
d、基于model
class UsersSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" # fields = ['name', 'pwd','group'] depth = 1 class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() # [obj1,obj2,obj3] ser = UsersSerializer(instance=user_list,many=True) return Response(ser.data)
e、生成url
class UsersSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='detail') class Meta: model = models.UserInfo fields = "__all__" fields = ['name', 'pwd','group'] depth = 1 class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() # [obj1,obj2,obj3] ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) return Response(ser.data)
f、全局生成url
class UsersSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = models.UserInfo fields = "__all__" # fields = ['id','name','pwd'] class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() # [obj1,obj2,obj3] ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) return Response(ser.data)
请求数据验证
方式一
class PasswordValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if value != self.base: message = '用户输入的值必须是 %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): """ This hook is called by the serializer instance, prior to the validation call being made. """ # 执行验证之前调用,serializer_fields是当前字段对象 pass class UsersSerializer(serializers.Serializer): name = serializers.CharField(min_length=6) pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
方式二
class PasswordValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if value != self.base: message = '用户输入的值必须是 %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): """ This hook is called by the serializer instance, prior to the validation call being made. """ # 执行验证之前调用,serializer_fields是当前字段对象 pass class UsersSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" extra_kwargs = { 'name': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]} }
使用:
class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects.all() # [obj1,obj2,obj3] ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) return Response(ser.data) def post(self,request,*args,**kwargs): ser = UsersSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('...')
8、分页
a、基于limitoffsetpagination做分页
class P1(LimitOffsetPagination): max_limit = 3 default_limit = 2 limit_query_param = 'limit' offset_query_param = 'offset'
b、基于PageNumberPagination做分页
class P2(PageNumberPagination): # 每页显示的数据条数 max_page_size = 5 page_size = 2 page_size_query_param = 'size' # 页码 page_query_param = 'page'
c、基于CursorPagination做分页
class P3(CursorPagination): cursor_query_param = 'cursor' page_size = 2 ordering = 'id'
需要用到的模块
from django.shortcuts import render from rest_framework import views from rest_framework.response import Response from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination,CursorPagination from api import models from api.serializers.index import IndexSerializer
基于视图实现
class IndexView(views.APIView): def get(self,request,*args,**kwargs): user_list = models.UserInfo.objects.all() #查询到所有的数据 p1 = P1() #实例化显示的那个对象 page_user_list = p1.paginate_queryset(queryset=user_list, request=request, view=self) #经过处理后的数据列表 ser = IndexSerializer(instance=page_user_list, many=True) return Response(ser.data) # 不含上一页和下一页 # return p1.get_paginated_response(ser.data) # 含上一页和下一页
基于视图使用对象的方式实现
class BaseResponse(object): def __init__(self,code=1000,data=None,error=None): self.code = code self.data = data self.error = error class IndexView(views.APIView): def get(self,request,*args,**kwargs): ret = BaseResponse() #基于对象的形式展示 try: user_list = models.UserInfo.objects.all() p1 = P1() page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self) ser = IndexSerializer(instance=page_user_list,many=True) ret.data = ser.data #给对象赋值 ret.next = p1.get_next_link() #上一页下一页链接 except Exception as e: ret.code= 1001 ret.error = 'xxxx错误' return Response(ret.__dict__) #以字典的形式返回
9、视图
1. APIView
class IndexView(views.APIView): def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all() ser = IndexSerializer(instance=user_list,many=True) return Response(ser.data)
2.GenericAPIView
class IndexView(generics.GenericAPIView): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2 def get(self,request,*args,**kwargs): user_list = self.get_queryset() p1 = self.paginator data = p1.paginate_queryset(queryset=user_list,request=request,view=self) ser = self.get_serializer(instance=data,many=True) return p1.get_paginated_response(ser.data)
3. GenericViewSet(ViewSetMixin, generics.GenericAPIView)
路由修改 urlpatterns = [ url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),] from rest_framework.viewsets import GenericViewSet class IndexView(GenericViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2 def list(self,request,*args,**kwargs): print("这里是list请求") return Response("...") def retrieve(self,request,*args,**kwargs): print("这里是post请求") return Response("...") def create(self,request,*args,**kwargs): print("这里是put请求") return Response("...") 自定义: 增 POST /users/ 删 DELETE /users/1/ 改 PUT /users/1/ patch /users/1/ 查 GET /users/ GET /users/1/ urlpatterns = [ url(r'^index/$', views.IndexView.as_view()), url(r'^index/(?P<pk>d+)$', views.IndexView.as_view({'get':'retrieve'})), ] class IndexView(views.APIView): def get(self,request,*args,**kwargs): pk = kwargs.get('pk') if pk: pass # 获取单条信息 else: pass # 获取列表信息 def post(self,request,*args,**kwargs): pass def put(self,request,*args,**kwargs): pass def patch(self,request,*args,**kwargs): pass def delete(self,request,*args,**kwargs): pass
4.ModelViewSet
ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet) 视图: urlpatterns = [ url(r'^user/$',views.IndexView.as_view({"get":"list","post":"create"})), url(r'^user/(?P<pk>d+)/$',views.IndexView.as_view({"get":"retrieve","delete":"destroy","put":"update","patch":"partial_update"})) ] from rest_framework.viewsets import ModelViewSet class IndexView(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2
10、路由和渲染器
第一类: # http://127.0.0.1:8000/api/v1/auth/ url(r'^auth/$', views.AuthView.as_view()), # http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式 url(r'^auth.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()), # http://127.0.0.1:8000/api/v1/auth/1/ url(r'^auth/(?P<pk>d+)/$', views.AuthView.as_view()), # http://127.0.0.1:8000/api/v1/auth/1.json url(r'^auth/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.AuthView.as_view()), class AuthView(views.APIView): def get(self,request,*args,**kwargs): return Response('...')
第二类: url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})), url(r'^index/.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})), url(r'^index/(?P<pk>d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), url(r'^index/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), class IndexView(viewsets.ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2
第三类: router = DefaultRouter() router.register('index',views.IndexViewSet) urlpatterns = [ url(r'^', include(router.urls)), ] class IndexViewSet(viewsets.ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2 class IndexSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__"
.渲染器 renderer_classes = [JSONRenderer,BrowsableAPIRenderer] #好看的页面默认返回的是这两个,如果只想返回json则 JSONRenderer
##
给query_set 新增一个扩展字段,并按照扩展字段进行排序(需要更新serializer,不需要更新model)
类继承顺序