什么是restful
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
- 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
- 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
什么是API
1、什么是API?
答:API就是接口,提供的url。接口有两个用途:
- - 为别人提供服务
- - 前后端分离,一个写vue,一个写后端,他们之间都是通过ajax请求
restful API设计规范
- API与用户的通信协议,总是使用HTTPS协议。
- 域名
- https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
- https://example.org/api/ API很简单
- 版本
- URL,如:https://api.example.com/v1/
- 请求头 跨域时,引发发送多次请求
- 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
- https://api.example.com/v1/employees
- method
- GET :从服务器取出资源(一项或多项)
- POST :在服务器新建一个资源
- PUT :在服务器更新资源(客户端提供改变后的完整资源)
- PATCH :在服务器更新资源(客户端提供改变的属性)
- DELETE :从服务器删除资源
- 过滤,通过在url上传参的形式传递搜索条件
- https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
- https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
- https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
- https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
- https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
- 状态码
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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
- 错误处理,状态码是4xx时,应返回错误信息,error当做key。
{ error: "Invalid API key" }
- 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档
- Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
基于Django实现restful api
参考博客:https://www.cnblogs.com/wusir66/p/10016584.html
基于Django Rest Framework框架实现
PS:以下介绍的使用方式都是一些常用的,还有一些方式使用较少,在此不做介绍。
一、自定义用户认证
在models.py的UserInfo表中创建一些数据
from django.db import models class UserInfo(models.Model): user_type_choices = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32,unique=True) password = models.CharField(max_length=64) class UserToken(models.Model): user = models.OneToOneField(to='UserInfo') token = models.CharField(max_length=64)
from django.http import JsonResponse from rest_framework.views import APIView from app.models import * import hashlib import time #创建token字符串 def md5(user): ctime = str(time.time()) m = hashlib.md5(bytes(user,encoding='utf-8')) m.update(bytes(ctime,encoding='utf-8')) return m.hexdigest() #找到指定用户给其token值 class AuthView(APIView): authentication_classes = [] def post(self,request,*args,**kwargs): ret = {'code':1000,'msg':None} try: name = request._request.POST.get('username') pwd = request._request.POST.get('password') obj = UserInfo.objects.filter(username=name,password=pwd).first() if not obj: ret['code'] = 1001 ret['msg'] = '用户名或密码错误' token = md5(name) 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) #利用token值来进行认证 class OrderView(APIView): def get(self,request,*args,**kwargs): ret = {'code':1000,'msg':None,'data':None} order = {'goods':'food'} try: ret['data'] = order except Exception as e: ret['msg'] = '有问题' return JsonResponse(ret)
在app目录下创建一个rest_utils的文件夹
from rest_framework.authentication import BaseAuthentication from app.models import * from rest_framework import exceptions class MyAuthentication(BaseAuthentication): def authenticate(self, request): token = request._request.GET.get('token') obj = UserToken.objects.filter(token=token).first() if not obj: raise exceptions.AuthenticationFailed('用户未认证') return (obj.user,obj) def authenticate_header(self, request): pass
配置文件
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES':['app.rest_utils.auth.MyAuthentication',], }
如果有某些类不需要使用认证,可以在类中加上以下代码
authentication_classes = []
源码大致流程
def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs 第一步:对request进行加工(添加数据) request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: #第二步: #处理版权信息 #认证 #权限 #请求用户进行访问频率的限制 self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed # 第三步、执行:get/post/put/delete函数 response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) #第四步、 对返回结果再次进行加工 self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
源码具体流程
请求来了先走dispatch方法做分发
1、对request进行加工(添加数据)
a、首先 request = self.initialize_request(request, *args, **kwargs)点进去,会发现:在Request里面多加了四个,如下
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ #把请求弄成一个字典返回 parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), #解析数据,默认的有三种方式,可点进去看 #self.get_authenticator优先找自己的,没有就找父类的 authenticators=self.get_authenticators(), #获取认证相关的所有类并实例化,传入request对象供Request使用 negotiator=self.get_content_negotiator(), parser_context=parser_context )
b、获取认证相关的类的具体 authenticators=self.get_authenticators()
def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ #返回的是对象列表 return [auth() for auth in self.authentication_classes] #[SessionAuthentication,BaseAuthentication]
c、查看认证的类:self.authentication_classes
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #默认的,如果自己有会优先执行自己的
d、接着走进api_settings
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) #点击继承的DEFAULTS类 DEFAULTS类 DEFAULTS = { # Base API policies 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', #这时候就找到了他默认认证的类了,可以导入看看 'rest_framework.authentication.BasicAuthentication' ),
e、导入了类看看类里面具体干了什么
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import BaseAuthentication
f、看到里面有个authenticate方法和authenticate_header方法
class BaseAuthentication(object): """ All authentication classes should extend BaseAuthentication. """ def authenticate(self, request): """ Authenticate the request and return a two-tuple of (user, token). """ raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass
具体处理认证,从headers里面能获取用户名和密码
class BasicAuthentication(BaseAuthentication): """ HTTP Basic authentication against username/password. """ www_authenticate_realm = 'api' def authenticate(self, request): """ Returns a `User` if a correct username and password have been supplied using HTTP Basic authentication. Otherwise returns `None`. """ auth = get_authorization_header(request).split() if not auth or auth[0].lower() != b'basic': return None #返回none不处理。让下一个处理 if len(auth) == 1: msg = _('Invalid basic header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: msg = _('Invalid basic header. Credentials string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') #用partition切割冒号也包括 except (TypeError, UnicodeDecodeError, binascii.Error): msg = _('Invalid basic header. Credentials not correctly base64 encoded.') raise exceptions.AuthenticationFailed(msg) userid, password = auth_parts[0], auth_parts[2] # 返回用户和密码 return self.authenticate_credentials(userid, password, request) def authenticate_credentials(self, userid, password, request=None): """ Authenticate the userid and password against username and password with optional request for context. """ credentials = { get_user_model().USERNAME_FIELD: userid, 'password': password } user = authenticate(request=request, **credentials) if user is None: raise exceptions.AuthenticationFailed(_('Invalid username/password.')) if not user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (user, None) def authenticate_header(self, request): return 'Basic realm="%s"' % self.www_authenticate_realm
g、当然restfulframework默认定义了两个类。我们也可以自定制类,自己有就用自己的了,自己没有就去找父类的了,但是里面必须实现authenticate方法,不然会报错。
2、加工完request之后的操作
- 处理版权信息
- 认证
- 权限
- 请求用户进行访问频率的限制
认证流程
a、首先 self.initial(request, *args, **kwargs)可以看到做了以下操作
def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """ self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use. #2.1 处理版本信息 version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted #2.2 认证 self.perform_authentication(request) # 2.3 权限 self.check_permissions(request) # 2.4 请求用户进行访问频率的限制 self.check_throttles(request)
b、我们先来看认证,self.perform_authentication(request) 具体干了什么,按住ctrl点击进去
def perform_authentication(self, request): """ Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication will instead be performed lazily, the first time either `request.user` or `request.auth` is accessed. """ request.user #执行request的user,这是的request已经是加工后的request了
c、那么我们可以从视图里面导入一下Request,找到request对象的user方法
from rest_framework.views import Request
@property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() # return self._user #返回user
d、执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ #循环对象列表 for authenticator in self.authenticators: try: #执行每一个对象的authenticate 方法 user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple #返回一个元组,user,和auth,赋给了self, # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了 return self._not_authenticated()
e、在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法
f、如果用户没有认证成功:self._not_authenticated()
def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None. """ #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None # if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser else: self.user = None # None 表示跳过该认证 if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() # 默认值为:None else: self.auth = None # (user, token) # 表示验证通过并设置用户名和Token; # AuthenticationFailed异常
3、执行get/post/delete等方法
4、对返回结果在进行加工
二、自定义权限
在app目录下创建一个rest_utils的文件夹
from rest_framework.permissions import BasePermission class MyPermission(BasePermission): message = '必须是svip才能访问' def has_permission(self,request,view): if request.user.user_type != 3: return False return True
配置文件
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ['app.rest_utils.permission.MyPermission', ], }
如果有某些类不需要使用权限,可以在类中加上以下代码
permission_classes = []
三、自定义节流
在app目录下创建一个rest_utils的文件夹
from rest_framework.throttling import BaseThrottle import time VISIT_RECORD = {} class VisitThrottle(BaseThrottle): def __init__(self): self.history = None def allow_request(self,request,view): # 1. 获取用户IP remote_addr = self.get_ident(request) 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): # 还需要等多少秒才能访问 ctime = time.time() return 60 - (ctime - self.history[-1])
配置文件
REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES": ["app.rest_utils.throttle.VisitThrottle"], }
如果有某些类不需要使用节流,可以在类中加上以下代码
throttle_classes = []
四、版本
配置文件
REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', }
路由
from django.conf.urls import url from app.views import * urlpatterns = [ url('^(?P<version>[v1|v2]+)/orderview/$',OrderView.as_view(),name='wusir'), ]
视图
from django.http import JsonResponse from rest_framework.views import APIView from app.models import * import hashlib import time def md5(user): ctime = str(time.time()) m = hashlib.md5(bytes(user,encoding='utf-8')) m.update(bytes(ctime,encoding='utf-8')) return m.hexdigest() class AuthView(APIView): authentication_classes = [] permission_classes = [] def post(self,request,*args,**kwargs): ret = {'code':1000,'msg':None} try: name = request._request.POST.get('username') pwd = request._request.POST.get('password') obj = UserInfo.objects.filter(username=name,password=pwd).first() if not obj: ret['code'] = 1001 ret['msg'] = '用户名或密码错误' token = md5(name) 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) class OrderView(APIView): def get(self,request,*args,**kwargs): ret = {'code':1000,'msg':None,'data':None} order = {'goods':'food'} # 获得版本信息 print(request.version) # 获取处理版本的对象 print(request.versioning_scheme) #反向生成url(rest_framework) u1 = request.versioning_scheme.reverse(viewname='wusir',request=request) print(u1) try: ret['data'] = order except Exception as e: ret['msg'] = '有问题' return JsonResponse(ret)
五、解析器
配置文件
REST_FRAMEWORK = { "DEFAULT_PARSER_CLASSES": ['rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser'] }
视图函数中可以直接通过request.data拿到解析之后的数据
六、序列化
序列化共有两个功能:1、数据序列化 2、请求数据校验
数据序列化
from django.db import models class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): user_type_choices = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32,unique=True) password = models.CharField(max_length=64) group = models.ForeignKey("UserGroup") roles = models.ManyToManyField("Role") class UserToken(models.Model): user = models.OneToOneField(to='UserInfo') token = models.CharField(max_length=64) class Role(models.Model): title = models.CharField(max_length=32)
import json from rest_framework.views import APIView from django.http import HttpResponse from rest_framework import serializers from app.models import * #========================================= # 自定义序列化类一 class RolesSerializers(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField() class RoleViews(APIView): def get(self,request,*args,**kwargs): # 方式一 ,没有使用数据序列化 res = Role.objects.all().values('title') res = list(res) res = json.dumps(res,ensure_ascii=False) # 方式二 ,序列化多个数据[obj,obj,obj] res = Role.objects.all() ser = RolesSerializers(instance=res,many=True) res = json.dumps(ser.data,ensure_ascii=False) # 方式三 ,序列化单个数据 [obj] res = Role.objects.all().first() ser = RolesSerializers(instance=res,many=False) res = json.dumps(ser.data,ensure_ascii=False) return HttpResponse(res) # ========================================= # +++++++++++++++++++++++++++++++++++++++++ # 自定义序列化类二 class UserInfoSerializers(serializers.Serializer): # user_type = serializers.IntegerField() aaaaa = serializers.IntegerField(source='user_type') bbbbb = serializers.CharField(source='get_user_type_display') username = serializers.CharField() password = serializers.CharField() gps = serializers.CharField(source='group.id') # rls = serializers.CharField(source='roles.all') # 用这个拿到的是一个一个的对象 rls = serializers.SerializerMethodField() # 自定义显示 def get_rls(self,row): obj_list = row.roles.all() ret = [] for i in obj_list: ret.append({'id':i.id,'title':i.title}) return ret # 自定义序列化类三 class UserInfoSerializers(serializers.ModelSerializer): bbbbb = serializers.CharField(source='get_user_type_display') group = serializers.CharField(source='group.title') rls = serializers.SerializerMethodField() def get_rls(self,row): obj_list = row.roles.all() ret = [] for i in obj_list: ret.append({'id':i.id,'title':i.title}) return ret class Meta: model = UserInfo # fields = '__all__' fields = ['id','username','password','bbbbb','group','rls'] # 自定义序列化类四(深度化控制) class UserInfoSerializers(serializers.ModelSerializer): class Meta: model = UserInfo # fields = '__all__' fields = ['id','username','password','user_type','group','roles'] depth = 1 # 自定义序列化类五(Hypermedia API) class UserInfoSerializers(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='wusir',lookup_field='group_id',lookup_url_kwarg='pk') class Meta: model = UserInfo # fields = '__all__' fields = ['id','username','password','user_type','group','roles'] class UserInfoViews(APIView): def get(self,request,*args,**kwargs): users = UserInfo.objects.all() ser = UserInfoSerializers(instance=users,many=True,context={'request':request}) res = json.dumps(ser.data,ensure_ascii=False) return HttpResponse(res) # GroupSerializers和GroupViews配合自定义序列化类五生成Hypermedia API后,点击url可以看详情 class GroupSerializers(serializers.ModelSerializer): class Meta: model = UserGroup fields = '__all__' class GroupViews(APIView): def get(self,request,*args,**kwargs): pk = kwargs.get('pk') res = UserGroup.objects.filter(id=pk).first() ser = GroupSerializers(instance=res,many=False) res = json.dumps(ser.data,ensure_ascii=False) return HttpResponse(res) # +++++++++++++++++++++++++++++++++++++++++
from django.conf.urls import url from app.views import * urlpatterns = [ url('role/$',RoleViews.as_view()), url('info/$',UserInfoViews.as_view()), url('group/(?P<pk>\d+)$',GroupViews.as_view(),name='wusir'), ]
请求数据校验
class XXValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if not value.startswith(self.base): message = '标题必须以 %s 为开头。' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): pass class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required': '标题不能为空'},validators=[XXValidator('wusir'),]) # required为错误时的提示信息,validators为自定义验证器,可以自定义功能,也可以不写,不写的话只能校验数据是否为空 class UserGroupView(APIView): def post(self, request, *args, **kwargs): ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data['title']) else: print(ser.errors) return HttpResponse('提交数据')
from django.conf.urls import url from app.views import * urlpatterns = [ url('usergroup/$',UserGroupView.as_view()), ]
七、分页
PS:先自定义一个序列化,然后在分页程序中导入这个序列化程序,所有的原生分页需要现在settings.py中定义一下每页显示几条数据
REST_FRAMEWORK = { "PAGE_SIZE":2, }
A1、分页,看第n页,每页显示n条数据(原生)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = PageNumberPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
A2、分页,看第n页,每页显示n条数据(自定义)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class MyPageNumberPagination(PageNumberPagination): page_size = 3 #默认每页显示个数 page_query_param = 'page' #get传参表示第几页 page_size_query_param = 'pagesize' #get传参表示每页显示几个 max_page_size = 5 #每页最大显示个数 class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = MyPageNumberPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
B1. 分页,在n个位置,向后查看n条数据(原生)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import LimitOffsetPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = LimitOffsetPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
B2. 分页,在n个位置,向后查看n条数据(自定义)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import LimitOffsetPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class MyLimitOffsetPagination(LimitOffsetPagination): default_limit = 3 #默认每页显示个数 limit_query_param = 'limit' #get传参表示每页显示个数 offset_query_param = 'offset' #get传参表示跳过几个数据显示 max_limit = 6 #每页最大显示个数 class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = MyLimitOffsetPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
C1.加密分页,上一页和下一页(原生)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import CursorPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = CursorPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
C2.加密分页,上一页和下一页(自定义)
from django.http import JsonResponse, HttpResponse from rest_framework.pagination import CursorPagination from rest_framework.views import APIView from app.models import * import hashlib import time from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response class MyCursorPagination(CursorPagination): cursor_query_param = 'wusir' #get参数中确定以什么值为key来接受下一页的参数 page_size = 3 #默认每页显示数目 ordering = 'id' #根据什么字段来进行排序 page_size_query_param = 'pagesize' #get传参表示每页显示几个 max_page_size = 5 #每页最大显示数目 class PageView(APIView): authentication_classes = [] permission_classes = [] throttle_classes = [] def get(self,request,*args,**kwargs): roles = Role.objects.all() pg = MyCursorPagination() page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self) ser = PagerSerialiser(instance=page_roles,many=True) # return Response(ser.data) return pg.get_paginated_response(ser.data) #页面上加上上下页的url
八、视图
PS:View和APIView在此处就不多介绍
GenericAPIView
from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from app.models import * from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response from rest_framework.generics import GenericAPIView class View1View(GenericAPIView): authentication_classes = [] permission_classes = [] throttle_classes = [] queryset = Role.objects.all() serializer_class = PagerSerialiser pagination_class = PageNumberPagination def get(self,request,*args,**kwargs): # 获取数据 roles = self.get_queryset() # 分页 pager_roles = self.paginate_queryset(roles) # 序列化 ser = self.get_serializer(instance=pager_roles,many=True) return Response(ser.data)
GenericViewSet(as_view里面可以用字典的方式让get,post等不同的方法对应执行不同名称的函数)
from rest_framework.pagination import PageNumberPagination from app.models import * from rest_framework.response import Response from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.viewsets import GenericViewSet class View1View(GenericViewSet): authentication_classes = [] permission_classes = [] throttle_classes = [] queryset = Role.objects.all() serializer_class = PagerSerialiser pagination_class = PageNumberPagination def list(self, request, *args, **kwargs): # 获取数据 roles = self.get_queryset() # 分页 pager_roles = self.paginate_queryset(roles) # 序列化 ser = self.get_serializer(instance=pager_roles, many=True) return Response(ser.data)
from django.conf.urls import url from app.views import * urlpatterns = [ url(r'^view1view/$',View1View.as_view({'get':'list'})), ]
mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,
(任意举两个栗子)
from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.viewsets import GenericViewSet,ModelViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin class View1View(GenericViewSet,ListModelMixin,CreateModelMixin): authentication_classes = [] permission_classes = [] throttle_classes = [] queryset = Role.objects.all() serializer_class = PagerSerialiser pagination_class = PageNumberPagination
from django.conf.urls import url from app.views import * urlpatterns = [ url(r'^view1view/$',View1View.as_view({'get':'list','post':'create'})), ]
ModelViewSet
from app.rest_utils.serializsers.pager import PagerSerialiser from rest_framework.viewsets import ModelViewSet class View1View(ModelViewSet): authentication_classes = [] permission_classes = [] throttle_classes = [] queryset = Role.objects.all() serializer_class = PagerSerialiser pagination_class = PageNumberPagination
from django.conf.urls import url from app.views import * urlpatterns = [ url(r'^view1view/$',View1View.as_view({'get': 'list','post':'create'})), url(r'^view1view/(?P<pk>\d+)/$',View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), ]
继承关系:APIView继承了View,GenericAPIView继承了APIView,GenericViewSet继承了GenericAPIView和ViewSetMixin,ModelViewSet继承了mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin和GenericViewSet。
九、路由系统
当继承了ModelViewSet之后,一个视图对于的完整的路由就有以下四种
from django.conf.urls import url from app.views import * urlpatterns = [ # http://127.0.0.1:8000/api/v1/v1/?format=json url(r'^(?P<version>[v1|v2]+)/view1view/$', View1View.as_view({'get': 'list','post':'create'})), # http://127.0.0.1:8000/api/v1/v1.json url(r'^(?P<version>[v1|v2]+)/view1view\.(?P<format>\w+)$', View1View.as_view({'get': 'list','post':'create'})), url(r'^(?P<version>[v1|v2]+)/view1view/(?P<pk>\d+)/$', View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), url(r'^(?P<version>[v1|v2]+)/view1view/(?P<pk>\d+)\.(?P<format>\w+)$', View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), ]
这时候我们可以使用rest_framework给我们自动生成路由的方式来生成以上四种路由,效果相同
from django.conf.urls import url, include from app.views import * from rest_framework import routers router = routers.DefaultRouter() router.register(r'view1view',View1View) urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/', include(router.urls)), ]
十、渲染器
只需要在配置文件中配置一下所需要的渲染器类型就可以了
REST_FRAMEWORK = { "DEFAULT_RENDERER_CLASSES":[ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ] }