# .save() will create a new instance.
serializer = CommentSerializer(data=tata)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
# Passing additional attributes to .save() which is not part of the request data
serializer.save(owner=request.user)
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)
참조관계를 갖는 다른 모델의 데이터를 사용해야 할 경우, 아래와 같이 참조할 모델의 Serializer를 가져와서 사용할 수 있다.
required=False
를 설정하면 된다.many=True
를 설정하면 된다.class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField(max_length=100)
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
edits = EditItemSerializer(many=True) # A nested list of 'edit' items.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
만약 writable nested representation을 하고 싶다면, 여러 개의 객체를 저장할 수 있는 create()
메소드와 update()
메소드를 작성해야 한다.
.Create()
작성하기아래 사례는 profile을 nested로 가지고 있는 user를 생성하는 코드이다.
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
[코드 해석]
.pop('profile')
메소드로 profile 정보만 추출하여 profile_data에 담고, validated_data에는 username, email이 남는다.update를 위해서는 고려해야 되는 사항들이 많다.
많약 관계를 맺는 user의 profile이 존재하지 않으면 어떻게 할 것인가와 같은 문제가 생길 수 있다.
따라서 update를 작성할 때는 엄격하고 디테일하게 코드를 작성해야 한다.
디폴트 ModelSerializer .created(), .update() 메소드는 writable nested representations을 지원하지 않기 때문이다.
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
# Unless the application properly enforces that this field is
# always set, the follow could raise a `DoesNotExist`, which
# would need to be handled.
profile = instance.profile
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.save()
profile.is_premium_member = profile_data.get(
'is_premium_member',
profile.is_premium_member
)
profile.has_support_contract = profile_data.get(
'has_support_contract',
profile.has_support_contract
)
profile.save()
return instance
여러 개의 related instances를 저장하는 또 다른 방법은 custom model manager 클래스를 만들어서, 복수의 객체를 생성해 버리는 것이다.
가령, 유저 인스턴스를 생성할 때 프로파일 인스턴스도 항상 동시에 생성시키고자 한다면 아래와 같은 custom manager 클래스를 만들어서 사용하는 것도 한 방법이다.
class UserManager(models.Manager):
...
def create(self, username, email, is_premium_member=False, has_support_contract=False):
user = User(username=username, email=email)
user.save()
profile = Profile(
user=user,
is_premium_member=is_premium_member,
has_support_contract=has_support_contract
)
profile.save()
return user
def create(self, validated_data):
return User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
is_premium_member=validated_data['profile']['is_premium_member'],
has_support_contract=validated_data['profile']['has_support_contract']
)
many=True를 세팅하면, 복수의 객체들을 serialize할 수 있다.
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
# {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
# {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]
__str__
메소드에서 리턴하는 값을 리턴해 줌.
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
order = models.IntegerField()
title = models.CharField(max_length=100)
class Meta:
unique_together = ['album', 'order']
ordering = ['order']
def __str__(self):
return '%d: %s' % (self.order, self.title)
[Arguments]
- queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.
- many - If applied to a to-many relationship, you should set this argument to True.
- allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.
- pk_field - Set to a field to control serialization/deserialization of the primary key's value. For example, pk_field=UUIDField(format='hex') would serialize a UUID primary key into its compact hex representation.
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ['order', 'title', 'duration']
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
[예상 출력 값]
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
...
],
}
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ['order', 'title', 'duration']
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
>>> data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>