django中如何解析content-type=application/json的请求

django中如何解析content-type=application/json的请求

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!

往期文章回顾:

问题描述

主要问题

Django原生开发时,View视图里POST请求处理方法post里通过request.POST获取content-type=application/json类型的请求的请求体的结果为空字典{}

其他观察

  • 对于content-type=application/x-www-form-urlencoded类型的请求体能正常解析

  • 对于content-type=application/json类型的请求,调试发现request.body里包含请求的json字符串

  • 处理视图View的入参request的类型是django.core.handlers.wsgi.WSGIRequest

原因分析

综合分析上述问题和观察结果,猜测django在解析请求的时候根据content-type做了特殊区分处理

分析django源码,发现request.POST实际上是个property(POST = property(_get_post, _set_post))。

具体逻辑如下:

python 复制代码
    def _get_post(self):
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post

    def _set_post(self, post):
        self._post = post

而上述问题是查询的时候无法获取,因此继续跟踪_get_post方法,_load_post_and_files就是加载和解析post请求参数的主要逻辑,继承自django.http.request.HttpRequest

具体逻辑如下

python 复制代码
    def _load_post_and_files(self):
        """Populate self._post and self._files if the content-type is a form type"""
        if self.method != 'POST':
            self._post, self._files = QueryDict(encoding=self._encoding), MultiValueDict()
            return
        if self._read_started and not hasattr(self, '_body'):
            self._mark_post_parse_error()
            return

        if self.content_type == 'multipart/form-data':
            if hasattr(self, '_body'):
                # Use already read data
                data = BytesIO(self._body)
            else:
                data = self
            try:
                self._post, self._files = self.parse_file_upload(self.META, data)
            except MultiPartParserError:
                # An error occurred while parsing POST data. Since when
                # formatting the error the request handler might access
                # self.POST, set self._post and self._file to prevent
                # attempts to parse POST data again.
                # Mark that an error occurred. This allows self.__repr__ to
                # be explicit about it instead of simply representing an
                # empty POST
                self._mark_post_parse_error()
                raise
        elif self.content_type == 'application/x-www-form-urlencoded':
            self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
        else:
            self._post, self._files = QueryDict(encoding=self._encoding), MultiValueDict()

通过分析不难发现仅仅解析如下content-type的请求体

  • multipart/form-data- 也就是文件上传
  • application/x-www-form-urlencoded
  • 其他类型 - 返回空字典(这也就解释了为啥content-type=application/json时获取的是个空字典)

解决方案

当抽丝剥茧找到问题的根本原因时,解决方案也就来了,那就是 自己解析 😂,当然你也可以投入djangorestframework的怀抱,这是后话。

在构造form表单参数验证前,根据request.content_type == 'application/json'条件判断,满足的进行json字符串解析即可

方案示例

python 复制代码
def post(self, request, *args, **kwargs):
    if request.content_type == 'application/json':
        # 这里可以增加一些异常处理逻辑
        body = json.loads(request.body)
    else:
        body = request.POST
    # 创建form表单
    form = CustomForm(body)
    .... # 后续处理

One More Thing

授人以鱼不如授人以渔,本文以Django中POST请求处理时无法通过request.POST直接获取content-type=application/json的请求体的问题为例,系统地展示在Django开发中遇到问题时,该如何从现象排查、问题定位、原因分析到最终解决的完整方法论。

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!

相关推荐
Venuslite9 小时前
从 Unexpected token < 到 Extra data:一次讲清 JSON 解析错误的排查思路
json
兵慌码乱5 天前
面向桌面端的资产管理系统分层架构设计与核心模块实现
python·系统架构·sqlite·pyqt5·数据库设计·桌面应用开发·mvc架构
呱呱复呱呱5 天前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
兵慌码乱6 天前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
疯狂SQL7 天前
手写高性能在线 JSON 工具|Web Worker 工程化打包 + 语法自动修复 + 多语言代码生成实战
typescript·json·next.js·web worker·前端性能优化·esbuild·源码实战
伶俜6612 天前
鸿蒙原生应用实战(十八)ArkUI 记账本:SQLite 账单 + 图表统计 + 分类管理
jvm·sqlite·harmonyos
码云骑士12 天前
31-慢查询排查全流程(上)-Django-Debug-Toolbar与EXPLAIN入门
后端·python·django
龙腾AI白云12 天前
数字孪生和世界模型,二者的技术边界正在慢慢融合吗?
人工智能·django·知识图谱
terry60012 天前
5G视频短信服务商选型全攻略:通道资源、架构能力与成本评估2026最新标准
大数据·人工智能·5g·json·asp.net·信息与通信·数据库架构