7
votes

I've got a model with a boolean field that I'd like to deserialize with the Django rest framework and I want the serializer to complain when a field is missing in the post request. Yet, it doesn't. It silently interprets a missing boolean as False.

class UserProfile(models.Model):
    """
     Message between two users
"""
     user = models.OneToOneField(User, verbose_name="django authentication user", related_name='user_profile')
     newsletter = models.BooleanField(null=False)
     research = models.BooleanField(null=False)

The model is created with a Serialiser like this:

 class UserProfileSerializer(serializers.ModelSerializer):
 research = BooleanField(source='research', required=True)
 newsletter = BooleanField(source='newsletter', required=True)

 class Meta:
    model = UserProfile
    fields = ('research', 'newsletter')

In my view I'm also creating a user, so I have some manual steps:

 def post(self, request, format=None):
    userprofile_serializer = UserProfileSerializer(data=request.DATA)
    reg_serializer = RegistrationSerializer(data=request.DATA)
    phone_serializer = PhoneSerializer(data=request.DATA)


    errors = {}
    if userprofile_serializer.is_valid() and reg_serializer.is_valid() and phone_serializer.is_valid():
        user = reg_serializer.save()
        data = reg_serializer.data

        user_profile = userprofile_serializer.object
        user_profile.user = user
        userprofile_serializer.save()

        return Response(data, status=status.HTTP_201_CREATED)

    errors.update(reg_serializer.errors)
    # ...
    return Response(errors, status=status.HTTP_400_BAD_REQUEST)

However, the following test case fails, because the rest framework doesn't complain about the missing param but instead inserts a False in from_native

     def test_error_missing_flag(self):
    data = {'username': "test", 'password': "123test", 'email': '[email protected]',
            'newsletter': 'true', 'uuid': self.uuid}

    response = self.client.post(reverse('app_register'), data)
    # should complain that 'research' is not found
    self.assertTrue('research' in response.data)

If I replace my 'research' field with an Integer field that the serializer fails as expected. Any ideas?

4

4 Answers

3
votes

There was an issue with Boolean fields and the required argument. Should now be fixed in master.

See this issue: https://github.com/tomchristie/django-rest-framework/issues/1004

1
votes

Add

your_field = serializers.NullBooleanField(required=False)

in serializer.

That's it. It'll work :)

1
votes

Create a new custom class:

from rest_framework import serializers

class RequirableBooleanField(serializers.BooleanField):
    default_empty_html = serializers.empty

Now, you can use:

research = RequirableBooleanField(required=True)

or

research = RequirableBooleanField(required=False)
0
votes

For anyone who has read @Tom's accepted answer from 2013 and finds that this still doesn't work, it's because this behavior is intended for HTML form inputs. Here's the original issue.

To use serializers.BooleanField with a JSON payload, convert your request.POST to a Python dict by doing request.POST.dict() and pass it to your serializer while initializing.