Alexandr Tatarinov
Alexandr Tatarinov

Reputation: 4034

DRF BooleanField in ModelSerializer causes IntegrityError

I am having trouble with my ModelSerializer

class Recall(models.Model):
    thermal_step = models.BooleanField()
    have_inventory = models.BooleanField()
    have_adverse = models.BooleanField()


class OrderRecallSerializer(serializers.ModelSerializer):
    class Meta:
        model = Recall
        fields = ['thermal_step', 'have_inventory', 'have_adverse']

s = OrderRecallSerializer(data={})
s.is_valid()
>>> True
s.save()
>>> django.db.utils.IntegrityError: null value in column 
"thermal_step" violates not-null constraint

In django BooleanField is always set to blank=True due to browsers don't send unchecked checkbox in POST data.

ModelForm sets model field to False in this case. When using DRF ModelSerializer, generated BooleanField is created with required=False, and when the field is not present in data, passed to serializer, model field is set to None and raises IntegrityError when saving model.

Should I explicitly specify BooleanField(default=False) in my ModelSerializer, or I am missing something? I would expect ModelSerializer to behave similar to ModelForm - set value to False when it is not present, which is equal to generating BooleanField with default=False automatically.

I think getting IntegrityError for default behaviour is not what expected, maybe I should submit a bug?

Upvotes: 1

Views: 1743

Answers (2)

codeadict
codeadict

Reputation: 2753

This was a bug in older versions of Django Rest Framework https://github.com/encode/django-rest-framework/issues/1004 but seems to be solved some time ago, probably you need to explicitly make it required in the serializer like:

class OrderRecallSerializer(serializers.ModelSerializer):
    class Meta:
        model = Recall
        fields = ['thermal_step', 'have_inventory', 'have_adverse']
        extra_kwargs = {
          'thermal_step': {'required': True, 'allow_null': False},
          'have_inventory': {'required': True, 'allow_null': False},
          'have_adverse': {'required': True, 'allow_null': False},
        }

Or what @bear-brown says is usually the best practice.

Upvotes: 0

user8060120
user8060120

Reputation:

When you use models.BooleanField it usually need to check is value True or not, so i think best practices always set default value for it. And set the default in the models class, for example in your case:

class Recall(models.Model):
    thermal_step = models.BooleanField(default=False)
    have_inventory = models.BooleanField(default=False)
    have_adverse = models.BooleanField(default=True)

Upvotes: 1

Related Questions