如何在后续请求中存储并访问Django的ChangeList对象?
解决无法存储ChangeList对象的问题
直接存储整个ChangeList实例确实行不通,因为它包含大量不可序列化的对象(比如数据库连接、模块引用、懒加载的查询集元素等),不管是缓存的pickle序列化还是session的JSON序列化都会失败。下面给你几个可行的替代思路:
思路1:存储过滤参数而非整个ChangeList
这是最稳妥的方案——你不需要保存整个ChangeList,只需要保存生成过滤后queryset的原始参数,后续AJAX请求时用这些参数重新构建ChangeList或直接过滤queryset。
示例代码:
在你的changelist_view里存储过滤参数:
def changelist_view(self, request, extra_context=None): changelist = ChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter, self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_max_show_all, self.list_editable, self) # 提取request中的过滤、搜索、排序参数,转成可序列化的普通字典 filter_params = request.GET.dict() # 用用户ID作为缓存键的一部分,避免不同用户的参数混淆 cache_key = f"time_report_filters_{request.user.id}" # 设置合理的过期时间,比如5分钟,避免旧数据长期留存 cache.set(cache_key, filter_params, 300) ...
然后在AJAX视图中,用存储的参数重新获取过滤后的queryset:
from django.contrib.admin.views.main import ChangeList from django.http import QueryDict, JsonResponse def ajax_get_filtered_data(request): user = request.user cache_key = f"time_report_filters_{user.id}" filter_params = cache.get(cache_key) if not filter_params: return JsonResponse({"error": "No saved filters found"}, status=400) # 重新构建ChangeList来处理复杂的admin过滤逻辑 admin_instance = TimeReportEntryAdmin(TimeReportEntry, admin.site) # 构造一个新的QueryDict替换request.GET mutable_get = QueryDict('', mutable=True) mutable_get.update(filter_params) request.GET = mutable_get changelist = ChangeList( request, admin_instance.model, admin_instance.list_display, admin_instance.list_display_links, admin_instance.list_filter, admin_instance.date_hierarchy, admin_instance.search_fields, admin_instance.list_select_related, admin_instance.list_per_page, admin_instance.list_max_show_all, admin_instance.list_editable, admin_instance ) filtered_qs = changelist.get_queryset(request) # 这里根据你的需求处理queryset,比如返回所需字段 data = [{"id": obj.pk, "date": obj.report_date.strftime("%Y-%m-%d")} for obj in filtered_qs] return JsonResponse(data, safe=False)
思路2:存储过滤后queryset的主键列表
如果你的需求只是获取过滤后的对象,不需要重新使用ChangeList的其他功能,可以直接提取过滤后queryset的主键列表(列表是可序列化的),后续AJAX请求时用主键重新查询。
示例代码:
def changelist_view(self, request, extra_context=None): changelist = ChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter, self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_max_show_all, self.list_editable, self) filtered_qs = changelist.get_queryset(request) # 提取所有主键存为列表 pk_list = list(filtered_qs.values_list('pk', flat=True)) cache_key = f"time_report_pks_{request.user.id}" cache.set(cache_key, pk_list, 300) ...
AJAX视图中:
def ajax_get_filtered_data(request): user = request.user cache_key = f"time_report_pks_{user.id}" pk_list = cache.get(cache_key) if not pk_list: return JsonResponse({"error": "No saved data found"}, status=400) filtered_qs = TimeReportEntry.objects.filter(pk__in=pk_list) # 处理数据返回 data = [{"id": obj.pk, "date": obj.report_date.strftime("%Y-%m-%d")} for obj in filtered_qs] return JsonResponse(data, safe=False)
注意事项:
- 这种方法的缺点是,如果两次请求之间数据有更新(比如对象被删除或修改),AJAX返回的会是旧的主键对应的结果,适合数据不频繁变动的场景。
- 如果queryset数据量极大,主键列表会占用较多缓存空间,需要权衡。
思路3:自定义序列化必要数据
如果ChangeList里有你需要的特定元数据(比如分页信息、过滤选项),可以手动提取这些可序列化的部分存储,而不是整个对象。比如提取changelist.result_count、changelist.page_num等字段,和过滤参数一起保存。
内容的提问来源于stack exchange,提问作者saturnusringar
相关产品推荐
相关产品推荐

