I've got a model with a field tool_class
, whose verbose name is class
and differs from name:
class Tool(models.Model):
tool_class = jsonfield.JSONField(verbose_name="class")
The Serializer and ViewSet are just stock HyperlinkedModelSerializer
and ModelViewSet
.
So, when I POST or PUT data to the server with a key class
, it is recognized fine:
'{"class": "..."}
but in the response data it is called tool_class
again:
{"tool_class": "..."}
How to make it be called class
always?
I can't use the name "class"
for the field name, as it is a reserved word in python, but in API it absolutely must be called "class"
, because the API conforms to a certain open standard, which specifies this word.
Obviously, I cannot say:
class = CharField(source="tool_class")
in my ToolSerializer
, because it's a SyntaxError: invalid syntax
.
SIMPLE SOLUTION:
Guys in another thread suggested a great solution. You can use vars()
syntax to circumvent this problem. For instance, I use the following code:
class Tool(Document):
vars()['class'] = mongoengine.fields.DictField(required=True)
Serializer creates respective field automatically. Ain't we sneaky?
I tried to find a way to have a field called
class
on the serializer, using some tricks withsetattr
, but it was getting very intrusive and hacky. Thefield_name
is collected from the field at the time of binding the field to the serializer, and there is no easy place to override the behaviour of the bind.In the end I decided it would be better and simpler just to let DRF do its thing, and add a post-processing step on the serializer:
Note that the data structure returned by
to_representation
is anOrderedDict
, and this disturbs the ordering slightly - the renamed key in this mapping will be removed from wherever it was at and pushed to the back.That is unlikely to be an issue for most use-cases, so you shouldn't bother to address it if not necessary. If you do need to preserve ordering, rebuild a new
OrderedDict
using a comprehension:You can do this by overriding the metaclass for Serializers. Here is an example of a
serializers.py
file.The main magic is this section of the metaclass
This takes any field you define in the serializer that ends in an underscore (ie.
field_
) and removes the underscore from the name when it binds theFields
and sets the_declared_fields
attribute on the serializer.