'Django Rest Framework ignoring custom field
I have a model with a nullable boolean field that I'd like to have serialized in a way that converts null in the output to false.
My model:
class UserPreferences(models.Model):
receive_push_notifications = models.BooleanField(
null=True, blank=True,
help_text=("Receive push notifications))
I'm trying to do it with a custom field like so:
class StrictlyBooleanField(serializers.Field):
def to_representation(self, value):
# Force None to False
return bool(value)
def to_internal_value(self, data):
return bool(data)
class UserPreferencesSerializer(serializers.ModelSerializer):
class Meta(object):
model = UserPreferences
fields = ('receive_push_notifications',)
receive_push_notifications = StrictlyBooleanField()
but this isn't working, I'm still seeing null in my API responses.
I think I must be missing something simple in wiring it up because I don't even get an error if I replace my to_representation with:
def to_representation(self, value):
raise
DRF doesn't seem to be calling my method at all... What am I missing here?
Solution 1:[1]
Explanation
After looking into rest framework's Serializer's to_representation method, you will find that it iterates through all of the fields and calls field.get_attribute method for each field. If the value returned from that method is None it skips calling field.to_representation entirely and set None as the field value.
# Serializer's to_representation method
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
Solution
Override field.get_attribute by calling super().get_attribute and return False if the value is None
class StrictlyBooleanField(serializers.Field):
def get_attribute(self, instance):
attribute = super().get_attribute(instance)
return bool(attribute)
def to_representation(self, value):
return value
def to_internal_value(self, data):
return bool(data)
Solution 2:[2]
You can just write a simple function inside your serializer
class UserPreferencesSerializer(serializers.ModelSerializer):
yourField = serializers.SerializerMethodField(read_only=True)
class Meta(object):
model = UserPreferences
fields = ['receive_push_notifications', 'yourField']
def get_yourField(self, obj):
if obj.receive_push_notifications == null:
return False
else:
return True
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | shaswat kumar |
