You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AJAX更新Div时遇TypeError:QuerySet无法JSON序列化求助

Django AJAX定时刷新Div的JSON序列化问题解决与优化建议

问题根源分析

从你的报错栈可以明确看到,TypeError的核心原因是:你把Django特有的QuerySet对象直接传给了json.dumps()——不管是Jobs模型返回的模型实例QuerySet(backup_info),还是Update.objects.values(...)返回的ValuesQuerySet(update_info),原生Python的json模块都无法直接序列化这些非标准Python数据结构。


针对性解决方案

要解决这个问题,核心是把Django QuerySet转换成JSON可识别的普通Python数据结构(比如字典列表),这里有两种最常用的可行方式:

1. 使用Django内置序列化器

Django提供了django.core.serializers模块,可以直接将QuerySet序列化成字典列表或JSON字符串,支持指定需要序列化的字段:

from django.core import serializers

# 将Jobs的QuerySet序列化为字典列表
backup_data = serializers.serialize('python', b)
# 如果只需要特定字段,可添加fields参数
backup_data = serializers.serialize('python', b, fields=('end_time', 'id_cliente'))

2. 手动转换ValuesQuerySet为普通列表

对于用values()获取的ValuesQuerySet,只需要把它转成普通Python列表,就能被JSON序列化:

update_data = list(u)  # u是Update.objects.values('nome_cliente').distinct()的结果

修改后的完整代码示例

1. 修复后的AJAX视图代码

import json
import time
from django.http import HttpResponse, Http404
from django.core import serializers
from django.contrib import messages
from .models import Jobs, Update, Cliente

def reload_data(request):
    if request.is_ajax():
        b = Jobs.objects.order_by('end_time').reverse()[:10]
        u = Update.objects.values('nome_cliente').distinct()
        
        # 处理序列化问题
        backup_info = serializers.serialize('python', b)
        # 若只需要特定字段,也可以用values转列表:backup_info = list(b.values('end_time', 'id_cliente'))
        update_info = list(u)
        
        content = {"backup_info": backup_info, "update_info": update_info}
        
        # 消息提醒逻辑注意:AJAX请求中添加的messages不会直接在前端显示,需额外处理(比如在响应中返回消息内容)
        for cliente in Cliente.objects.all():
            now = time.time()
            min_time = now - 86400  # 最近24小时
            job_count = Jobs.objects.filter(
                id_cliente_id=cliente.id_cliente, 
                insert_time__range=(min_time, now)
            ).count()
            if job_count < cliente.n_jobs:
                messages.add_message(
                    request, 
                    messages.WARNING, 
                    f'Cliente {cliente.identificador} com menos {cliente.n_jobs - job_count} jobs!'
                )
        
        data = json.dumps(content)
        return HttpResponse(data, content_type='application/json')
    else:
        raise Http404

2. 优化后的模板代码(修复循环变量重名问题)

<div id="update">
  <div id="dash1div">
    <a href="">
      <strong>Updates</strong>
    </a>
  </div>
  <ul>
    {% for item in update_info %}
    <li>
      <a id="{{item.nome_cliente}}" href="/dashboard/ListUpdate/{{item.nome_cliente}}/">{{item.nome_cliente}}</a>
    </li>
    {% endfor %}
  </ul>
</div>

3. 改进后的AJAX代码(避免请求重叠)

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
// 用setTimeout替代setInterval,防止请求堆积
function refreshUpdateDiv() {
    console.log('正在刷新数据...');
    $.ajax({
        url: '/dashboard/ajax/reload_data/',
        success: function (data) {
            const response = JSON.parse(data);
            const updateList = $('#update ul');
            
            // 清空原有列表
            updateList.empty();
            // 重新渲染更新列表
            response.update_info.forEach(item => {
                const link = $('<a>')
                    .attr('id', item.nome_cliente)
                    .attr('href', `/dashboard/ListUpdate/${item.nome_cliente}/`)
                    .text(item.nome_cliente);
                const li = $('<li>').append(link);
                updateList.append(li);
            });
            
            // 处理backup_info的渲染逻辑可在此添加
            // 再次设置下一次刷新
            setTimeout(refreshUpdateDiv, 1000);
        },
        error: function() {
            // 请求失败后仍尝试刷新
            setTimeout(refreshUpdateDiv, 1000);
        }
    });
}

// 页面加载完成后启动刷新
$(document).ready(() => {
    refreshUpdateDiv();
});
</script>

关于定时刷新方式的优化建议

你当前使用setInterval的方式存在潜在风险:如果某个AJAX请求因网络延迟未及时完成,setInterval会继续发送新请求,导致请求堆积,增加服务器压力。

更优的方案选择:

  • 优先用setTimeout替代setInterval:就像上面的AJAX代码那样,在每次请求完成(成功或失败)后再设置下一次刷新,避免请求重叠。
  • 高实时性场景用WebSocket:如果你的项目需要数据变化后立即推送到前端,而非定时轮询,可以考虑使用Django Channels结合WebSocket实现双向通信,服务器主动推送更新,减少不必要的轮询请求,性能更优。

内容的提问来源于stack exchange,提问作者Micolho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:13:58