多対多のフィールドをシリアル化するDjangoRESTフレームワーク


84

多対多のフィールドを何かのリストにシリアル化し、残りのフレームワークを介してそれらを返すにはどうすればよいですか?以下の例では、投稿に関連付けられているタグのリストと一緒に投稿を返そうとしています。

models.py

class post(models.Model):
    tag = models.ManyToManyField(Tag)
    text = models.CharField(max_length=100)

serializers.py

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag"??)

views.py

class PostViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

@Brianの助けを借りて、私はなんとか次の形式でアイテムをリストすることができます: "tags":[{"name": "tag1"}]。リストに簡略化したいと思いますが、可能ですか: "tags":["tag1"、 "tag2"、...]
kengcc 2015年

2
PostSerializersで `tags = serializers.SlugRelatedField(many = True、read_only = True、slug_field = 'title'、// tag's fireld you want to show allow_null = True)`を使用する
M. Dhaouadi 2017

回答:


105

あなたは必要になりますTagSerializer、そのclass Meta持っていますmodel = Tag。後TagSerializerに作成され、変更PostSerializerしてmany=TrueのためのManyToManyField関係:

class PostSerializer(serializers.ModelSerializer):
    tag = TagSerializer(read_only=True, many=True)

    class Meta:
        model = Post
        fields = ('tag', 'text',)

答えはDRF3用です


できます!!!:Dこのシリアライザーをコンマ区切りのリストに変換する方法はありますか?class TagSerializer(serializers.ModelSerializer):class Meta:model = Tag fields =( 'name')
kengcc 2015年

1
今、私は次のようになります: "tags":[{"name": "tag1"}]単純化して: "tags":["tag1"、 "tag2"、...]
kengcc

タグ= serializers.ListField(source = 'tag')。これにより、タグの各オブジェクトのstr表現のリストが表示されます
Sachin Gupta

2
投稿を通じてタグを更新できるようにしたい場合はどうなりますか?(例:read_onlyではない)read_onlyを削除し、タグフィールドの更新をパッチしようとすると、奇妙な動作が発生します(タグが既に存在するというエラーが発生します)
getup8 2016

1
read_only=True一部には、ここで説明されていますdjango-rest-framework.org/api-guide/relations/...
パベルVergeev

25

これは私がしたことです。1つの本に複数の著者を含めることができ、1人の著者に複数の本を含めることができると仮定しましょう。

class Author(models.Model):
    name = models.CharField(max_length=100, default="")
    last_name = models.IntegerField(default=0)

class Book(models.Model):
    authors = models.ManyToManyField(Author, related_name="book_list", blank=True)
    name = models.CharField(max_length=100, default="")
    published = models.BooleanField(default=True)

シリアライザーについて:

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True)

    class Meta:
        model = Book
        fields = ('id', 'name', 'published', 'authors')


class AuthorSerializer(serializers.ModelSerializer):
    book_list = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ('id', 'name', 'last_name', 'book_list')

Bookエンティティの作成時に著者を作成するにはどうすればよいですか?
KishanMehta19年

2
はい、Viewsクラスで行う必要があります。より詳細な回答が必要な場合は、別の質問を投稿してください
Jesus Almaral –Hackaprende19年

8

@Brianの回答に "tags":[{"name": "tag1"}]を追加すると、次のように "tags":["tag1"、 "tag2"、...]に簡略化できます。

class PostSerializer(serializers.ModelSerializer):
    tag = TagSerializer(read_only=True, many=True)

    class Meta:
        ...

class TagSerializer(serializers.RelatedField):

     def to_representation(self, value):
         return value.name

     class Meta:
        model = Tag

詳細はこちら:https//www.django-rest-framework.org/api-guide/relations/#custom-relational-fields


4

これは私にとってはうまくいきます。

tag = TagSerializer(source="tag", read_only=True, many=True)

4

Django 2.0

多対多の分野で、特定の分野が必要な場合:

class QuestionSerializer(serializers.ModelSerializer):

    topics_list = serializers.SerializerMethodField()

    def get_topics_list(self, instance):
        names = []
        a = instance.topics.get_queryset()
        for i in a:
            names.append(i.desc)
        return names
    class Meta:
        model = Question
        fields = ('topics_list',)

get_topics_listあなたはに簡素化することができreturn list(instance.topics.values_list('desc', flat=True))
bdoubleu

2

上のシリアライザでのinitメソッドあなたはフィールドにクエリセットを渡すことができますし、そのクエリセットにヴァリデIDをrest_framework

1)最初にserializers.ModelSerializerからシリアライザーを拡張します

class YourSerializer(serializers.ModelSerializer):

2)メタクラスにフィールドを含める

class YourSerializer(serializers.ModelSerializer):
  class Meta:
        fields = (..., 'your_field',)

3)initメソッドの場合:

def __init__(self, *args, **kwargs):
    super(YourSerializer, self).__init__(*args, **kwargs)
    self.fields['your_field].queryset = <the queryset of your field>

フィルタを使用して任意の引数の下でそのフィールドのクエリセットを制限したり、通常どおりに除外したりできます。すべてを含めたい場合は、.objects.all()を使用してください。


1

デフォルトでModelSerializerは、関係に主キーが使用されます。ただし、次のMeta depth属性を使用して、ネストされた表現を簡単に生成できます。

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag")
        depth = 1 

ドキュメントに記載されているように

このdepthオプションは、フラットな表現に戻す前にトラバースする必要がある関係の深さを示す整数値に設定する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.