Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating m2m not possible when using serializers as fields

I have following models:

class Song(models.Model):
    name = models.CharField(max_length=64)

    def __unicode__(self):
        return self.name

class UserProfile(AbstractUser):
    current = models.ManyToManyField(Song, related_name="in_current", blank=True)
    saved = models.ManyToManyField(Song, related_name="in_saved", blank=True)
    whatever = models.ManyToManyField(Song, related_name="in_whatever", blank=True)

    def __unicode__(self):
        return self.get_username()

and following serializers:

class SongSerializer(serializers.ModelSerializer):
    class Meta:
        model = Song

class UserProfileSongsSerializer(serializers.ModelSerializer):
    current = SongSerializer(many=True)
    saved = SongSerializer(many=True)
    whatever = SongSerializer(many=True)

    class Meta:
        model = UserProfile
        fields = ("id", "current", "saved", "whatever")

and am using UpdateAPIView as such:

class UserProfileSongsUpdate(generics.UpdateAPIView):
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSongsSerializer

The problem: I can't add a song (even if it already exists in the DB) to any of (current, saved, whatever), I can only remove it.

curl -X PUT -d '{"current": [{"id": 1, "name": "sialalalal"}, {"id": 2, "name": "imissmykitty"}], "saved": [{"id": 3, "name": "kittyontheroad"}], "whatever": []}' -H "Content-Type:application/json" localhost:8000/userprofile/1/songs/update/

This will remove all of the other songs in current collection (that's good :)), but when I'll try to add already existing song to the current collection it will show me an error:

curl -X PUT -d '{"current": [{"id": 1, "name": "sialalalal"}, {"id": 2, "name": "imissmykitty"}, {"id": 7, "name": "vivalakita"}], "saved": [{"id": 3, "name": "kittyontheroad"}], "whatever": []}' -H "Content-Type:application/json" localhost:8000/userprofile/1/songs/update/

I get:

{"current": [{}, {}, {"non_field_errors": ["Cannot create a new item, only existing items may be updated."]}]}

BUT! if I remove serializers fields:

class UserProfileSongsSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserProfile
        fields = ("id", "current", "saved", "whatever")

and I do:

curl -X PUT -d '{"current": [1, 2, 7], "saved": [3], "whatever": []}' -H "Content-Type:application/json" localhost:8000/userprofile/1/songs/update/

it adds the song without any issues...

Can I add and remove songs from collections like current and saved using serializers as fields?

like image 865
marwy Avatar asked Mar 21 '23 11:03

marwy


1 Answers

Yes you can. you need to set allow_add_remove to True and read_only to False:

current = SongSerializer(many=True, allow_add_remove=True, read_only=False)

Note that the current implementation of nested serializers will remove the whole Song object from DB, not only the relation.

like image 159
almalki Avatar answered Apr 20 '23 01:04

almalki