IT박스

django-rest-framework 3.0 중첩 직렬 변환기에서 생성 또는 업데이트

itboxs 2020. 11. 2. 07:46
반응형

django-rest-framework 3.0 중첩 직렬 변환기에서 생성 또는 업데이트


장고 - 나머지 프레임 워크 3.0 와 가진 간단한 모델 :

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)

그리고이 JSON 요청이 주어지면 :

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

이 JSON을 처리 page하고 주어진 각각에 대해 book새 페이지를 만들거나 존재하는 경우 업데이트 하는 중첩 직렬 변환기를 작성하려면 어떻게해야합니까 ?

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


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

직렬 변환기를 인스턴스화하면 instance현재 직렬 변환기 가 업데이트 된다는 것을 알고 있지만 create중첩 직렬 변환기 메서드 내에서 어떻게 사용해야 합니까?


첫째, 새 도서 인스턴스 생성을 지원 하시겠습니까, 아니면 기존 도서 인스턴스 만 업데이트 하시겠습니까?

새 책 인스턴스 만 만들고 싶었다면 다음과 같이 할 수 있습니다.

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

Note that I haven't included the book_id here. When we're creating book instances we won't be including a book id. When we're updating book instances we'll typically include the book id as part of the URL, rather than in the request data.

If you want to support both create and update of book instances then you need to think about how you want to handle pages that are not included in the request, but are currently associated with the book instance.

You might choose to silently ignore those pages and leave them as they are, you might want to raise a validation error, or you might want to delete them.

Let's assume that you want to delete any pages not included in the request.

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

It's also possible that you might want to only support book updates, and not support creation, in which case, only include the update() method.

There are also various ways you could reduce the number of queries eg. using bulk create/deletion, but the above would do the job in a fairly straightforward way.

As you can see there are subtleties in the types of behavior you might want when dealing with nested data, so think carefully about exactly what behavior you're expecting in various cases.

Also note that I've been using Serializer in the above example rather than ModelSerializer. In this case it's simpler just to include all the fields in the serializer class explicitly, rather than relying on the automatic set of fields that ModelSerializer generates by default.


You can simply use drf-writable-nested. It automatically make your nested serializers writable and updatable.

in you 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

And that's it!

Also the library supports using only one of the create and update logics if you don't need both.

참고URL : https://stackoverflow.com/questions/27434593/django-rest-framework-3-0-create-or-update-in-nested-serializer

반응형