[Python自学] DRF (5) (解析器、URL控制、分页)

参考博客:https://www.cnblogs.com/yuanchenqi/articles/8719520.html

一、数据解析器

1.Django默认的数据解析

在我们使用django框架时,浏览器如果发送以下类型的POST数据:

Content-Type=application/x-www-form-urlencoded
Content-Type=application/form-data

则django会自动帮我们将请求体中的数据转换为字典,保存在request.POST中。

但是,如果浏览器发送的是json数据:

Content-Type=application/json

则django无法为我们转换,我们只能从request.body中获取原始数据,自己进行转换。

2.restframework提供的解析器

如果我们使用restframework,他给我们提供了几个常用的数据解析器,列表如下:

from rest_framework import parsers

# 处理json数据,media_type = 'application/json'
parsers.JSONParser
# 处理x-www-form-urlencoded数据,media_type = 'application/x-www-form-urlencoded'
parsers.FormParser
# 处理multipart/form-data数据,media_type = 'multipart/form-data'
parsers.MultiPartParser
# 处理所有数据,media_type = '*/*'
parsers.FileUploadParser

如果我们在视图类中不指定需要使用的解析器,则默认会使用三种:

在APIView类中可以看到:

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    ...
    ...

在DEFAULTS中找到 DEFAULT_PARSER_CLASSES :

'DEFAULT_PARSER_CLASSES': [
    'rest_framework.parsers.JSONParser',
    'rest_framework.parsers.FormParser',
    'rest_framework.parsers.MultiPartParser'
],

默认使用了JSONParser、FormParser和MultiPartParser三种解析器。

3.在视图类中指定可以使用的解析器

class LoginView(APIView):
    authentication_classes = []
    parser_classes = [parsers.JSONParser,parsers.FormParser]
    ...
    ...

我们可以在视图类中使用parser_classes列表来指定该视图类可以使用的解析器。

当然,我们也可以仿造JSONParser等解析器实现自己的解析器。

二、URL控制

1.自动生成URL路由条目

在 [Python自学] restframework (2) (视图类的封装) 中的level-3中,一个视图类提供5种操作,但是要对应两条urls路由条目。

其实restframework也给我们提供了一个封装,来自动生成相应的urls:

from django.contrib import admin
from django.urls import path, re_path, include
from demo import views

from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'authors', views.AuthorViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^publishes/$', views.PublishView.as_view(), name="publish"),
    re_path('^publishes/(?P\d+)/$', views.PublishDetailView.as_view(), name="publishdetail"),
    re_path('^books/$', views.BookView.as_view(), name="book"),
    re_path('^books/(?P\d+)/$', views.BookDetailView.as_view(), name="bookdetail"),
    # re_path('^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author"),
    # re_path('^authors/(?P\d+)/$', views.AuthorViewSet.as_view(
    #     {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}), name="authordetail"),
    re_path('^login/$', views.LoginView.as_view(), name="login"),
    re_path('', include(router.urls))
]

这样,就不用自己写两条authors的路由条目了。

2.测试结果

1)浏览器访问authors全部数据,http://127.0.0.1:8000/authors/?token=81ba24601ce5be47ff2d96142a8ccb76:

[Python自学] DRF (5) (解析器、URL控制、分页)_第1张图片

 2)浏览器访问authors全部数据,http://127.0.0.1:8000/authors.json?token=81ba24601ce5be47ff2d96142a8ccb76:

3)浏览器访问authors全部数据,http://127.0.0.1:8000/authors/?format=json&token=81ba24601ce5be47ff2d96142a8ccb76:

4)浏览器访问authors中id为1的数据,http://127.0.0.1:8000/authors/1/?token=81ba24601ce5be47ff2d96142a8ccb76:

[Python自学] DRF (5) (解析器、URL控制、分页)_第2张图片

3.总结

使用restframework提供的url控制功能,可以自动为我们生成4条路由条目:

^authors/$ [name='author-list']
^authors\.(?P[a-z0-9]+)/?$ [name='author-list']
^authors/(?P[^/.]+)/$ [name='author-detail']
^authors/(?P[^/.]+)\.(?P[a-z0-9]+)/?$ [name='author-detail']

其中,当使用浏览器访问时,authors.json和authors的区别在于是否提供渲染页面。前者只返回纯数据,后者会返回restframework提供的页面。

三、分页

1.直接在视图类中添加分页

在 [Python自学] restframework (1) 中,我们手工从数据库中获取books数据,并序列化返回给浏览器。GET获取全量数据的代码如下:

