Django Rest Framework, das viele zu viele Felder serialisiert

80

Wie serialisiere ich ein Viele-zu-Viele-Feld in eine Liste von etwas und gebe sie über das Rest-Framework zurück? In meinem Beispiel unten versuche ich, den Beitrag zusammen mit einer Liste der damit verbundenen Tags zurückzugeben.

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
kengcc
quelle
Mit Hilfe von @Brian gelingt es mir, die Elemente in dieser Form aufzulisten: "tags": [{"name": "tag1"}]. Ich möchte es vereinfachen, um es aufzulisten, ist es möglich: "tags": ["tag1", "tag2", ...]
kengcc
2
Verwenden Sie `tags = serializers.SlugRelatedField (many = True, read_only = True, slug_field = 'title', // Tag's Fireld, das Sie anzeigen möchten allow_null = True)` in PostSerializers
M. Dhaouadi

Antworten:

102

Sie benötigen eine TagSerializer, deren class Metahat model = Tag. Nach TagSerializererstellt wird, ändern die PostSerializermit many=Truefür eine ManyToManyFieldBeziehung:

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

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

Die Antwort ist für DRF 3

Brian
quelle
Es klappt!!! : D Haben Sie eine Idee, wie Sie diesen Serializer in eine durch Kommas getrennte Liste verwandeln können? Klasse TagSerializer (serializers.ModelSerializer): Klasse Meta: model = Tag fields = ('name')
kengcc
1
Im Moment bekomme ich: "tags": [{"name": "tag1"}] Ich möchte es vereinfachen zu: "tags": ["tag1", "tag2", ...]
kengcc
tags = serializers.ListField (source = 'tag'). Dadurch erhalten Sie die Liste der str- Darstellung jedes Objekts des Tags
Sachin Gupta
2
Was ist, wenn Sie das Tag über die Post aktualisieren möchten? (zB nicht read_only) Ich bekomme seltsames Verhalten, wenn ich read_only wegnehme und versuche, eine Aktualisierung des Tag-Feldes zu PATCHEN (ich erhalte eine Fehlermeldung über das bereits vorhandene Tag)
getup8
1
Der read_only=TrueTeil wird hier erklärt: django-rest-framework.org/api-guide/relations/…
Pavel Vergeev
23

Nehmen wir an, ein Buch kann mehr als einen Autor haben und ein Autor kann mehr als ein Buch haben: On Model:

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)

Auf Serialisierern:

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')
Jesus Almaral - Hackaprende
quelle
Irgendeine Idee, wie wir Autoren beim Erstellen einer Buchentität erstellen können?
Kishan Mehta
2
Ja, es muss in der Views-Klasse gemacht werden. Bitte posten Sie eine weitere Frage, wenn Sie eine detailliertere Antwort wünschen
Jesus Almaral - Hackaprende
7

Das Hinzufügen zu @ Brians Antwort "tags": [{"name": "tag1"}] kann auf folgende Weise zu "tags": ["tag1", "tag2", ...] vereinfacht werden:

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

Weitere Informationen hier: https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields

Candyfoxxx
quelle
4

Django 2.0

Für viele bis viele Bereiche, wenn Sie einen bestimmten möchten:

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',)
user5299374
quelle
Denn get_topics_listSie könnten vereinfachen, umreturn list(instance.topics.values_list('desc', flat=True))
bdoubleu
2

Das funktioniert bei mir.

tag = TagSerializer(source="tag", read_only=True, many=True)
Windsooon
quelle
2

In der Methode serializer on init können Sie das Abfrageset an das Feld übergeben und rest_framework die IDs auf diesem Abfrageset validieren

1) Erweitern Sie zuerst Ihren Serializer von Serializers.ModelSerializer

class YourSerializer(serializers.ModelSerializer):

2) Fügen Sie das Feld in die Metaklasse ein

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

3) in der init-Methode:

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

Sie können den Abfragesatz für dieses Feld unter einem beliebigen Argument mithilfe von Filter einschränken oder ausschließen, wie Sie es normalerweise tun. Wenn Sie alle einschließen möchten, verwenden Sie einfach .objects.all ()

yiyo
quelle
1

Die Standardeinstellung ModelSerializerverwendet Primärschlüssel für Beziehungen. Mit dem Meta depthAttribut können Sie jedoch problemlos verschachtelte Darstellungen erstellen:

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

Wie in der Dokumentation erwähnt :

Die depthOption sollte auf einen ganzzahligen Wert festgelegt werden, der die Tiefe der Beziehungen angibt, die durchlaufen werden sollen, bevor zu einer flachen Darstellung zurückgekehrt wird.

mohamed ali Mimouni
quelle