• 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就是我们自定义的分页组件。

  • 相关阅读:
    面试题之发散思维能力:如何用非常规方法求1+2+···+n
    优秀Python学习资源收集汇总(强烈推荐)
    JavaScript简洁继承机制实现(不使用prototype和new)
    JsRender for index 循环索引使用说明
    JsRender for object 语法说明
    pasteimg浏览器中粘贴图片jQuery插件
    西安电子科技大学泄漏信息
    移动端二维码弹出框,自适应屏幕尺寸
    服务器端json数据文件分割合并解决方案
    html中a标签href属性的一个坑
  • 原文地址:https://www.cnblogs.com/yang-China/p/9816292.html
Copyright © 2020-2023  润新知