Given an OpenAPI specification that I'm writing code against that requires hyphen-case (aka kebab-case) variable names in request bodies, how should this be handled when using Django Rest Framework?
For example, a request POST /thing
to create a Thing has this body:
{
"owner-type": "platform"
}
But in Python, owner-type
is not a valid variable name ("SyntaxError: can't assign to operator"), so instead Thing
has owner_type
in the model definition:
class Thing(models.Model):
owner_type = models.CharField(max_length=8)
But now the ThingSerializer
is problematic because, again, owner-type
is an illegal name. This is not allowed:
owner-type = serializers.CharField(...)
I've tried to override how the names are generated in the ModelSerializer
by trying to adjust the field names generated by get_fields()
, but it failed. Here's my serializer:
class ThingSerializer(serializers.ModelSerializer):
class Meta:
model = Thing
fields = [
'owner_type',
]
def get_fields(self):
fields = super().get_fields()
out_fields = OrderedDict()
for field_name, field in fields.items():
out_fields[field_name.replace('_', '-')] = field
return out_fields
And the error:
../venv/lib/python3.6/site-packages/rest_framework/fields.py:453: in get_attribute
return get_attribute(instance, self.source_attrs)
../venv/lib/python3.6/site-packages/rest_framework/fields.py:101: in get_attribute
instance = getattr(instance, attr)
E AttributeError: 'Thing' object has no attribute 'owner-type'
So my question - how can I configure a DRF model serializer to allow a model's fields that contain underscore to be serialized / deserialized so that the API client sees hyphens instead of underscores? This would be a generic solution to the example above where Thing.owner_type
should be read / writeable by passing the field "owner-type"
in the JSON body.
I'm using latest Django and DRF on Python 3.6.
Edit 1: Clarified that ideally this would be a generic solution that translates underscores to hyphens.
Any 'read_only' fields that are incorrectly included in the serializer input will be ignored. Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
By default it is set to False. Setting it to True will allow you to mark the field as optional during "serialization". Note: required property is used for deserialization.
Serializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.
You can define field name with hyphen in fields
and map it to correct django model field by defining source
attribute in extra_kwargs
- see https://www.django-rest-framework.org/api-guide/serializers/#additional-keyword-arguments
To answer you question you define ThingSerializer
as bellow:
class ThingSerializer(serializers.ModelSerializer):
class Meta:
model = Thing
fields = [
'owner-type',
]
extra_kwargs = {
'owner-type': {'source': 'owner_type'},
}
You can use the to_internal_value
of Django(See in DJango Serializer fields) to get the key with the hyphens and rename it.
Example:
class Thing(models.Model):
owner_type = models.CharField(max_length=8)
def to_internal_value(self, data):
data['owner_type'] = data['owner-type']
data.pop('owner-type', None)
return data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With