I'm using Django-rest-framework to build an API. I have a model Chair
I'm building a viewset for. It has a ManyToManyField
to a model Tag
, so each chair has multiple tags.
Tag
is a Django model, but when interacting with the API, I don't want to see a JSON dict for each tag; I just want to use the name of the tag.
E.g. when viewing a Chair
in the API, I want to see it has this:
{
'tags': ['meow', 'frrr', 'nutella'],
... Any other chair attributes
}
And similarly, when I create a Chair
, I want to be able to pass in a list of tag names, and then for each of them do get_or_create
by that name. (So I'm either using the existing tag with that name, or creating a new one.)
How do I put all of this logic into my serializer/viewset?
define your tag field in the serializer as this:
tags = serializers.SlugRelatedField(slug_field='name', many=True)
Now for the get_or_create behaviour my suggestion will be to use a django form. You will have to override the post method (or create method if you are using a viewset) and write a normal django method for creating stuff using forms.
Look at request.DATA it is a normal python dictionary, use it as the data for your chair form.
The form will accept this data and then you can validate the data normally, as you would with a django form.
Then create a chair instance using:
chair = form.save(commit=False)
chair.save()
Once you have the chair instance with you now you can add as many tags using:
chair.tags.add(tag1, tag2, tag3...)
To get the tags as python objects take out the list of tag names from the request.DATA dict and pass the names to the get_or_create function. You can do something like:
tags = []
tags_name_list = request.DATA['tags']
for tag_name in tags_name_list:
tag = Tag.objects.get_or_create(name=tag_name)
tags.append(tag)
Now you have the list of tags with you. Add them to chair:
chair.tags.add(*tags)
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