1
votes

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?

2
use models.NullBooleanField() or models.BooleanField(required=False, null=True, default=False)alfonso.kim
@alfonso.kim I don't need to store null values and I think specifiying null=True for BooleanField is wrong idea. Also, required is wrong argument for models.BooleanField. Maybe best answer would be to always set default=False for BooleanField...Alexandr Tatarinov

2 Answers

1
votes

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)
0
votes

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.