【Django】DRFでManyToManyフィールドを含むデータ更新でハマった点。

Django REST Frameworkを使って、ManyToManyフィールドを含むデータの更新をしようとしてハマったのメモ。

今回の課題

やりたいことは「投稿(Post)と一緒に、タグ(Tag: M2M)も更新すること」です。

ただ更新したいデータをDjango側で受け取った時に、validated_dataの「Tag」部分データが受け取れませんでした

送信したデータ

{
    "uuid":"af773f1b3184",
    "title":"「HTTPリクエスト/HTTPレスポンス」って何?",
    "tags":[
        {"id": 2},
    ]
}

Djangoで受け取ったデータ(validated_data

OrderedDict([
    ('tags', [OrderedDict()]),
    ('uuid', 'af773f1b3184'),
    ('title', '「HTTPリクエスト/HTTPレスポンス」って何?')
])

tagsのOrderedDict()の中身が空になってしまっています…。

今回のコード

Models.py

from django.db import models


class Tag(models.Model):
    name = models.CharField(blank=True, null=True, max_length=255)


class Post(models.Model):
    uuid = models.CharField(blank=True, null=True, max_length=255)
    title = models.CharField(blank=True, null=True, max_length=255)
    tags = models.ManyToManyField("Tag", through="PostTagRelation", blank=True, null=True) 


class PostTagRelation(models.Model):
    post = models.ForeignKey("Post", on_delete=models.CASCADE)
    tag = models.ForeignKey("Tag", on_delete=models.CASCADE)

Views

class PostUpdateView(generics.UpdateAPIView):
    queryset = Post.objects.prefetch_related('tags').all()
    serializer_class = PostUpdateSerializer
    permission_classes = (AllowAny,)
    lookup_field = 'uuid'

Serielizers

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = '__all__'


class PostUpdateSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True)

    class Meta:
        model = Post
        fields = '__all__'

解決法

TagSerializerのidをオーバーライドする(下記のように追記)ことで受け取ることができました。

TagSerializerのidがデフォルトでread_only = Trueになっていたようで、validated_dataに含まれなかったようです。

class TagSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(label='id')  # 追加(idをオーバーライド)

    class Meta:
        model = Post
        fields = '__all__'

コメントを残す

*