How to parse multipart/form-data from a put request in django

I want to submit a form to my backend and use the form data as the initial value for my form. Simple stuff if you are using a POST request:

def intervals(request, **kwargs):
  form = MyForm(initial=request.POST)

However, I am sending a form that should replace the current resource, which should idiomatically be a PUT request (I am using HTMX which allows you to do that). The problem is that I cannot find out how I can parse the form data from a put request. request.PUT does not exist and QueryDict only works for query params. What am I missing here?

The request.POST is constructed by a method:

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, TooManyFilesSent):
            # 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.
            self._mark_post_parse_error()
            raise
    elif self.content_type == "application/x-www-form-urlencoded":
        # According to RFC 1866, the "application/x-www-form-urlencoded"
        # content type does not have a charset and should be always treated
        # as UTF-8.
        if self._encoding is not None and self._encoding.lower() != "utf-8":
            raise BadRequest(
                "HTTP requests with the 'application/x-www-form-urlencoded' "
                "content type must be UTF-8 encoded."
            )
        self._post = QueryDict(self.body, encoding="utf-8")
        self._files = MultiValueDict()
    else:
        self._post, self._files = (
            QueryDict(encoding=self._encoding),
            MultiValueDict(),
        )

so essentially replace this, but then without the guard for self.method:

def load_post_and_files(request):
    if request._read_started and not hasattr(request, "_body"):
        request._mark_post_parse_error()
        return

    if request.content_type == "multipart/form-data":
        if hasattr(request, "_body"):
            # Use already read data
            data = BytesIO(request._body)
        else:
            data = request
        try:
            return request.parse_file_upload(request.META, data)
        except (MultiPartParserError, TooManyFilesSent):
            # An error occurred while parsing POST data. Since when
            # formatting the error the request handler might access
            # request.POST, set request._post and request._file to prevent
            # attempts to parse POST data again.
            request._mark_post_parse_error()
            raise
    elif request.content_type == "application/x-www-form-urlencoded":
        # According to RFC 1866, the "application/x-www-form-urlencoded"
        # content type does not have a charset and should be always treated
        # as UTF-8.
        if request._encoding is not None and request._encoding.lower() != "utf-8":
            raise BadRequest(
                "HTTP requests with the 'application/x-www-form-urlencoded' "
                "content type must be UTF-8 encoded."
            )
        return QueryDict(request.body, encoding="utf-8"), MultiValueDict()
    else:
        return = (
            QueryDict(encoding=request._encoding),
            MultiValueDict(),
        )

and thus work with:

def intervals(request, **kwargs):
  data, files = load_post_and_files(request)
  form = MyForm(initial=request.POST)

You can also use the Django REST framework, which does the parsing for all HTTP methods by essentially overriding the ._load_post_and_files() method, and then call a method named ._parse(..).

Вернуться на верх