返回
Django原生sql灵活高效分页方案
后端
2023-10-02 00:24:06
原生SQL分页的妙招:打破Django限制
在Django的浩瀚世界中,Paginator 扮演着分页大师的角色,轻松驾驭 ORM 查询集和列表。然而,当原生 SQL 登场时,Paginator 的魔法就失效了,因为原生 SQL 返回的是一个神秘的游标对象,而 Paginator 只认得 ORM 查询集。
别担心,我们有办法打破这个限制,让原生 SQL 也能享受分页的乐趣。
方式一:巧用ORM查询集
这个方法可谓化腐朽为神奇,它将原生 SQL 查询的结果巧妙地转换成 Django ORM 查询集,让 Paginator 欢天喜地地接受。代码如下:
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT * FROM my_table")
# 将游标对象变身 ORM 查询集
queryset = Model.objects.from_queryset(cursor)
# 交给 Paginator 分页
paginator = Paginator(queryset, 10) # 每页 10 条数据
# 拿到当前页数据
page = paginator.page(1) # 第一页
# 渲染分页模板
return render(request, 'my_template.html', {'page': page})
方式二:自定义分页器
这个方法更具灵活性,我们可以按自己的喜好定制分页行为。代码如下:
from django.core.paginator import Paginator
import math
class CustomPaginator(Paginator):
def __init__(self, cursor, per_page):
self.cursor = cursor
self.per_page = per_page
self.num_pages = math.ceil(self.cursor.rowcount / self.per_page)
def page(self, number):
if number > self.num_pages:
raise Http404("非法页码")
# 获取当前页数据
self.cursor.execute("SELECT * FROM my_table LIMIT %s OFFSET %s", [self.per_page, (number - 1) * self.per_page])
data = self.cursor.fetchall()
# 创建一个 Page 对象
page = Page(data, number, self)
return page
# 使用自定义分页器分页原生 SQL 结果
paginator = CustomPaginator(cursor, 10) # 每页 10 条数据
# 获取当前页数据
page = paginator.page(1) # 第一页
# 渲染分页模板
return render(request, 'my_template.html', {'page': page})
选择哪种方式?
两种方法各有千秋:
- 方式一 更简单,但原生 SQL 结果需转换为 ORM 查询集,可能影响查询效率。
- 方式二 更灵活,可定制分页行为,但需要编写自定义分页器,代码复杂度更高。
根据实际情况选择最适合你的方法吧!
常见问题解答
1. 如何在分页模板中显示页码链接?
使用 Django 的 {% paginate %}
和 {% page_numbers %}
标签。
2. 如何自定义分页样式?
修改 django.contrib.admin.templatetags.admin_list.html
模板文件。
3. 如何分页嵌套查询的结果?
使用递归或分步查询。
4. 如何处理大数据集分页?
考虑使用数据库分页或异步分页。
5. 是否有其他分页库可以与 Django 集成?
是的,例如 Django Extensions 和 Django REST Framework。