drf - 偏移分页组件 LimitOffsetPagination
Posted 863652104kai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了drf - 偏移分页组件 LimitOffsetPagination相关的知识,希望对你有一定的参考价值。
数据准备
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 LimitOffsetPagination
class CarLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 # 设置每页显示的数量为3,此时url中下一页的offset就会往后偏移3条
# 优先使用limit_query_param来设置显示条数
limit_query_param = 'limit'
offset_query_param = 'offset' # 偏移数,就是多少条数据后显示
max_limit = 5
# url链接:car/?limit=2 一页显示2条,默认显示第一页
# url链接:car/?limit=2&offset=4 往后偏移4条数据后,再显示自定义的2条数据,limit输入的数不能大于max_limit设置的数,大于则按max_limit来显示
注意:car/?limit=2&offset=4,若数据总条数只有5条,偏移offset=4条后显示就只显示1条数据
view.py文件:需要自定义pagination_class
from rest_framework.viewsets import ModelViewSet
from . import models, serializer
from .paginations import CarLimitOffsetPagination
class CarModelViewSet(ModelViewSet):
queryset = models.Car.objects.filter(is_delete=False)
serializer_class = serializer.CarModelSerializer
# 自定义pagination_class
parser_classes = CarLimitOffsetPagination
分页组件部分源码分析二
1. 调用CarLimitOffsetPagination的paginate_queryset方法(继承至LimitOffsetPagination)
def paginate_queryset(self, queryset, request, view=None):
self.count = self.get_count(queryset) # 获取数据的总数量
self.limit = self.get_limit(request)
if self.limit is None:
return None
self.offset = self.get_offset(request)
self.request = request
if self.count > self.limit and self.template is not None:
self.display_page_controls = True
if self.count == 0 or self.offset > self.count:
return []
return list(queryset[self.offset:self.offset + self.limit])
2. 调用 get_limit 方法获取 limit
def get_limit(self, request):
if self.limit_query_param: # limit_query_param 为'limit'
try:
return _positive_int(
request.query_params[self.limit_query_param],
strict=True,
cutoff=self.max_limit # 最大limit
)
except (KeyError, ValueError):
pass
return self.default_limit # drf中默认设置为None,可以在类中配置
3. 设置了limit_query_param时,self.limit 为调用_positive_int方法后的结果
def _positive_int(integer_string, strict=False, cutoff=None):
"""
Cast a string to a strictly positive integer.
"""
ret = int(integer_string) # url传入的值,在url中:car/?limit=4.则ret=4
if ret < 0 or (ret == 0 and strict):
raise ValueError()
if cutoff:
return min(ret, cutoff)
return ret
4. 调用 get_offset方法获取 offset
def get_offset(self, request):
try:
return _positive_int(
request.query_params[self.offset_query_param], # offset_query_param = 'offset'
)
except (KeyError, ValueError):
return 0
以上是关于drf - 偏移分页组件 LimitOffsetPagination的主要内容,如果未能解决你的问题,请参考以下文章