版本
新建一个工程Myproject和一个名为api的app(这里使用的Django版本是1.11)
分别写下以下代码
1、api/models.py
from django.db import models class UserInfo(models.Model): USER_TYPE = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP') ) user_type = models.IntegerField(choices=USER_TYPE) username = models.CharField(max_length=32,unique=True) password = models.CharField(max_length=64) group = models.ForeignKey('UserGroup',on_delete=models.CASCADE) roles = models.ManyToManyField('Role') class UserToken(models.Model): user = models.OneToOneField('UserInfo',on_delete=models.CASCADE) token = models.CharField(max_length=64) class UserGroup(models.Model): title = models.CharField(max_length=32) class Role(models.Model): title = models.CharField(max_length=32)
2、Myproject/urls.py
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url('admin/', admin.site.urls), url('api/', include('api.urls')), ]
3、api/urls.py
from django.conf.urls import url, include from .views import UserView urlpatterns = [ url('users/', UserView.as_view()), ]
4、api/views.py
# api/views.py from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.request import Request from rest_framework.versioning import QueryParameterVersioning class UserView(APIView): versioning_class = QueryParameterVersioning def get(self,request,*args,**kwargs): #获取版本 print(request.version) return HttpResponse('用户列表')
5、settings.py
#版本 REST_FRAMEWORK = { "DEFAULT_VERSION":'v1', #默认的版本 "ALLOWED_VERSIONS":['v1','v2'], #允许的版本 "VERSION_PARAM":'version' #GET方式url中参数的名字 ?version=xxx }
同时我们是通过网页测试的,所以在settings中应该注册'rest_framework'
settings.py中找到对应的位置添加下面黄色部位
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' ]
上面就是这些代码下面是我们测试的结果,
1、url中通过GET传参
启动项目在网页中访问该网址:http://127.0.0.1:8000/api/users/?version=v2
网页显示用户列表,在Django的后台显示
可以看到获取到的版本号是V2
当我们在url中没有传参数版本就会显示默认版本如访问:http://127.0.0.1:8000/api/users/
这个在上面我们设置了它的默认版本是v1所以这里显示v1
当我们url传的版本不再setting设置的范围中就会报错
如:http://127.0.0.1:8000/api/users/?version=v3
2.在URLPATH中获取
通常情况我门应该用URLPATH的方式,而不是用前面GET()传参方式
url里面通过正则表达式定义哪些版本,
1、修改api/urls.py,这个里面获取版本也可以放在Myproject.py下面,看个人的喜好
from django.conf.urls import url, include from .views import UserView # 当我们不知道格式的时候可以去 # from rest_framework import versioning中去查看 # 进入到versioning中找到 class URLPathVersioning(BaseVersioning):的类里面就有教你如何使用 urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', UserView.as_view()), ]
2、api/views.py
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.request import Request from rest_framework.versioning import URLPathVersioning class UserView(APIView): versioning_class = URLPathVersioning def get(self,request,*args,**kwargs): #获取版本 print(request.version) return HttpResponse('用户列表')
这个URLPathVersioning我们可以放到settings里面,全局配置,就不用写到views里面,每个类都要写一遍了
settings.py
# 版本 # REST_FRAMEWORK = { # "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", # "DEFAULT_VERSION":'v1', #默认的版本 # "ALLOWED_VERSIONS":['v1','v2'], #允许的版本 # "VERSION_PARAM":'version' #get方式url中参数的名字 ?version=xxx # } #全局 REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", }
这个时候的api/views.py为
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.request import Request class UserView(APIView): def get(self,request,*args,**kwargs): #获取版本 print(request.version) return HttpResponse('用户列表')
浏览器访问:http://127.0.0.1:8000/api/v1/users/
反向解析访问的url
1、api/urls.py
from django.conf.urls import url, include from .views import UserView # 当我们不知道格式的时候可以去 # from rest_framework import versioning中去查看 # 进入到versioning中找到 class URLPathVersioning(BaseVersioning):的类里面就有教你如何使用 urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', UserView.as_view(), name='api_user'), ]
2、api/views.py
from django.shortcuts import render, HttpResponse from rest_framework.views import APIView from rest_framework.request import Request class UserView(APIView): def get(self, request, *args, **kwargs): # 获取版本 print('version', request.version) # 获取处理版本的对象 print('versioning_scheme', request.versioning_scheme) # 获取浏览器访问的url,reverse反向解析 # 需要两个参数:viewname就是url中的别名,request=request是url中要传入的参数 # (?P<version>[v1|v2]+)/users/,这里本来需要传version的参数,但是version包含在request里面(源码里面可以看到),所有只需要request=request就可以 url_path = request.versioning_scheme.reverse(viewname='api_user', request=request) print('url_path', url_path) # self.dispatch return HttpResponse('用户列表')
浏览器访问:http://127.0.0.1:8000/api/v1/users/
会看到以下结果:
上面的方法推荐使用URLPATH这种版本号。
解析器
1、api/urls.py
from django.conf.urls import url, include from .views import UserView,PaserView # 当我们不知道格式的时候可以去 # from rest_framework import versioning中去查看 # 进入到versioning中找到 class URLPathVersioning(BaseVersioning):的类里面就有教你如何使用 urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', UserView.as_view(), name='api_user'), url(r'paser/', PaserView.as_view(), ), # 解析 ]
2、api/views.py
from django.shortcuts import render, HttpResponse from rest_framework.views import APIView from rest_framework.request import Request class UserView(APIView): def get(self, request, *args, **kwargs): # 获取版本 print('version', request.version) # 获取处理版本的对象 print('versioning_scheme', request.versioning_scheme) # 获取浏览器访问的url,reverse反向解析 # 需要两个参数:viewname就是url中的别名,request=request是url中要传入的参数 # (?P<version>[v1|v2]+)/users/,这里本来需要传version的参数,但是version包含在request里面(源码里面可以看到),所有只需要request=request就可以 url_path = request.versioning_scheme.reverse(viewname='api_user', request=request) print('url_path', url_path) # self.dispatch return HttpResponse('用户列表') from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser class PaserView(APIView): parser_classes = [JSONParser, FormParser] # 一共有上面4种方式,但是常用的就是下面2种方式,同时默认的也是三种方式JSONParser, FormParser, MultiPartParser # 如何查看可以在APIView下找到api_settings里面的DEFAULTS里面可以看到默认的是三种。 # JSONParser:表示只能解析content-type:application/json的头 # FormParser:表示只能解析content-type:application/x-www-form-urlencoded的头 def post(self, request, *args, **kwargs): # 获取解析后的结果 print(request.data) return HttpResponse('paser')
如果全局使用某一个解析器的话在setting里面
#全局配置 REST_FRAMEWORK = { #版本 "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", #解析器 "DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FormParser"] }
上面我们实验要借助postman这个软件来完成测试
路由控制
在我们前面说到的序列化的最后一个版本(可以看关于restforamework的第一篇文章)
urls.py的代码如下所示
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/$', views.BookViewSet.as_view({"get": "list", "post": "create"}), name="book_list"), url(r'^books/(?P<pk>d+)$', views.BookViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }), name="book_detail"), ]
这个时候当我们有多个url的时候就要写多个这个时候就显得不是很智能所以这里使用了restframework的路由系统,这个系统就是针对上面的路由的
上面的urls.py改成如下
from django.conf.urls import url, include from rest_framework import routers from app01 import views router = routers.DefaultRouter() router.register('books', views.BookViewSet) urlpatterns = [ url(r'^',include(route.urls)), url(r'^(?P<version>[v1|v2]+)/users/$', UserView.as_view(), name='api_user'), ]
上面就会帮我们生成开始的两条url外还会帮我们生成一下2条url,一共有四条
^books.(?P<format>[a-z0-9]+)/?$ [name='books-list'] ^books/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='books-detail']
上面的第一个url对应下面的访问
我们访问http://127.0.0.1:8000/books/?format=josn或者http://127.0.0.1:8000/books.json
他返回的是一个json数据想要什么数据就在后面写上前提是他要支持这个数据。
上面的第二个url
我们访问http://127.0.0.1:8000/book/1/?format=josn或者http://127.0.0.1:8000/1/books.json
理解和上面是一样的。
分页
基本使用
1、urls.py
from django.conf.urls import url, include from .views import Pager1View urlpatterns = [ url(r'(?P<version>[v1|v2]+)/page1/', Pager1View.as_view(),) #分页1 ]
2、api/utils/serializers/pager.py
from rest_framework import serializers from api import models class PagerSerialiser(serializers.ModelSerializer): class Meta: model = models.Role fields = "__all__"
3、api/views.py
from api.utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from api import models class Pager1View(APIView): def get(self, request, *args, **kwargs): # 获取所有数据 roles = models.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)
4、settings配置
REST_FRAMEWORK = { # 分页 "PAGE_SIZE": 2 # 每页显示多少个 }
在数据库里面添加几条数据
访问:http://127.0.0.1:8000/api/v1/page1/?page=2
自定义分页类
from api.utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from api import models # 自定义分页类 class MyPageNumberPagination(PageNumberPagination): # 每页显示多少个 page_size = 3 # 默认每页显示3个,可以通过传入pager1/?page=2&size=4,改变默认每页显示的个数 page_size_query_param = "size" # 最大页数不超过10 max_page_size = 10 # 获取页码数的 page_query_param = "page" class Pager1View(APIView): def get(self, request, *args, **kwargs): # 获取所有数据 roles = models.Role.objects.all() # 创建分页对象,这里是自定义的MyPageNumberPagination pg = MyPageNumberPagination() # 获取分页的数据 page_roles = pg.paginate_queryset(queryset=roles, request=request, view=self) # 对数据进行序列化 ser = PagerSerialiser(instance=page_roles, many=True) return Response(ser.data)
访问:http://127.0.0.1:8000/api/v1/page1/?page=1&size=2
上面我们默认是显示三个数据但是我在访问的时候自己设置为2个所以页面显示的是2个数据
第二种分页 LimitOffsetPagination
from api.utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response from rest_framework.pagination import LimitOffsetPagination from rest_framework.views import APIView from api import models # 自定义分页类 class MyLimitOffsetPagination(LimitOffsetPagination): # 默认显示的个数 default_limit = 2 # 当前的位置 offset_query_param = "offset" # 通过limit改变默认显示的个数 limit_query_param = "limit" # 一页最多显示的个数 max_limit = 10 class Pager1View(APIView): def get(self, request, *args, **kwargs): # 获取所有数据 roles = models.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)
访问:http://127.0.0.1:8000/api/v1/page1/?offset=1&limit=1
我们在返回的时候可以使用get_paginated_response方法这样就会得到上一页和下一页的url
访问:http://127.0.0.1:8000/api/v1/page1/?limit=1&ofset=1
这个适用于上面2种分页方式
第三种分页 CursorPagination
加密分页方式,只能通过点“上一页”和下一页访问数据
from api.utils.serializsers.pager import PagerSerialiser from rest_framework.response import Response from rest_framework.pagination import CursorPagination from rest_framework.views import APIView from api import models # 自定义分页类 class MyCursorPagination(CursorPagination): cursor_query_param = "cursor" page_size = 2 #每页显示2个数据 ordering = 'id' #排序 page_size_query_param = None max_page_size = None class Pager1View(APIView): def get(self,request,*args,**kwargs): #获取所有数据 roles = models.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)
我们访问:http://127.0.0.1:8000/api/v1/page1/
点击红色部位会看到如下部分。
我们可以看到现在只能点击上一页不能够点击下一页。因为数据只有2页。
我们直接输入:http://127.0.0.1:8000/api/v1/page1/?cursor=2
会出现上面的错误提示因为该分页使用的是加密。
如果我们使用的序列化是最终极版本的如:
from rest_framework import viewsets from app01.models import * from app01.utils.serializers import * class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() # BookModelSerializers和前面的一样没什么变化功能类似于modelform serializer_class = BookModelSerializers
如何使用分页只需要在代码中添加:
from rest_framework import viewsets from app01.models import * from app01.utils.serializers import * from rest_framework.pagination import CursorPagination class MyCursorPagination(CursorPagination): cursor_query_param = "cursor" page_size = 2 # 每页显示2个数据 ordering = 'id' # 排序 page_size_query_param = None max_page_size = None class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() # BookModelSerializers和前面的一样没什么变化功能类似于modelform serializer_class = BookModelSerializers pagination_class = MyCursorPagination
上面的 MyCursorPagination就是我们自定义的分页组件。