Django rest-framework后续

版本

新建一个工程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)
api/models.py

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')),
]
Myproject/urls.py

3、api/urls.py

from django.conf.urls import url, include
from .views import UserView

urlpatterns = [
    url('users/', UserView.as_view()),
]
api/urls.py

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('用户列表')
api/views.py

5、settings.py

#版本
REST_FRAMEWORK = {
    "DEFAULT_VERSION":'v1',               #默认的版本
    "ALLOWED_VERSIONS":['v1','v2'],       #允许的版本
    "VERSION_PARAM":'version'             #GET方式url中参数的名字  ?version=xxx
}
settings.py

同时我们是通过网页测试的,所以在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()),
]
api/urls.py

 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('用户列表')
api/views.py

这个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",
}
settings.py

 这个时候的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('用户列表')
api/views.py

浏览器访问: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'),
]
api/urls.py

 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('用户列表')
api/views.py

浏览器访问: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(), ),  # 解析
]
api/urls.py

 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')
api/views.py

如果全局使用某一个解析器的话在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"),
]
View Code

这个时候当我们有多个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'),
]
View Code

 上面就会帮我们生成开始的两条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就是我们自定义的分页组件。

原文地址:https://www.cnblogs.com/yang-China/p/9816292.html