Writable nested serializers
기본적으로 nested serializer는 읽기 전용이다.
외래키로 연결되어 두개 이상의 모델이 중첩 된 serializer를 사용해 모델을 저장, 수정하려면 creat()또는 update()메서드를 만들어 외래키 관계를 저장하는 방법을 직접 구현해야 한다.
Nested Model
from django.db import models
class BasePage(models.Model):
created_time = models.DateTimeField('created time', auto_now_add=True)
last_mod_time = models.DateTimeField('modified time', auto_now=True)
class Meta:
abstract = True
class Page(BasePage):
title = models.CharField(max_length=200, null=True, blank=True)
order = models.PositiveIntegerField("page order", default=1)
class Meta:
verbose_name = "Page"
verbose_name_plural = verbose_name
db_table = 'page'
class Component(models.Model):
title = models.CharField(max_length=200, null=True, blank=True)
sub_title = models.CharField(max_length=1000, null=True, blank=True)
body = models.TextField(default='')
order = models.PositiveIntegerField("component order", default=1)
type = models.CharField(max_length=100, null=True, blank=True)
sub_type = models.CharField(max_length=100, null=True, blank=True)
bg_color_code = models.CharField(max_length=50, null=True, blank=True)
page = models.ForeignKey(
Page,
null=True,
on_delete=models.SET_NULL,
related_name='component')
def __str__(self):
try:
return self.title
except:
return ''
class PageImage(models.Model):
alt = models.CharField(max_length=200, null=True, blank=True)
image_url = models.URLField(max_length=256)
order = models.PositiveIntegerField("image order", default=1)
created_time = models.DateTimeField('created time', auto_now_add=True)
component = models.ForeignKey(
Component,
on_delete=models.CASCADE,
related_name='pageimage')
def __str__(self):
return self.image_url
class Meta:
db_table = 'pageimages'
위 3개의 모델은 중첩되어있다.
Component 모델은 Page 모델의 하위 관계(Realation) 모델이 된다.
PageImage 모델은 Component 모델의 하위 관계 모델이 된다.
Nested Serializer
## serializers.py
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from pages.utils import construct_component
from pages.models import *
class ImageListerializer(serializers.ModelSerializer):
class Meta:
model = PageImage
fields = (
'alt',
'image_url',
'order',
)
class ComponentCreateSerializer(serializers.ModelSerializer):
pageimages = ImageListerializer(many=True, read_only=True)
class Meta:
model = Component
fields = (
'title',
'sub_title',
'body',
'order',
'type',
'sub_type',
'bg_color_code',
'page',
'pageimages'
)
def create(self, validated_data):
print(validated_data)
type = validated_data['type']
# Get Page object
page = validated_data['page']
# Create the Component
component = construct_component(type)
for key, value in validated_data.items():
setattr(component, key, value)
component.page = page
component.save()
pageimage_datas = validated_data['pageimages']
for pageimage_data in pageimage_datas:
PageImage.objects.create(
component=component,
**pageimage_data)
return component
위 모델처럼 중첩된 관계도 Serializer로 표현할 수 있다.
Component모델의 하위 모델로 PageImage모델이 있다.
따라서 여러개의 PageImage가 Component에 포함될 수 있기 때문에
pageimages = ImageListerializer(many=True, read_only=True)
many=True 옵션을 반드시 추가해 준다.
(만약 OneToOne 관계라면 many=True를 쓸 필요없다.)
create 메서드 부분을 살펴보자 (중요한 부분만 살펴보겠다)
component = construct_component(type)
for key, value in validated_data.items():
setattr(component, key, value)
component.page = page
component.save()
construct_component(type) 함수는 Component 모델을 type에 따라 다르게 생성해주는 함수이다.
크게 신경 쓸 필요없이 Component 객체를 만들어 준다고 생각하면 된다.
create 메서드의 인자로 받은 validated_data는 dict 객체이다.
key, value로 구분해 for문을 수행하고, setattr 함수를 사용해 component객체의 필드에 알맞은 값을 설정해준다.
pageimage_datas = validated_data['pageimages']
for pageimage_data in pageimage_datas:
PageImage.objects.create(
component=component,
**pageimage_data)
return component
validated_data에서 key 값이 pageimages 인 value들을 꺼내온다.
순서대로 PageImage 객체를 만들어주면서 객체의 component 필드값을 위에서 저장한 component로 설정하면서 저장한다.
'Back-End > Django' 카테고리의 다른 글
[Django] DRF를 사용한 JWT Authentication #2 (0) | 2022.01.03 |
---|---|
[Django] DRF를 사용한 JWT Authentication #1 (0) | 2022.01.03 |
[Django] django-debug-toolbar 안보임 오류 해결 (0) | 2021.12.17 |
[Django] DataFrame to CSV (download) (0) | 2021.12.01 |
[Djnago] Django 이메일 인증하기(Thread) (0) | 2021.10.27 |