zoukankan      html  css  js  c++  java
  • drf

    数据准备

    model.py文件

    定义两个表Car表和Brand表,其中Car中的brand字段外键关联Brand表

    from django.db import models
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        create_time = models.DateTimeField(auto_now_add=True)
        class Meta:
            abstract = True
    
    
    class Car(BaseModel):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        brand = models.ForeignKey('Brand', db_constraint=False, on_delete=models.DO_NOTHING, related_name='cars')
        @property
        def brand_name(self):
            return self.brand.name
        class Meta:
            db_table = 'old_boy_car'
            verbose_name = '汽车'
            verbose_name_plural = verbose_name
        def __str__(self):
            return self.name
        
    class Brand(BaseModel):
        name = models.CharField(max_length=32)
        class Meta:
            db_table = 'old_boy_brand'
            verbose_name = '品牌'
            verbose_name_plural = verbose_name
        def __str__(self):
            return self.name
    

    新建的serializer.py文件

    brand字段只参与反序列化,brand_name只参与序列化

    from rest_framework.serializers import ModelSerializer
    from . import models
    class CarModelSerializer(ModelSerializer):
        class Meta:
            model = models.Car
            fields = ('name','price','brand','brand_name')
            extra_kwargs = {
                "brand":{
                    'write_only':True
                },
                'brand_name':{
                    'read_only':True
                },
            }
    

    分页组件部分源码分析一

    通常是在获取多条数据list方法中,进行分页显示。所以viewsets.py文件中list方法是分页入口

    class ListModelMixin:
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())  # 先筛选
    
            page = self.paginate_queryset(queryset)  # 后分页,再序列化显示
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
    

    1. 先调用paginate_queryset方法,此方法继承至generics中的GenericAPIView类

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:  # self.paginator分页器,如果为None表示不分页
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)
    

    2. 调用paginator方法

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            # 如果配置中的pagination_class为空就不分页,所以要分页就需要配置pagination_class类,else中实例化分页类
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator
    

    3. 自定义pagination_class

    4. 调用pagination_class类中的paginate_queryset方法

    自定义分页组件

    新建的paginations.py文件,CarPageNumberPagination继承了drf分页组件中的PageNumberPagination类

    from rest_framework.pagination import PageNumberPagination
    class CarPageNumberPagination(PageNumberPagination):
        page_size = 3  # 设置每页显示的数量为3
        
        # 优先使用page_size_query_param的设置来显示条数
        page_size_query_param = 'page_size'  # 自己输入每页显示的条数
        max_page_size = 5  # 一页显示的最大条数,与page_size_query_param搭配使用
        
    # url链接:car/?page=2  显示第2页,不写默认显示第一页
    # url链接:car/?page_size=4  每页4条数据,若大于max_page_size,则显示max_page_size设置的条数
    # url链接:car/?page=2&page_size=4  每页显示4条,显示第2页
    # url链接:car/?page=last  显示最后一页
    

    注意:是根据数据显示,若数据总条数只有5条,每页显示3条,这时第2页就值显示2条数据

    view.py文件:需要自定义pagination_class

    from rest_framework.viewsets import ModelViewSet
    from . import models, serializer
    from .paginations import CarPageNumberPagination
    
    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializer.CarModelSerializer
        # 自定义pagination_class
        parser_classes = CarPageNumberPagination
    

    分页组件部分源码分析二

    1. 调用CarPageNumberPagination中的paginate_queryset方法

    def paginate_queryset(self, queryset, request, view=None):
        """
        Paginate a queryset if required, either returning a
        page object, or `None` if pagination is not configured for this view.
        """
        page_size = self.get_page_size(request)  # 获取page_size
        if not page_size:
            return None
    
        paginator = self.django_paginator_class(queryset, page_size)  # 分页器,django.core.paginator中的Paginator分页器类
        page_number = request.query_params.get(self.page_query_param, 1)  # page_query_param为'page',在url接口中page=2表示第2页,page就是链接的页数表示。默认为page=1
        if page_number in self.last_page_strings:  
            # last_page_strings为('last',),如果url输入page=last,表示最后一页
            page_number = paginator.num_pages
    
        try:
            self.page = paginator.page(page_number)
        except InvalidPage as exc:
            msg = self.invalid_page_message.format(
                page_number=page_number, message=str(exc)
            )
            raise NotFound(msg)
    
        if paginator.num_pages > 1 and self.template is not None:
            # The browsable API should display pagination controls.
            self.display_page_controls = True
    
        self.request = request
        return list(self.page)
    

    2. 调用get_page_size方法,获取page_size:每页显示的数量

    def get_page_size(self, request):
        if self.page_size_query_param:  # drf中默认设置为None,可以在CarPageNumberPagination类中自定义,如果没有设置就直接返回page_size的值
            try:
                return _positive_int(
                    request.query_params[self.page_size_query_param],  
                    strict=True,
                    cutoff=self.max_page_size  # 一页显示的最大数量
                )
            except (KeyError, ValueError):
                pass
    
        return self.page_size  # drf中默认设置为None,可以在类中配置
    

    3. 设置了page_size_query_param时,获取的page_size每页显示的数量。调用_positive_int方法

    def _positive_int(integer_string, strict=False, cutoff=None):
        """
        Cast a string to a strictly positive integer.
        """
        ret = int(integer_string) # url传入的值,如page_size_query_param='page_size',在url中:car/?page_size=4.则ret=4
        if ret < 0 or (ret == 0 and strict):
            raise ValueError()
        if cutoff:
            return min(ret, cutoff)
        return ret  # 此时ret为4就是返回的page_size
    
  • 相关阅读:
    SVM学习笔记-线性支撑向量机
    阿里面试回来,想和Java程序员谈一谈
    看外国女程序员如何直播写代码
    shoeBox超实用的雪碧图(Sprite)图制作工具-使用
    Android图像处理之图形特效处理
    SMP、NUMA、MPP体系结构介绍
    TIOBE 2017 8月编程语言排行榜 后院“硝烟四起”
    Android Studio中Git和GitHub使用详解
    矩阵乘法快速幂 codevs 1574 广义斐波那契数列
    矩阵乘法 codevs 1287 矩阵乘法
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11523358.html
Copyright © 2011-2022 走看看