python Django 之 DRF(四)分页、视图、路由、渲染器的使用

一、rest framework分页的使用

通过上篇文章中我们讲到的序列化操作后。如果想让它通过在请求上传参数的形式给后台、后台获取到参数通过数据库limit的方式获取数据,这种方法是可以实现的。

1.PageNumberPagination类的使用

如果不想通过自己写的方法来实现分页,可以在rest framework框架中内置的PageNumberPagination类实现,该类中有多个对象需要传递,如下:

  • page_size:(每一页显示多少条数据,可在settings配置中设置或自己自动配置)
  • page_size_query_param:通过在路由上传递数据来让每一页显示多少条数据(默认为None)
  • max_page_size:最大显示多少个数据(默认为None)
  • page_query_param:通过什么数据翻页(默认通过?page=页码进行翻页)

此时设置settings配置文件,将其设置为每一页显示2条数据,并配置上rest framework。

settings如下:

# 配置上rest framework。
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',
]

REST_FRAMEWORK = {
    "DEFAULT_VERSION": 'v1',
    "ALLOWED_VERSIONS": ['v1', 'v2'],
    "VERSION_PARAM": 'version',
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "PAGE_SIZE": 2,
}

urls.py如下:

from django.urls import path, re_path
from api import views

urlpatterns = [
    re_path(r'api/(?P<version>[v1|v2]+)/pager1/$', views.Pager1View.as_view()),
]

views.py如下:

from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination


