2014-12-11 19 views
61

Z django-rest-framework 3.0 i posiadające te proste modele:django-rest-framework 3.0 tworzenia lub aktualizacji w zagnieżdżonych serializatora

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) 

A biorąc pod uwagę to żądanie JSON:

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

Jak napisać zagnieżdżony serializer, aby przetworzyć ten JSON i dla każdego page dla danego book albo utworzyć nową stronę lub aktualizację, jeśli istnieje.

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


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

wiem, że utworzenie wystąpienia serializatora z instance zaktualizuje aktualny jednym, ale w jaki sposób należy go używać wewnątrz metody zagnieżdżonych serializatora create?

Odpowiedz

84

Po pierwsze, czy chcesz wesprzeć tworzenie nowych instancji książek, czy tylko aktualizować istniejące?

Jeśli tylko kiedykolwiek chciał stworzyć nowe instancje książki można zrobić coś takiego ...

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 

pamiętać, że nie obejmowały book_id tutaj. Podczas tworzenia instancji książek nie będziemy uwzględniać identyfikatora książki. Gdy aktualizujemy instancje książek, zazwyczaj podajemy identyfikator książki jako część adresu URL, a nie w danych żądania.

Jeśli chcesz obsługiwać tworzenie i aktualizowanie instancji książek, musisz zastanowić się, w jaki sposób obsługiwać strony, które nie są zawarte w żądaniu, ale są obecnie powiązane z instancją książki.

Możesz zignorować te strony i pozostawić je w niezmienionej postaci, możesz zgłosić błąd sprawdzania poprawności lub możesz je usunąć.

Załóżmy, że chcesz usunąć wszystkie strony nieuwzględnione w żądaniu.

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 

Jest również możliwe, że chcesz tylko aktualizacjach książki wsparcie, a nie wspierać tworzenie, w którym to przypadku, tylko obejmują metodę update().

Istnieje również wiele sposobów na zmniejszenie liczby zapytań, np. przy użyciu zbiorczego tworzenia/usuwania, ale powyższe czynności byłyby wykonywane w dość prosty sposób.

Jak widać, istnieją subtelności w typach zachowań, które mogą być przydatne w przypadku zagnieżdżonych danych, więc należy dokładnie przemyśleć, jakiego zachowania oczekuje się w różnych przypadkach.

Należy również zauważyć, że użyłem w powyższym przykładzie Serializer zamiast ModelSerializer. W takim przypadku prostsze jest tylko jawne uwzględnienie wszystkich pól w klasie serializera, zamiast polegania na automatycznym zestawie pól generowanych domyślnie przez ModelSerializer.

+1

'może chcesz tylko wspierać aktualizacje książek ..., dołącz tylko metodę update()". W takim przypadku, w jaki sposób metoda "instancji" w aktualizacji zostanie wypełniona istniejącą książką? – norbertpy

+0

Poprzez utworzenie instancji serializatora za pomocą argumentu słowa kluczowego "instancja". Zwykle otrzymasz to, wykonując wyszukiwanie oparte na kluczu podstawowym w adresie URL. Jeśli używasz ogólnych widoków, które będą dla Ciebie obsługiwane. Spójrz na DetailMixin w "mixins.py" na potrzeby implementacji tego. –

+1

Dzięki Tom. Mam to teraz. – norbertpy

Powiązane problemy