db에있는걸 파이썬객체로 가져오는게 model이고
serializer는 파이썬객체를 json으로 변환하거나 json을 파이썬 객체로 변환하는거임
전자가 serialize고 후자가 deserialize
그 실제로 http body로 보내는건 텍스트데이터로 엄밀히얘기하면 json으로 변경가능한 바이트 스트링임.
serializer는 json에 대응가능한 dictionary형식으로 변경해줌.
여기서 serializer = SnippetSerializer(snippet)
로 serialize 했을때 시리얼라이저에 id, title, code, linenos, language, language, style 필드가 있으니 해당 항목들이 나옴.
// serializer
class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
snippet = Snippet(code='print("hello, world")\n')
snippet.save()
serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}
content = JSONRenderer().render(serializer.data)
content
# b'{"id": 2, "title": "", "code": "print(\\"hello, world\\")\\n", "linenos": false, "language": "python", "style": "friendly"}'
데이터를 deserialize(json을 파이썬 객체로 변환)할때 .save()
를 불러서 객체 인스턴스를 리턴해 줄 수 있음.
.save()
를 부르면 새로운 인스턴스를 생성하거나 이미 존재하는 인스턴스를 업데이트 해줄 수 있는데 시리얼라이저 클래스를 인스턴스화할때 이미 존재하는 인스턴스가 시리얼라이저 클래스에 넘어갔는지에 따라 다름.
아래에서 볼 수 있는 것처럼 save()
에서 시리얼라이저에 instance가 들어왔으면 update하고 아니면 create해줌.
// https://github.com/encode/django-rest-framework/blob/efc7c1d664e5909f5f1f4d07a7bb70daef1c396e/rest_framework/serializers.py#L179
class BaseSerializer(Field):
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
def save(self, **kwargs):
validated_data = {**self.validated_data, **kwargs}
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.
실제 사용예시는 아래처럼하면 됨.
생성할때는 아래처럼 instance를 안넘겨주고
self.get_serializer(data=request.data)
serializer.save()
업데이트 할 때는 시리얼라이에 data앞에다가 instance를 넣어줌.
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data)
serializer.save()
시리얼라이저에 시리얼라이즈 하는 객체말고 추가적인 context를 넘겨줄 수 있음.
context = self.get_serializer_context()
context['post_id'] = instance.post_id
serializer = self.get_serializer(instance, data=request.data, context=context, partial=True)
넘겨진 컨텍스트 딕셔너리는 시리얼라이저에서 self.context
로 접근가능함.
아래는 위의 컨텍스트를 받아서 시리얼라이저 안에서 사용한 예시로 컨텟스트를 받아서 validated data인 attr에다가 넣어줌.
def validate(self, attr):
author = self.context['request'].user
if author.is_anonymous:
raise ValidationError('anonymous user cannot create comment')
attr['author'] = self.context['request'].user.id
attr['post_id'] = self.context['post_id']
return attr