Django Admin 百万级数据变慢主因是默认全量加载,禁用 list_editable 外键、改用 autocomplete_fields、精简 get_queryset 和 list_display、设 list_per_page=20 并关闭总数统计,性能可从 8 秒降至 300 毫秒。

直接说结论:Django Admin 在百万级数据下变慢,90% 的问题出在默认行为上——不是代码写得差,而是没关掉那些“自动全量加载”的开关。改几行配置,性能常能从 8 秒降到 300 毫秒。
禁用 list_editable 字段(尤其外键)
只要开了 list_editable,Django 就会为每行每个字段渲染完整表单控件,外键字段还会触发 SELECT * FROM related_table。50 行 × 2 个外键字段 = 至少 100 次全表扫描。
- 绝对不要把
ForeignKey、ManyToManyField或带动态choices的字段放进list_editable - 若必须批量改状态类字段(如
is_active),用actions替代:queryset.update(is_active=True)绕过 ORM 实例化 - 真要保留
list_editable,务必搭配list_per_page = 20,否则性能随行数线性恶化
替换外键下拉框为 autocomplete_fields
默认的 ModelChoiceField 会执行 queryset.all(),几万条记录全查出来再塞进 <select></select>,后端 SQL 直接卡死。这不是前端慢,是数据库被拖垮。
- 在 Admin 类里加
autocomplete_fields = ['author', 'category'](字段名必须是ForeignKey或ManyToManyField) - 对应关联模型的 Admin 必须定义
search_fields,例如class AuthorAdmin(admin.ModelAdmin): search_fields = ['name', 'email'] - 确保关联字段加了数据库索引,否则搜索仍慢:
db_index=True或用Meta.indexes显式声明
精简 get_queryset 中的查询逻辑
select_related 和 prefetch_related 解决的是列表页的 N+1 问题,但它们对外键下拉框无效——下拉框走的是字段自己的 queryset,不是列表页的 get_queryset。
立即学习“Python免费学习笔记(深入)”;
- 只在
get_queryset里做真正需要的预加载,比如list_display里写了'author__name',才加select_related('author') - 避免无意义的
.order_by('name'):对几万条记录排序开销极大,且下拉框通常不需要固定顺序 - 别在
formfield_for_foreignkey里写数据库查询或 API 调用——它会在每次页面渲染时执行,行数越多越致命
控制 list_display 和分页数量
列表页渲染慢,一半原因是传了太多字段给模板。每个字段都要调用 __str__、触发关联对象访问、甚至执行自定义方法。
- 用
list_display只留核心字段,删掉不必要展示的外键、富文本、JSON 字段 -
list_per_page别用默认 100,设为 20–30;配合show_full_result_count = False关掉总数统计(避免COUNT(*)全表扫描) - 对大文本字段(如
TextField)用Truncator截断显示,避免传输和渲染巨量 HTML
最易被忽略的一点:所有优化都依赖真实查询分析。上线前一定要跑 QuerySet.explain(),或装 django-debug-toolbar 看清到底哪条 SQL 最重——有时候瓶颈根本不在 Django 层,而在缺失复合索引或未加 db_index=True 的外键字段上。


















