DRF Serialization

14735 단어 djangodjango

Serialize/Deseralize

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"}'

serializer.save()

데이터를 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()

Including extra context

시리얼라이저에 시리얼라이즈 하는 객체말고 추가적인 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

좋은 웹페이지 즐겨찾기