Django core.serializers序列化速度过慢,如何优化以提升结果展示效率?
你在Django视图中使用django.core.serializers进行序列化,功能正常但有时展示结果表格需要超过1分钟,视图代码如下:
# views.py from django.core import serializers def search_institution(request): form = SearchInstitutionsForm() qs = Institution.objects.all() if request.method == "POST": form = SearchInstitutionsForm(request.POST) if form.is_valid(): cd = form.cleaned_data if cd['name']: qs = Institution.objects.filter(name__contains=cd['name']) print(f"Before requesting from db: {datetime.now()}") print(f"After requesting from db, before serializing: {datetime.now()}") context = { "result_data": SafeString(serializers.serialize("json", qs)), 'form': form } print(f"After serializing, before rendering: {datetime.now()}") return render(request, "landing/result_table.html", context) else: context = { "form": SearchInstitutionsForm } return render(request, "stakeholders/institution_form.html", context)
嘿,我看了你的问题和代码,序列化慢确实很影响用户体验,这里有几个实用的优化方案,你可以根据自己的场景来选择:
替换Django自带序列化器,手动构建数据
Django自带的serializers.serialize会额外处理很多元数据(比如模型的app_label、主键类型等),如果你的前端不需要这些冗余信息,完全可以手动构建只包含所需字段的字典,再用JSON工具序列化,速度会快很多。示例代码:import json # 只提取你需要的字段,避免不必要的序列化处理 result_data = [] for inst in qs: result_data.append({ "id": inst.id, "name": inst.name, # 这里添加其他需要展示的字段 }) # 替换成手动序列化的结果 context = { "result_data": SafeString(json.dumps(result_data)), 'form': form }优化数据库查询,避免N+1问题
如果Institution模型有外键、多对多等关联字段,序列化时可能会触发多次数据库查询(也就是N+1问题),拖慢整体速度。你可以用select_related(针对外键/一对一)或prefetch_related(针对多对多/反向外键)提前把关联数据一次性查询出来:# 假设有外键category,用select_related预取 qs = Institution.objects.filter(name__contains=cd['name']).select_related('category') # 如果是多对多关系比如tags,用prefetch_related qs = Institution.objects.filter(name__contains=cd['name']).prefetch_related('tags')这样数据库只需要一次查询,序列化时就不用反复访问数据库了。
对大量结果进行分页处理
如果查询返回的数据集很大(比如上千条),一次性序列化所有数据肯定慢,而且前端渲染大表格也会卡顿。可以用Django的Paginator做分页,每次只处理和返回一页的数据:from django.core.paginator import Paginator # 设置每页显示20条,可根据需求调整 paginator = Paginator(qs, 20) page_number = request.GET.get('page', 1) page_obj = paginator.get_page(page_number) # 只序列化当前页的数据 result_data = [] for inst in page_obj: result_data.append({ "id": inst.id, "name": inst.name }) # 把分页信息传给前端,方便做翻页控件 context = { "result_data": SafeString(json.dumps(result_data)), "page_obj": page_obj, 'form': form }使用更快的JSON序列化库
标准库的json模块可以换成更高效的第三方库,比如ujson,它的序列化速度比标准库快不少。安装后直接替换即可:import ujson # 用ujson替代json进行序列化 context = { "result_data": SafeString(ujson.dumps(result_data)), 'form': form }缓存重复查询的结果
如果你的机构数据不是实时更新的,可以把查询和序列化后的结果缓存起来,相同的搜索请求直接返回缓存内容,省去重复的数据库查询和序列化步骤:from django.core.cache import cache # 用搜索关键词作为缓存键,确保唯一性 cache_key = f"institution_search_{cd['name']}" cached_data = cache.get(cache_key) if not cached_data: # 没有缓存时才查询和序列化 result_data = [] for inst in qs: result_data.append({ "id": inst.id, "name": inst.name }) cached_data = ujson.dumps(result_data) # 设置缓存有效期,比如1小时(根据数据更新频率调整) cache.set(cache_key, cached_data, 3600) context = { "result_data": SafeString(cached_data), 'form': form }
内容的提问来源于stack exchange,提问作者piah

