Django-Vue-Admin 列表页“慢、乱、抖”的 500 字速修
场景:Django(DRF)+ Vue Admin,列表页翻页重复/漏项、筛选卡顿、导出与页面口径不一致。下面是一套可直接抄的 500 字速修方案(无外链)。
目标
稳定排序:翻页不抖动
消灭 N+1:SQL 次数不随行数线性增长
可观测:能解释“慢在哪里”
一、统一 QuerySet(queries.py)
# queries.py
from django.db.models import Q, F
from django.db.models.functions import Coalesce
from .models import Order
def build_order_qs(p):
qs = (Order.objects
.select_related("user")
.prefetch_related("items"))
if kw := p.get("keyword"):
qs = qs.filter(Q(code__icontains=kw) | Q(user__email__icontains=kw))
if st := p.get("status"):
qs = qs.filter(status=st)
return qs.annotate(amount_safe=Coalesce(F("amount"), 0))
)
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.pagination import CursorPagination
from .queries import build_order_qs
from .serializers import OrderSerializer
class StablePage(CursorPagination):
page_size = 20
ordering = ("-created_at", "-id") # 次级唯一键
class OrderViewSet(ReadOnlyModelViewSet):
serializer_class = OrderSerializer
pagination_class = StablePage
def get_queryset(self):
return build_order_qs(self.request.query_params)
导出:直接 build_order_qs() + iterator(chunk_size=500) 流式写 CSV
统计:在同一 QuerySet 上做 aggregate()/values().annotate()
防抖:搜索 300ms 防抖
响应去重:维护 requestId,旧响应丢弃
参数一致:切换筛选保留排序字段
开启数据库慢查询日志(>200ms)
记录接口 P50/P90/P99 与 SQL 次数
对大范围筛选给出提示与上限,必要时走异步导出
口诀:“稳排序、预取数、同口径、可观测”。先让列表不抖,再谈“快”。