class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        bs = BookModelSerializers(book_list, many=True)

        return Response(bs.data)

    def post(self, request):
        pass

如果我们想为其添加分页,每次只返回固定的条数:

class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()

        # 添加分页
        from rest_framework.pagination import PageNumberPagination
        pnp = PageNumberPagination()
        # 获取每一页
        book_page = pnp.paginate_queryset(book_list, request, self)
        # 将book_page传入进行序列化
        bs = BookModelSerializers(book_page, many=True, context={'request': request})

        return Response(bs.data)

每页显示的页数,我们可以在settings中的REST_FRAMEWORK中配置:

REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["demo.utils.TokenAuth"],
    # "DEFAULT_PERMISSION_CLASSES":["demo.utils.SVIPPermission"]
    "PAGE_SIZE": 2,
}

测试结果:

访问 http://127.0.0.1:8000/books/默认显示第一页的两条数据:

[Python自学] DRF (5) (解析器、URL控制、分页)_第3张图片

 

 

 访问 http://127.0.0.1:8000/books/?page=3显示指定页的数据:

[Python自学] DRF (5) (解析器、URL控制、分页)_第4张图片

 

2.自定义分页子类

在前面我们的PAGE_SIZE是在settings中配置的,我们也可以自定义一个类,继承自 PageNumberPagination类:

from rest_framework.pagination import PageNumberPagination


class MyPageNumberPagination(PageNumberPagination):
    page_size = 1
    # 在url中指定页数的参数名http://127.0.0.1:8000/books/?page=1
    page_query_param = 'page'
    # 在url中指定每页显示条数http://127.0.0.1:8000/books/?page=1&size=2
    page_size_query_param = 'size'


class BookView(APIView):
    # authentication_classes = [TokenAuth]

    def get(self, request):
        book_list = Book.objects.all()

        # 这里使用我们自定义的类
        pnp = MyPageNumberPagination()
        # 获取每一页
        book_page = pnp.paginate_queryset(book_list, request, self)
        # 将book_page传入进行序列化
        bs = BookModelSerializers(book_page, many=True, context={'request': request})

        return Response(bs.data)

这样,我们在自己定义的子类中就可以指定page_size等参数,无需到settings中去配置了。而且这样可以让每个视图类由不同的分页特性。例如可以让books和authors每页显示条数不同。

3.另外一种分页类(limit和offset)

除了 PageNumberPagination类,restframe还提供了另一个类 LimitOffsetPagination:

from rest_framework.pagination import LimitOffsetPagination


class MyLimitOffsetPagination(LimitOffsetPagination):
    # 相当于PageNumberPagination类的page_size
    default_limit = 1
    # url中的limit参数,控制每页显示条数
    limit_query_param = 'limit'
    # url中的offset参数,控制偏移多少
    offset_query_param = 'offset'


class BookView(APIView):
    # authentication_classes = [TokenAuth]

    def get(self, request):
        book_list = Book.objects.all()

        # 这里使用我们自定义的类
        pnp = MyLimitOffsetPagination()
        # 获取每一页
        book_page = pnp.paginate_queryset(book_list, request, self)
        # 将book_page传入进行序列化
        bs = BookModelSerializers(book_page, many=True, context={'request': request})

        return Response(bs.data)

使用 MyLimitOffsetPagination 类的话,访问的url会不同,例如:

[Python自学] DRF (5) (解析器、URL控制、分页)_第5张图片

 limit=2表示每页显示两条数据(默认设置的是1条)。

[Python自学] DRF (5) (解析器、URL控制、分页)_第6张图片

offset=1表示向后偏一条数据(注意,是一条数据,不加offset=1时,显示的是id为8和9的数据,加了offset=1显示的时id为9和10的数据)。

4.封装后的视图类如何使用分页类

在[Python自学] restframework (2) (视图类的封装)中,我们对视图类的封装有三个级别,以最后level-3作为例子,如何使用分页器:

from rest_framework.pagination import PageNumberPagination


class MyPageNumberPagination(PageNumberPagination):
    page_size = 1
    page_query_param = 'page'
    page_size_query_param = 'size'


# Author序列化类
class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"


class AuthorViewSet(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers
    pagination_class = MyPageNumberPagination

这样设置以后,restframe就会自动的去使用 MyPageNumberPagination 类进行分页操作了。具体流程可以跟踪源代码。原理类似认证、权限、频率组件。

 

f≥Ö‿Ö≤

你可能感兴趣的:([Python自学] DRF (5) (解析器、URL控制、分页))