Django序列化数据传递问题:单引号致JSON解析失败
问题描述
在Django项目的个人主页中,尝试将体重记录数据集传递到前端,输出的数据使用单引号而非JSON要求的双引号,导致执行JavaScript的JSON.parse()时抛出语法错误。
相关代码与错误信息
View代码
def profile_page(request): if request.method == 'POST': form = WeightLogForm(request.POST) if form.is_valid(): weight_log = form.save(commit=False) weight_log.profile = Profile.objects.get(user=request.user) weight_log.save() return redirect('profile') else: form = WeightLogForm() user_weight_log = WeightRecord.objects.filter(profile__user=request.user).order_by('-entry_date') paginator = Paginator(user_weight_log, 10) page = request.GET.get('page') try: user_weight_log = paginator.page(page) except PageNotAnInteger: user_weight_log = paginator.page(1) except EmptyPage: user_weight_log = paginator.page(paginator.num_pages) serialized_data = [{'weight': str(record.weight), 'entry_date': record.entry_date.strftime('%Y-%m-%d')} for record in user_weight_log] return render(request, 'profile.html', { 'user_weight_log': user_weight_log, 'form': form, 'weight_data': serialized_data })
HTML模板代码
<div id="weight-data" data-weight-data="{{ weight_data|safe }}"></div>
前端输出的数据
[{'weight': '122.00', 'entry_date': '2023-09-28'}, {'weight': '123.00', 'entry_date': '2023-09-18'}, {'weight': '44.00', 'entry_date': '2023-09-15'}, {'weight': '85.00', 'entry_date': '2023-09-06'}, {'weight': '11.00', 'entry_date': '2023-09-06'}, {'weight': '12.00', 'entry_date': '2023-09-05'}, {'weight': '17.00', 'entry_date': '2023-09-05'}, {'weight': '44.00', 'entry_date': '2023-08-08'}, {'weight': '17.00', 'entry_date': '2023-06-08'}, {'weight': '33.00', 'entry_date': '2023-06-07'}]
JavaScript代码
var weightDataElement = document.getElementById('weight-data'); var weightDataJSON = weightDataElement.getAttribute('data-weight-data'); var weightData = JSON.parse(weightDataJSON);
报错信息
Uncaught SyntaxError: JSON.parse: expected property name or '}' at line 1 column 3 of the JSON data
问题原因
Python中字典和列表转换为字符串时默认使用单引号,而JSON规范要求必须使用双引号,因此JSON.parse()无法识别该格式。
解决方案
方法一:使用json.dumps生成标准JSON字符串
- 在View中导入
json模块,将数据序列化为标准JSON字符串:
import json # ... 保留原有代码 ... serialized_data = json.dumps([ {'weight': str(record.weight), 'entry_date': record.entry_date.strftime('%Y-%m-%d')} for record in user_weight_log ]) return render(request, 'profile.html', { 'user_weight_log': user_weight_log, 'form': form, 'weight_data': serialized_data })
- 模板中保留
|safe过滤器,确保输出不被转义:
<div id="weight-data" data-weight-data="{{ weight_data|safe }}"></div>
方法二:使用Django内置的json_script模板标签(推荐)
该方法无需手动序列化,且能自动处理XSS防护,更安全可靠:
- View中无需修改
serialized_data,保持原有的列表字典结构:
# ... 原有代码不变 ... serialized_data = [{'weight': str(record.weight), 'entry_date': record.entry_date.strftime('%Y-%m-%d')} for record in user_weight_log] return render(request, 'profile.html', { 'user_weight_log': user_weight_log, 'form': form, 'weight_data': serialized_data })
- 修改HTML模板,使用
json_script标签输出数据:
{% json_script "weight_data" %}
- 调整JavaScript代码,通过元素文本内容获取并解析JSON:
const weightData = JSON.parse(document.getElementById('weight_data').textContent);
内容的提问来源于stack exchange,提问作者Urek

