Django-Vue-Admin 列表页“又慢又乱”?一次把 N+1、排序抖动、分页重复 全部解决的实战笔记

发布于 2025-10-01 23:43:06

Django-Vue-Admin 列表页“又慢又乱”?一次把 N+1、排序抖动、分页重复 全部解决的实战笔记

场景:后端 Django(DRF)+ 前端 Vue Admin,某个“订单列表/用户列表”在数据一多就拖沓:接口 800ms 起步、翻页出现重复/漏项、筛选后导出顺序还和页面不一致。下面是我在项目里落地的一整套修复方案,无外链、可直接抄。

目标

稳定排序:翻页不重复、不漏项。

可预取:消灭 ORM N+1。

筛选一致:表格、导出、统计三处使用同一套查询。

观测可解释:哪里慢、慢多少、为什么慢,一眼看出来。

一、后端查询层:把“查询策略”抽出来
1) QuerySet 统一构造

app/queries.py

from django.db.models import Q
from django.db.models import F
from django.db.models.functions import Coalesce
from .models import Order

def build_order_qs(params):

qs = Order.objects.select_related("user").prefetch_related("items")  # 消灭 N+1
# 筛选
kw = params.get("keyword")
if kw:
    qs = qs.filter(Q(user__email__icontains=kw) | Q(code__icontains=kw))
status = params.get("status")
if status:
    qs = qs.filter(status=status)
# 统计字段(示例:空值置 0,便于排序)
qs = qs.annotate(amount_safe=Coalesce(F("amount"), 0))
return qs

经验:不要在 ViewSet 里乱拼 filter。把“可复用的查询构造器”抽到 queries.py,前端任意页面(表格/导出/统计)都走这一个入口。

2) 稳定排序(防翻页抖动)

app/views.py

from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.pagination import CursorPagination
from .serializers import OrderSerializer
from .queries import build_order_qs

class OrderCursorPagination(CursorPagination):

page_size = 20
ordering = ("-created_at", "-id")  # 关键:次级唯一键,稳定

class OrderViewSet(ReadOnlyModelViewSet):

serializer_class = OrderSerializer
pagination_class = OrderCursorPagination

def get_queryset(self):
    return build_order_qs(self.request.query_params)

要点:

游标分页(CursorPagination)天生防止“翻页后数据位移”;

即便不用游标,也务必在 ordering 中加入唯一键(如 -id)做次级排序。

二、序列化与只取所需字段:减少“行宽”

app/serializers.py

from rest_framework import serializers
from .models import Order, OrderItem

class OrderItemLiteSerializer(serializers.ModelSerializer):

class Meta:
    model = OrderItem
    fields = ("sku", "qty")

class OrderSerializer(serializers.ModelSerializer):

user_email = serializers.EmailField(source="user.email", read_only=True)
items = OrderItemLiteSerializer(many=True, read_only=True)

class Meta:
    model = Order
    fields = ("id", "code", "status", "amount_safe", "created_at", "user_email", "items")

只返回表格需要的字段,详情页另做详情接口。表格页“什么都想拿”是最容易拖慢的坑。

0 条评论

发布
问题