django-parler-rest icon indicating copy to clipboard operation
django-parler-rest copied to clipboard

"Input is not a valid dict" when posting to a model with file attribute

Open GuillaumeCisco opened this issue 7 years ago • 7 comments

Hello I've just detected that we get the error :

"Input is not a valid dict"

when posting with requests.post with a files attribute. the file attribute will force the request as a multipart formencoded, so the data will be json stringified.

I've created a pull request for handling this behavior. https://github.com/django-parler/django-parler-rest/pull/20

GuillaumeCisco avatar Jun 23 '17 17:06 GuillaumeCisco

Thanks for the PR! As mentioned in #20, do you have an example how to cause this error? For example, a curl command or Django unit test?

vdboor avatar Jul 04 '17 10:07 vdboor

Yes I was using a curl command like: curl -H "Content-Type:multipart/form-data" -F translations="{\"en\": {\"display_name\": \"toto\"}}" -F name="test" -F type="3" -F "file=@./toto;type=application/json" http://my_domain.com/my_ressource/

GuillaumeCisco avatar Jul 04 '17 11:07 GuillaumeCisco

Hi. This issue still exists - is there any update regarding this error?

crstian avatar Apr 08 '20 15:04 crstian

What I did to make it work was using json.loads(data) to format the submitted form data. Unfortunately django-parler is checking for isinstance(data, dict) (line 128, here) which returns false on JavaScript objects that where submitted by form data and previous stringified with json.stringify.

Hope this helps someone.

crstian avatar Sep 25 '20 07:09 crstian

Really helpful @crstian . I had the same issue and solved quickly with your solution !

MehdiDRISSIB avatar Jun 23 '21 11:06 MehdiDRISSIB

I have added the change that was done by @GuillaumeCisco but the code doesn't appear to work: Is there anything I am doing wrong?

    ...
 if isinstance(data, str):
     # try to convert to json
     try:
         data = json.loads(data)
      except:
          self.fail('invalid_json_dump')
    ...

EliasOPrado2 avatar Aug 25 '21 20:08 EliasOPrado2

You should overload TranslatedFieldsField and call the overloaded class in your serializer like this:

import json
from parler_rest.fields import TranslatedFieldsField
from rest_framework import serializers


class TranslatedFieldFixed(TranslatedFieldsField):

    def to_internal_value(self, data):
        """
        Deserialize data from translations fields.
        For each received language, delegate validation logic to
        the translation model serializer.
        """
        if data is None:
            return
        data = json.loads(data)
        if not isinstance(data, dict):
            self.fail('invalid')
        if not self.allow_empty and len(data) == 0:
            self.fail('empty')

        result, errors = {}, {}
        for lang_code, model_fields in data.items():
            serializer = self.serializer_class(data=model_fields)
            if serializer.is_valid():
                result[lang_code] = serializer.validated_data
            else:
                errors[lang_code] = serializer.errors

        if errors:
            raise serializers.ValidationError(errors)
        return result

But It would be best if the error is fixed directly in the library

MehdiDRISSIB avatar Mar 06 '23 23:03 MehdiDRISSIB