手撸drf中Request对象的data属性实现原理

django基础中提交post请求有两种方式:form表单;ajax提交数据。其中:form表单可以提交的数据可是有两种:urlencoded和form-data;ajax可以提交的数据有三种,除了urlencoded和form-data,还支持json格式的数据。

我们清楚的知道urlencoded格式的数据会被django封装到request.POST字典中,文件数据会被django封装到request.FILES中;而json数据比较特殊,django没有帮我们封装,而是原封不动的保存在request.body中,需要我们手动从请求体中自己反序列化取出。

django的drf框架,帮我们优化了这个取数据的方式,统一一个取数据的接口Request.data,即不论是json数据还是文件数据还是普通的在request.POST的数据,都统一从request.data中取出。

其实原理很简单,我们在中间件中,将数据统一取出并处理然后赋值给request的自定义data属性

import json
from django.utils.deprecation import MiddlewareMixin


class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # print(request)
        if not request.POST:
            if request.is_ajax():
                request.data = json.loads(request.body)
        else:
            request.data = dict(request.POST)		# 因为QueryDict是不可变字典,另一种解决方式是使用QueryDict的内置copy方法,实现深拷贝并且拷贝后的字典可以修改。
            request.data.update(request.FILES)		# 将文件数据也放在request.data中

补充:另一种解决方式,异常捕获

import json
from django.utils.deprecation import MiddlewareMixin

class JsonMiddel(MiddlewareMixin):
    def process_request(self, request):
        try:
            request.data=json.loads(request.body)
        except Exception as e:
            request.data=request.POST

注意点:

  • form表单和ajax同时提交的bug:将form标签中input的submit类型和button按钮绑定了ajax事件。这样的结果是触发了两次提交请求:form表单的和ajax的请求。避免的办法是不要给这两个标签绑定ajax请求,或者使用input的submit类型绑定ajax,则不会触发表单的数据提交。
  • QueryDict是一个特殊的字典,它内部继承dict,但QueryDict是一个不可变字典无法修改。如果需要修改它可以使用其内置的copy()方法。
  • CommonMiddleware中间件控制了是否重定向到带/的地址
def should_redirect_with_slash(self, request):
        """
        Return True if settings.APPEND_SLASH is True and appending a slash to
        the request path turns an invalid path into a valid one.
        """
        if settings.APPEND_SLASH and not request.path_info.endswith('/'):
            urlconf = getattr(request, 'urlconf', None)
            return (
                not is_valid_path(request.path_info, urlconf) and
                is_valid_path('%s/' % request.path_info, urlconf)
            )
        return False
posted @ 2020-07-01 17:26  the3times  阅读(846)  评论(0编辑  收藏  举报