如何将Django中安全传递JSON数据到前端的最佳实践是什么?

2026-04-28 22:253阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计900个文字,预计阅读时间需要4分钟。

如何将Django中安全传递JSON数据到前端的最佳实践是什么?

相关专题内容如下:

本文讲解如何在 django 视图中正确序列化 python 数据为标准 json 字符串,并通过 html `data-*` 属性或 `json_script` 模板过滤器安全传递至前端 javascript,避免因单引号、未转义字符导致的 `json.parse()` 失败。

在 Django 开发中,常需将后端查询的数据(如用户体重记录)以结构化方式传给前端 JavaScript 进行图表渲染或动态交互。但直接使用 Python 字面量(如 [{...}, {...}])并插入 HTML data-* 属性中是危险且无效的——它输出的是 Python 的 repr() 字符串(含单引号、无转义),而非符合 RFC 8259 的标准 JSON,因此 JSON.parse() 会立即报错:SyntaxError: expected property name or '}'。

✅ 正确做法:始终使用 json.dumps() 生成合法 JSON 字符串
Django 不提供自动 JSON 序列化逻辑,必须显式调用 Python 标准库的 json.dumps()。它确保:

  • 使用双引号包裹键与字符串值;
  • 自动转义特殊字符(如换行、引号、反斜杠);
  • 输出 UTF-8 编码的纯文本(默认行为);
  • 支持 separators=(',', ':') 压缩空格(可选优化)。

修改后的视图代码如下:

import json # 推荐显式 import,更清晰 from django.core.paginator import Paginator from django.shortcuts import render, redirect from .models import WeightRecord, Profile from .forms import WeightLogForm 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) # ✅ 关键修正:用 json.dumps() 生成标准 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 # 此时已是合法 JSON 字符串 })

对应模板中,仍使用 |safe(因 json.dumps() 输出已为安全字符串,不含 HTML 特殊字符):

<div id="weight-data" data-weight-data="{{ weight_data|safe }}"></div>

前端 JavaScript 可安全解析:

立即学习“前端免费学习笔记(深入)”;

const weightDataElement = document.getElementById('weight-data'); const weightDataJSON = weightDataElement.getAttribute('data-weight-data'); const weightData = JSON.parse(weightDataJSON); // ✅ 现在完全合法 console.log(weightData); // [{weight: "122.00", entry_date: "2023-09-28"}, ...]

⚠️ 注意事项:

  • 永远不要手动拼接 JSON 字符串(如 '{' + ... + '}'),极易引入语法错误;
  • 若数据含非 ASCII 字符(如中文),json.dumps() 默认会转义为 \uXXXX;如需可读性,可加参数 ensure_ascii=False(但需确保响应编码为 UTF-8);
  • 对于大型数据集,避免在 HTML 中嵌入海量 JSON,考虑改用 API 异步加载(如 fetch('/api/weight-data/'));
  • Django 4.2+ 提供更优方案:|json_script 过滤器(推荐用于复杂/敏感数据)。它将数据写入 <script type="application/json"> 标签,天然规避 HTML 属性转义问题,且支持 XSS 防护:

<!-- 模板中 --> {{ weight_data|json_script:"weight-data" }}

// 前端 JS 中 const weightData = JSON.parse(document.getElementById('weight-data').textContent);

该方式无需 |safe,由 Django 自动处理转义与类型安全,是当前 Django 官方推荐的最佳实践。

本文共计900个文字,预计阅读时间需要4分钟。

如何将Django中安全传递JSON数据到前端的最佳实践是什么?

相关专题内容如下:

本文讲解如何在 django 视图中正确序列化 python 数据为标准 json 字符串,并通过 html `data-*` 属性或 `json_script` 模板过滤器安全传递至前端 javascript,避免因单引号、未转义字符导致的 `json.parse()` 失败。

在 Django 开发中,常需将后端查询的数据(如用户体重记录)以结构化方式传给前端 JavaScript 进行图表渲染或动态交互。但直接使用 Python 字面量(如 [{...}, {...}])并插入 HTML data-* 属性中是危险且无效的——它输出的是 Python 的 repr() 字符串(含单引号、无转义),而非符合 RFC 8259 的标准 JSON,因此 JSON.parse() 会立即报错:SyntaxError: expected property name or '}'。

✅ 正确做法:始终使用 json.dumps() 生成合法 JSON 字符串
Django 不提供自动 JSON 序列化逻辑,必须显式调用 Python 标准库的 json.dumps()。它确保:

  • 使用双引号包裹键与字符串值;
  • 自动转义特殊字符(如换行、引号、反斜杠);
  • 输出 UTF-8 编码的纯文本(默认行为);
  • 支持 separators=(',', ':') 压缩空格(可选优化)。

修改后的视图代码如下:

import json # 推荐显式 import,更清晰 from django.core.paginator import Paginator from django.shortcuts import render, redirect from .models import WeightRecord, Profile from .forms import WeightLogForm 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) # ✅ 关键修正:用 json.dumps() 生成标准 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 # 此时已是合法 JSON 字符串 })

对应模板中,仍使用 |safe(因 json.dumps() 输出已为安全字符串,不含 HTML 特殊字符):

<div id="weight-data" data-weight-data="{{ weight_data|safe }}"></div>

前端 JavaScript 可安全解析:

立即学习“前端免费学习笔记(深入)”;

const weightDataElement = document.getElementById('weight-data'); const weightDataJSON = weightDataElement.getAttribute('data-weight-data'); const weightData = JSON.parse(weightDataJSON); // ✅ 现在完全合法 console.log(weightData); // [{weight: "122.00", entry_date: "2023-09-28"}, ...]

⚠️ 注意事项:

  • 永远不要手动拼接 JSON 字符串(如 '{' + ... + '}'),极易引入语法错误;
  • 若数据含非 ASCII 字符(如中文),json.dumps() 默认会转义为 \uXXXX;如需可读性,可加参数 ensure_ascii=False(但需确保响应编码为 UTF-8);
  • 对于大型数据集,避免在 HTML 中嵌入海量 JSON,考虑改用 API 异步加载(如 fetch('/api/weight-data/'));
  • Django 4.2+ 提供更优方案:|json_script 过滤器(推荐用于复杂/敏感数据)。它将数据写入 <script type="application/json"> 标签,天然规避 HTML 属性转义问题,且支持 XSS 防护:

<!-- 模板中 --> {{ weight_data|json_script:"weight-data" }}

// 前端 JS 中 const weightData = JSON.parse(document.getElementById('weight-data').textContent);

该方式无需 |safe,由 Django 自动处理转义与类型安全,是当前 Django 官方推荐的最佳实践。