7

I'm trying to validate empty fields in an endpoint by overwriting to_internal_value function and displaying an error message with ValidationError, very similar as the following answer:

serializer.py

def to_internal_value(self, data):
    missing = []
    for k in ['comments']:
        try:
            if data[k] == '':
                missing.append(k)
        except Exception as e:
            missing.append(k)
        if len(missing):
            raise serializers.ValidationError("The following fields are required: %s" % ','.join(missing))
    return data

The problem is that I get: Error: too many values to unpack (expected 2) when raise serializers.ValidationError instruction is executed and data is comming with comments field empty (''):

(Pdb) data
<QueryDict: {'csrfmiddlewaretoken': ['<csrfmiddlewaretoken>'], 'comments': [''], 'user': ['']}>

Even testing with a simple string:

raise serializers.ValidationError("The following fields are required: comments")

I receive the same error. In the python console, raise throw the error:

>>> from rest_framework.serializers import ValidationError
>>> from rest_framework import serializers
>>> data={'comments': [''], 'user': ['']}
>>> missing=[]
>>> missing.append('comments')
>>> raise serializers.ValidationError("The following fields are required: %s" % ','.join(missing))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
rest_framework.exceptions.ValidationError: [ErrorDetail(string='The following fields are required: comments', code='invalid')]

Instead of serializers.ValidationError() I had to use ValueError() and It works good, but I guess that it's not the suggested way.

Edit I was using:

Django==2.2.4
djangorestframework==3.10.3

Then I upgraded to:

Django==2.2.9
djangorestframework==3.11.0

With the same results.

halfer
  • 19,824
  • 17
  • 99
  • 186
Manuel Carrero
  • 599
  • 1
  • 9
  • 29
  • I couldn't reproduce your error (too many values to unpack). Raiseerror returns only `ValidationError: [ErrorDetail(string='The following fields are required: ', code='invalid')]` django 3.0.1, djangoframework 3.11.0 – shimo Jan 01 '20 at 01:06
  • I upgraded to ```djangorestframework==3.11.0``` but I received the same error. I updated my question adding the dict (data) that I receive from the DRF Api view – Manuel Carrero Jan 01 '20 at 18:39

2 Answers2

6

The reason this happens is that to_internal_value collects all the validation errors and passes them up as a dictionary, so that the resulting 400 response can include all the errors that were found rather than just the first one it hits. This should work:

def to_internal_value(self, data):
    missing = []
    for k in ['comments']:
        try:
            if data[k] == '':
                missing.append(k)
        except Exception as e:
            missing.append(k)
        if len(missing):
            raise serializers.ValidationError(
                {"The following fields are required": missing}
            )
    return data

That said, if all you're doing is validating that something is present, I'd suggest declaring required=True on the field in your serializer instead, and then DRF will do this check for you.

Charlotte Mays
  • 325
  • 4
  • 11
  • I tried with your answer but unfortunately I got the same result. I can't use just ```required=True``` because that validation does not force you to send the field if it is optional. At the end, I think that according with your answer, drf validators documentation needs an updated related with that error. – Manuel Carrero Jan 11 '20 at 17:33
5

The reason is that ValidationError raised inside run_validation should be created with dict, for example:

ValidationError(','.join(missing): "These field are required")
VsM
  • 51
  • 1
  • 2