class PagerSerialiser(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class MyPagination(PageNumberPagination):
    page_size = 2
    # 默认显示多少个数据
    page_size_query_param = 'size'
    # 最大显示多少个数据
    max_page_size = 4

    page_query_param = 'page'



class Pager1View(APIView):
    def get(self, request, *args, **kwargs):
        # 获取数据库数据
        roles = models.Role.objects.all()
        # 实例化分页操作
        pg = MyPagination()
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        # 序列化操作
        ser = PagerSerialiser(instance=pager_roles, many=True)

        return Response(ser.data)

可以看到,此时我们定义了三个类,每个类都有不同的分工,通过序列化获取Role表的所有对象、以及继承于PageNumberPagination类的子类,重写该父类类方法、和访问接口路由,实例化分页、在将其序列化并返回给ser,之后在调用data函数解析数据并返回通过rest framework框架内置的Response方法将其转换成rest framework的好看界面、以及帮我们转为json格式


此时访问http://127.0.0.1:8000/api/v1/pager1/如下:
在这里插入图片描述

可以看到通过?page=页数(默认),是可以分页访问的,且如果想在后面加其他限制可通过&size=页数重写每页数据(在MyPagination类中重写了page_size_query_param=“size”、使其生效),也可以通过MyPagination类显示了最大显示数据值。

如果返回的参数为PageNumberPagination类中的get_paginated_response函数,那么返回的结果就会显示上一条和下一条的路由(没有数据了则显示NULL)。

views.py/Pager1View类如下:

class Pager1View(APIView):
    def get(self, request, *args, **kwargs):
        # 获取数据库数据
        roles = models.Role.objects.all()
        # 实例化分页操作
        pg = MyPagination()
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        # 序列化操作
        ser = PagerSerialiser(instance=pager_roles, many=True)

        return pg.get_paginated_response(ser.data)

此时访问http://127.0.0.1:8000/api/v1/pager1/如下:
在这里插入图片描述
可以看到上一条和下一条的路由也被放入到数据中了(实际用哪个返回根据需求做决定)。



2.LimitOffsetPagination类的使用

对于rest framework框架中还有另一个内置的LimitOffsetPagination类,该类中有多个对象需要传递,如下:

  • offset_query_param:表示索引位置(从0开始索引,默认使用offset做key
  • limit_query_param:表示每索引一页时(数据显示多少条,没写用全局配置的两条,默认使用limit做key
  • max_limit:显示数据时(最大多少条每一页,默认为None
  • default_limit :默认每页显示多少条数据(没写从配置文件找)

views.py/MyPagination类如下:

from rest_framework.pagination import LimitOffsetPagination

class MyPagination(LimitOffsetPagination):
    default_limit = 2
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    max_limit = 4

此时访问http://127.0.0.1:8000/api/v1/pager1/如下:
在这里插入图片描述

显然和上面效果一样,不过是传递的参数不同,不过内部实现原理也是不相同的。

3.CursorPagination类的使用

对于rest framework框架中还有另一个内置的CursorPagination类,该类中将分页的数据加密了,具体的数据参数如下:

  • cursor_query_param:(翻页数据的key,默认为cursor
  • ordering:(通过数据中什么字段降序、升序
  • page_size_query_param:(自定义每页显示多少个,默认为None
  • max_page_size:(最大每页长度数据,默认为None
  • page_size:默认每页显示多少个数据(没有去配置文件获取

views.py/MyPagination类如下:

from rest_framework.pagination import CursorPagination

class MyPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2
    ordering = 'id'
    page_size_query_param = 'size'
    max_page_size = 4

此时访问http://127.0.0.1:8000/api/v1/pager1/如下:

在这里插入图片描述

可以看到,和上面的那些内置类相同,不过是多了对每页显示页数的页码进行了加密,且内部源码中是通过id的值进行索引判断的,所以不会造成当从一个很小的数跳到很大的数时,向数据库发送的索引范围会很大。

二、rest framework视图的使用

到现在为止,我们的视图一直继承着rest framework框架中的APIVIew,而APIVIew是继承于View的,那么在DRF框架中,还有内置帮我们实现好的类,并且该类继承于APIView。



1.GenericAPIView类的使用

GenericAPIView类继承于APIVIew,功能更多,可实现分页,序列化、数据获取,不过该方法的使用有好有坏:

  1. 优点:将全部方法整合在一块(视图上减少代码量,便于使用
  2. 缺点:不够灵活,且有很多复杂的功能不能实现

要想使用该类,需满足该类所需的参数传递如下:

  • queryset:数据库中获取值
  • serializer_class:序列化的类方法
  • pagination_class:分页中的类方法

urls.py如下:

from django.urls import path, re_path
from api import views

urlpatterns = [
    path('user/', views.UserInfoView.as_view()),
    re_path(r'user/(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupView.as_view(), name='gp'),
    re_path(r'user/(?P<version>[v1|v2]+)/group/$', views.UserGroupView.as_view()),
    re_path(r'api/(?P<version>[v1|v2]+)/pager1/$', views.Pager1View.as_view()),
    re_path(r'api/(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view()),
]

views.py如下:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
from rest_framework.generics import GenericAPIView


class PagerSerialiser(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"

class View1View(GenericAPIView):
    queryset = models.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)

此时我们可以看到,在传入serializer_class 、pagination_class的时候传的类无需传括号。

是因为在调用paginate_queryset、get_serializer函数的时候,内部会调用并获取相应的值、序列化操作。

此时访问http://127.0.0.1:8000/api/v1/v1/显示:
在这里插入图片描述

可以看到,通过这几步骤就将分页、序列化、解析的功能都给实现了。


2.GenericViewSet类的使用

仅仅的一些功能,对于现在的我们而言是根本不够的,此时DRF框架还有内置类供我们使用,而该方法为GenericViewSet类,继承于ViewSetMixin类(该类的调用方法重写了View方法中的as_view方法,使得后面继承类可以通过请求定义其他别名,且定义相应的函数)、GenericAPIView类。

且在使用了该类后,路由中的as_view方法就需要定义参数了,具体如下:

urls.py如下:

from django.urls import path, re_path
from api import views

urlpatterns = [
    path('user/', views.UserInfoView.as_view()),
    re_path(r'user/(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupView.as_view(), name='gp'),
    re_path(r'user/(?P<version>[v1|v2]+)/group/$', views.UserGroupView.as_view()),
    re_path(r'api/(?P<version>[v1|v2]+)/pager1/$', views.Pager1View.as_view()),
    re_path(r'api/(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list'})),
]

views.py/View1View函数如下:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
from rest_framework.generics import GenericViewSet


class PagerSerialiser(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"

class View1View(GenericViewSet):
    queryset = models.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)

可以发现通过GenericViewSet类继承的ViewSetMixin类中重写了as_view方法,且请求函数发生了改变(可以自定义函数名)。

此时访问http://127.0.0.1:8000/api/v1/v1/显示:
在这里插入图片描述

此时访问的结果和上述GenericAPIView类是一致的。



3.ModelViewSet类的使用

通过上面GenericViewSet类中,我们发现请求函数名发生了修改,那么为什么要修改?修改的作用是什么呢?

此时就要说到DRF框架中的ModelViewSet类了,该类继承的父类有很多,包括以GenericViewSet类开头等:

  • CreateModelMixin:(用于POST请求时数据添加到数据库)
  • RetrieveModelMixin:(通过GET请求获取URL上的id作为页码)
  • UpdateModelMixin:(用于PATCH、PUT修改参数后保存至数据库)
  • DestroyModelMixin:(用于DELETE请求时删除数据库中数据)
  • ListModelMixin:(通过GET请求获取参数为页码)

而这些内置类,我们若想使用,仅仅只需要通过配置url中的as_view方法即可。

urls.py如下:

from django.urls import path, re_path
from api import views

urlpatterns = [
    re_path(r'api/(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$',
            views.View1View.as_view({'get': 'retrieve', 'post': 'create', 'delete': 'destroy', 'put': 'update',
                                     'patch': 'partial_update'})),
]

可以看到,每一个请求函数都有相关内置封装的类。

views.py如下:

from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination

class PagerSerialiser(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"
        
class View1View(ModelViewSet):
    queryset = models.Role.objects.all()
    serializer_class = PagerSerialiser
    pagination_class = PageNumberPagination

此时访问http://127.0.0.1:8000/api/v1/v1/1/如下:
在这里插入图片描述

可以看到只需要几步骤就可以完成数据的增删改查了,在使用的过程中,我们可根据自身需求来自定义添加继承的对象。

三、rest framework路由的使用

通过上面的路由访问中,发现如果我们前端想获取到数据的时候不可能是以渲染成rest framework的形式返回过去,我们需要json格式,在前面测试的时候点击了一个format参数那时候路由后面添加了一个?format=json,此时格式就变为json了,这是第一种方法。

而还有一种方法是通过路由的形式来正则表达式,使其通过后缀.json即可获取到json格式数据。

urls.py如下:

from django.urls import path, re_path
from api import views

urlpatterns = [
    re_path(r'api/(?P<version>[v1|v2]+)/v1\.(?P<format>\w+)$',
            views.View1View.as_view({'get': 'list', 'post': 'create'})),
]

此时访问http://127.0.0.1:8000/api/v1/v1.json如下:
在这里插入图片描述

可以看到通过定义路由的方法使数据变成了json的格式。

可以看到如果一个视图展示、一个视图转换成json的格式,浪费路由,且代码还很多,而这个问题rest framework框架也帮我们想到了,使用的时候调用其routers类,将视图作为参数通过include导入即可。

urls.py如下:

from django.urls import path, re_path, include
from api import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'rt', views.View1View)

urlpatterns = [
    re_path(r'api/(?P<version>[v1|v2]+)/', include(router.urls)),
]

此时我们访问http://127.0.0.1:8000/api/v1/rt/如下:

在这里插入图片描述

可以看到该方法将我们所有的路由都整合起来了,此时的代码变得很十分的简洁、且json格式和rest framework视图随意切换、非常灵活。

四、rest framework渲染器的使用

根据前面的rest framework提供给我们的界面,我们在想这到底是通过什么来展示出来的呢?

其实是在我们继承APIVIew的同时调用了全局配置的renderer_classes,而参数为列表,默认将渲染好的界面,通过封装类、模板提供给我们展示了。

  • JSONRenderer:将数据以json格式化
  • BrowsableAPIRenderer:将数据展示美化
  • AdminRenderer:将数据展示列表美化(使用后通过?format=admin展示)

urls.py如下:

from django.urls import path, re_path, include
from api import views


urlpatterns = [
    path('user/', views.UserInfoView.as_view()),
]

views.py如下:

from django.shortcuts import render, HttpResponse
from rest_framework import serializers
from rest_framework.views import APIView
from api import models
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer, AdminRenderer

class UserInfoModelSerializer(serializers.ModelSerializer):
    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')

    class Meta:
        model = models.UserInfo
        fields = "__all__"
        # fields = ['id', 'username', 'password', 'group', 'roles']
        depth = 1

class UserInfoView(APIView):
    renderer_classes = [JSONRenderer, BrowsableAPIRenderer]

    def get(self, request, *args, **kwargs):
        users = models.UserInfo.objects.all()

        ser = UserInfoModelSerializer(instance=users, many=True, context={'request': request})

        return Response(ser.data)

此时访问http://127.0.0.1:8000/user/如下:
在这里插入图片描述
可以发现函数都被调用了,但是在一般情况下,我们只需要JSONRenderer, BrowsableAPIRenderer就够了,所以我们可以通过配置全局样式让它生效即可。

settings.py如下:

REST_FRAMEWORK = {
    "DEFAULT_VERSION": 'v1',
    "ALLOWED_VERSIONS": ['v1', 'v2'],
    "VERSION_PARAM": 'version',
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "PAGE_SIZE": 2,
    "DEFAULT_RENDERER_CLASSES": [
        "rest_framework.renderers.JSONRenderer",
        "rest_framework.renderers.BrowsableAPIRenderer"
    ]
}

此时全局的配置都应用上了,那么如果我们想自己改这个rest framework给我们的模板,我们可以通过查看BrowsableAPIRenderer类的源码,找到模板的位置并修改即可。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
好的,下面我会简单介绍如何使用 DjangoDjango REST frameworkDRF)来实现 CRUD 操作。CRUD 是指 Create(创建)、Read(读取)、Update(更新)和 Delete(删除),是开发 Web 应用程序时最基本的操作。 首先,你需要安装 DjangoDRF。你可以使用以下命令来安装: ``` pip install django pip install djangorestframework ``` 接下来,创建一个 Django 项目,并在项目中创建一个应用程序。你可以使用以下命令来创建: ``` django-admin startproject projectname cd projectname python manage.py startapp appname ``` 在应用程序的 `models.py` 文件中定义一个模型。例如,我们创建一个简单的 `Book` 模型: ```python from django.db import models class Book(models.Model): title = models.CharField(max_length=200) author = models.CharField(max_length=200) pub_date = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) ``` 然后,在应用程序的 `serializers.py` 文件中创建一个序列化器。序列化器用于将模型转换为 JSON 格式,以便在 API 中返回。以下是一个简单的 `BookSerializer`: ```python from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ['id', 'title', 'author', 'pub_date', 'price'] ``` 接下来,我们需要创建视图视图定义了 API 的行为。在 `views.py` 文件中,创建一个继承自 DRF 的 `ViewSet` 类的视图。以下是一个简单的 `BookViewSet`: ```python from rest_framework import viewsets from .models import Book from .serializers import BookSerializer class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer ``` 最后,我们需要将视图添加到路由中。在 `urls.py` 文件中,创建一个路由器,并将 `BookViewSet` 添加到路由器中。以下是一个简单的 `urls.py`: ```python from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import BookViewSet router = DefaultRouter() router.register(r'books', BookViewSet) urlpatterns = [ path('', include(router.urls)), ] ``` 现在,你可以运行 Django 项目并使用 API 进行 CRUD 操作了。在命令行中运行 `python manage.py runserver` 启动 Django 服务器。然后,使用浏览器或其他 HTTP 客户端工具(例如 Postman)访问 API。 例如,要创建一个新的书籍,你可以向 `http://localhost:8000/books/` 发送一个 POST 请求,包含书籍的详细信息。要获取所有书籍的列表,你可以向 `http://localhost:8000/books/` 发送一个 GET 请求。要更新或删除特定的书籍,你可以向 `http://localhost:8000/books/<book_id>/` 发送一个 PUT 或 DELETE 请求,其中 `<book_id>` 是书籍的 ID。 这是一个非常简单的示例,但是它可以帮助你了解如何使用 DjangoDRF 来创建一个 CRUD API。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值