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.
'IT박스' 카테고리의 다른 글
Python 파일 편집을 위해 Vim 자동 들여 쓰기를 올바르게 설정하려면 어떻게해야합니까? (0) | 2020.11.02 |
---|---|
AngularJS의 구성 파일 (0) | 2020.11.02 |
XML 속성과 요소 (0) | 2020.11.02 |
PostgreSQL : pg_dump, pg_restore 성능 향상 (0) | 2020.11.02 |
GC로 또는 GC로 (0) | 2020.11.02 |