jacinli / jacinli.github.io

jacinli blog.
https://jacinli.github.io/
0 stars 0 forks source link

django的分页查询 #24

Open jacinli opened 1 month ago

jacinli commented 1 month ago

这个代码片段实现了一个基于 Django 的分页功能,用于从数据库中获取产品列表并返回分页后的结果。以下是对代码的详细解释,以及它与传统的基于偏移量(offset)和限制(limit)分页方式的区别。

代码详细介绍

from django.core.paginator import Paginator
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.decorators import api_view

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

@api_view(['POST'])
def product_list_view(request):
    user = request.user
    page_size = request.data.get("page_size", 10)
    page_number = request.data.get("page_number", 1)

    product_list = Product.objects.filter(yn=True).order_by("-sort")

    paginator = Paginator(product_list, page_size)
    page_obj = paginator.get_page(page_number)

    serializer = ProductSerializer(page_obj.object_list, many=True)
    data = serializer.data

    return Response(data)

代码分步解释:

  1. 获取当前用户

    user = request.user
  2. 获取分页参数

    page_size = request.data.get("page_size", 10)
    page_number = request.data.get("page_number", 1)
    • page_size:每页显示的项目数,默认为10。
    • page_number:请求的页码,默认为1。
  3. 查询数据库

    product_list = Product.objects.filter(yn=True).order_by("-sort")
    • Product 表中获取所有 yn=True 的产品,并按 sort 字段降序排序。
  4. 创建分页对象

    paginator = Paginator(product_list, page_size)
    • 使用 Django 的 Paginator 类对 product_list 进行分页,每页包含 page_size 个项目。
  5. 获取特定页的数据

    page_obj = paginator.get_page(page_number)
    • 获取请求的 page_number 页的数据。如果 page_number 超出范围,get_page 会返回最后一页的数据。
  6. 序列化数据

    serializer = ProductSerializer(page_obj.object_list, many=True)
    data = serializer.data
    • 使用 ProductSerializer 将分页后的产品数据转换为 JSON 格式。
  7. 返回响应

    return Response(data)
    • 返回序列化后的数据。

与 offset 和 limit 分页的区别

Django 分页 (基于页码的分页):

offset 和 limit 分页:

总结

选择哪种分页方式取决于您的具体需求和数据规模。Django 的分页系统提供了一个简单且可靠的解决方案,而 offsetlimit 则适合需要更高控制度的场景。

jacinli commented 1 month ago

Django的分页系统比较简单,但是处理复杂和快速的分页效率 不如自己写offset和limit的逻辑? 是的,可以这么理解。Django 的分页系统 (Paginator 类) 适用于大多数常见的分页需求,使用简单且能处理一些边界情况,但在处理非常大的数据集时,其性能可能不如基于 offsetlimit 的自定义分页逻辑高效。

Django 分页系统的优点

  1. 简单易用:Django 的分页系统封装了常见的分页逻辑,使用起来非常简单。
  2. 自动处理边界情况:例如,当请求的页码超出范围时,会自动返回最后一页的数据。
  3. 内置功能:Django 的分页系统提供了一些内置功能,例如分页导航、当前页码、高亮当前页等,适合快速开发。

Django 分页系统的缺点

  1. 性能问题:对于非常大的数据集,Django 的分页系统可能会有性能问题。原因是数据库在处理分页请求时,仍然需要扫描并跳过前面的记录,尤其是在使用较大偏移量(offset)时。
  2. 灵活性不足:Django 的分页系统是一个通用的解决方案,可能无法满足一些特定的需求。例如,在某些情况下,您可能需要更复杂的分页逻辑或更高的性能。

自定义 offsetlimit 的优点

  1. 更高的灵活性:您可以根据需要精确控制分页逻辑,适应特定的业务需求。
  2. 性能优化:对于非常大的数据集,您可以通过优化查询和使用索引来提高分页性能。例如,使用基于唯一标识符的分页方式,可以避免使用较大偏移量(offset)。

自定义 offsetlimit 的缺点

  1. 复杂度增加:自定义分页逻辑可能会增加代码的复杂度,需要您处理更多的细节,例如边界情况。
  2. 易错:由于需要手动处理分页逻辑,可能会出现错误,需要更多的测试和验证。

选择分页方式的建议

示例:基于 offsetlimit 的自定义分页

以下是一个使用 offsetlimit 的自定义分页示例:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.core.paginator import Paginator
from .models import Product
from .serializers import ProductSerializer

@api_view(['POST'])
def product_list_view(request):
    page_size = int(request.data.get("page_size", 10))
    page_number = int(request.data.get("page_number", 1))

    offset = (page_number - 1) * page_size
    limit = page_size

    product_list = Product.objects.filter(yn=True).order_by("-sort")[offset:offset + limit]

    serializer = ProductSerializer(product_list, many=True)
    data = serializer.data

    return Response(data)

示例:基于唯一标识符的分页

以下是一个使用唯一标识符(例如主键)进行分页的示例:

@api_view(['POST'])
def product_list_view(request):
    page_size = int(request.data.get("page_size", 10))
    last_id = request.data.get("last_id", None)

    if last_id:
        product_list = Product.objects.filter(yn=True, id__gt=last_id).order_by("id")[:page_size]
    else:
        product_list = Product.objects.filter(yn=True).order_by("id")[:page_size]

    serializer = ProductSerializer(product_list, many=True)
    data = serializer.data

    return Response(data)

在这个示例中,通过传递 last_id 参数来获取下一页的数据,这种方法可以避免大偏移量带来的性能问题。

jacinli commented 1 month ago

1