wake-up-neo.com

Django-Rest-Framework 3.0 erstellen oder aktualisieren in verschachtelten Serializer

Mit Django-rest-framework 3. und diesen einfachen Modellen:

class Book(models.Model):
    title = models.CharField(max_length=50)


class Page(models.Model):
    book = models.ForeignKey(Books, related_name='related_book')
    text = models.CharField(max_length=500)

Und angesichts dieser JSON-Anfrage:

{
   "book_id":1,
   "pages":[
      {
         "page_id":2,
         "text":"loremipsum"
      },
      {
         "page_id":4,
         "text":"loremipsum"
      }
   ]
}

Wie kann ich einen verschachtelten Serializer schreiben, um diese JSON zu verarbeiten und für jedes page für das angegebene book entweder eine neue Seite zu erstellen oder zu aktualisieren, falls vorhanden.

class RequestSerializer(serializers.Serializer):
    book_id = serializers.IntegerField()
    page = PageSerializer(many=True)


class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page

Ich weiß, dass das Instanziieren des Serializers mit einem instance das aktuelle aktualisiert. Aber wie soll ich es in der create -Methode des verschachtelten Serializers verwenden?

70
norbertpy

Möchten Sie erstens das Erstellen neuer Buchinstanzen oder nur das Aktualisieren vorhandener Instanzen unterstützen?

Wenn Sie immer nur neue Buchinstanzen erstellen wollten, könnten Sie so etwas tun ...

class PageSerializer(serializers.Serializer):
    text = serializers.CharField(max_length=500)

class BookSerializer(serializers.Serializer):
    page = PageSerializer(many=True)
    title = serializers.CharField(max_length=50)

    def create(self, validated_data):
        # Create the book instance
        book = Book.objects.create(title=validated_data['title'])

        # Create or update each page instance
        for item in validated_data['pages']:
            page = Page(id=item['page_id'], text=item['text'], book=book)
            page.save()

        return book

Beachten Sie, dass ich noch nicht den book_id Hier angegeben habe. Beim Erstellen von Buchinstanzen wird keine Buch-ID angegeben. Bei der Aktualisierung von Buchinstanzen wird in der Regel die Buch-ID als Teil der URL und nicht in die Anforderungsdaten aufgenommen.

Wenn Sie das Erstellen und Aktualisieren von Buchinstanzen unterstützen möchten, müssen Sie sich überlegen, wie Sie Seiten behandeln möchten, die nicht in der Anforderung enthalten sind, aber sind, die derzeit der Buchinstanz zugeordnet sind.

Sie können diese Seiten ignorieren und so lassen, wie sie sind. Möglicherweise möchten Sie einen Überprüfungsfehler auslösen oder sie löschen.

Angenommen, Sie möchten alle Seiten löschen, die nicht in der Anforderung enthalten sind.

def create(self, validated_data):
    # As before.
    ...

def update(self, instance, validated_data):
    # Update the book instance
    instance.title = validated_data['title']
    instance.save()

    # Delete any pages not included in the request
    page_ids = [item['page_id'] for item in validated_data['pages']]
    for page in instance.books:
        if page.id not in page_ids:
            page.delete()

    # Create or update page instances that are in the request
    for item in validated_data['pages']:
        page = Page(id=item['page_id'], text=item['text'], book=instance)
        page.save()

    return instance

Möglicherweise möchten Sie auch nur Buchaktualisierungen und nicht die Erstellung unterstützen. In diesem Fall nur die Methode update() einschließen.

Es gibt auch verschiedene Möglichkeiten, wie Sie die Anzahl der Abfragen reduzieren können, z. Verwenden von Bulk-Erstellung/-Löschung, aber das oben Genannte erledigt die Aufgabe auf relativ einfache Weise.

Wie Sie sehen, gibt es Feinheiten in den Verhaltensweisen, die Sie beim Umgang mit verschachtelten Daten möglicherweise wünschen. Überlegen Sie sich daher genau, welches Verhalten Sie in verschiedenen Fällen erwarten.

Beachten Sie auch, dass ich im obigen Beispiel Serializer anstelle von ModelSerializer verwendet habe. In diesem Fall ist es einfacher, alle Felder explizit in die Serializer-Klasse aufzunehmen, als sich auf den automatischen Satz von Feldern zu verlassen, den ModelSerializer standardmäßig generiert.

95
Tom Christie

Sie können einfach drf-writable-nested verwenden. Es macht Ihre verschachtelten Serializer automatisch beschreibbar und aktualisierbar.

in Ihnen serializers.py:

from drf_writable_nested import WritableNestedModelSerializer

class RequestSerializer(WritableNestedModelSerializer):
    book_id = serializers.IntegerField()
    page = PageSerializer(many=True)


class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page

Und das ist es!

Die Bibliothek unterstützt auch nur die Verwendung einer der create - und update -Logiken, wenn Sie nicht beide benötigen.

0
Peter Sobhi