Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transforming `ManyToManyField` in Django rest framework

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?

like image 850
Ram Rachum Avatar asked Nov 02 '22 04:11

Ram Rachum


1 Answers

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)
like image 142
zaphod100.10 Avatar answered Nov 15 '22 07:11

zaphod100.10