如何通过POST请求将Django对象从模板传递至视图并正确序列化?
解决Django复选框传递对象序列化无效JSON的问题
我尝试通过以下方式将复选框的值传递至views.py:
my_template.html
<input type="checkbox" name="playlist" value='{{ playlist }}'>
views.py
json_str_list = request.POST.getlist('playlist')
json_str_list中的序列化内容如下:
'{\'id\': \'UUkfDws3roWo1GaA3pZUzfIQ\', \'title\': "Item 1", \'created_on\': datetime.datetime(2023, 6, 12, 20, 44, 41, 392273, tzinfo=datetime.timezone.utc)}'
这显然不是有效的JSON字符串。我该如何调整Django中对象的序列化方式?
尝试用json.loads()反序列化为对象时,出现以下错误:
属性名必须用双引号包裹
你现在的问题出在直接把Django对象渲染到value属性里,这本质是调用了对象的__str__或__repr__方法,得到的不是标准JSON格式——不仅属性名用了单引号,datetime对象也保留了Python原生格式,自然无法被json.loads解析。
可以通过以下几种方式解决:
1. 在视图中预序列化对象,传递标准JSON字符串到模板
在渲染模板的视图里,用Django的序列化工具或者Python的json模块把对象转成标准JSON:
步骤1:修改视图(序列化对象)
from django.core import serializers import json from django.shortcuts import render def your_view(request): # 假设playlists是你要传递的查询集或单个对象 playlists = Playlist.objects.all() serialized_playlists = [] for playlist in playlists: # 用Django serializer转成字典,再补充id字段 data = serializers.serialize('python', [playlist])[0]['fields'] data['id'] = playlist.id # 将datetime转成ISO格式字符串,符合JSON规范 data['created_on'] = playlist.created_on.isoformat() # 转成标准JSON字符串 serialized_playlists.append(json.dumps(data)) return render(request, 'my_template.html', {'playlists': serialized_playlists})
步骤2:修改模板(渲染JSON字符串)
模板里直接使用序列化后的JSON字符串,用escapejs过滤器处理特殊字符,避免HTML渲染时出错:
{% for playlist_json in playlists %} <input type="checkbox" name="playlist" value="{{ playlist_json|escapejs }}"> {% endfor %}
2. 只传递对象ID,在后端重新查询(更简单高效)
如果不需要传递完整对象数据,只传ID是更轻量、安全的方案:
模板修改
<input type="checkbox" name="playlist_id" value="{{ playlist.id }}">
后端处理
playlist_ids = request.POST.getlist('playlist_id') # 根据ID批量查询对象 playlists = Playlist.objects.filter(id__in=playlist_ids)
这种方式避免了序列化/反序列化的麻烦,也不会把敏感数据暴露在前端。
3. 自定义模型的JSON序列化方法
如果需要频繁序列化该模型,可以在模型类中添加方法直接返回标准JSON:
import json from django.db import models class Playlist(models.Model): id = models.CharField(max_length=100, primary_key=True) title = models.CharField(max_length=200) created_on = models.DateTimeField(auto_now_add=True) def to_json(self): data = { 'id': self.id, 'title': self.title, 'created_on': self.created_on.isoformat() } return json.dumps(data)
然后在模板里直接调用:
<input type="checkbox" name="playlist" value="{{ playlist.to_json|escapejs }}">
为什么原来的方式不行?
直接渲染{{ playlist }}得到的是Python对象的字符串表示,和标准JSON有两个核心冲突:
- JSON要求属性名必须用双引号,而Python对象的字符串表示用单引号
datetime属于Python原生类型,无法被JSON直接解析,必须转成字符串格式(比如ISO格式)
内容的提问来源于stack exchange,提问作者CodeResearcher
相关产品推荐
相关产品推荐

