Post

Django REST Framework (DRF) Serializer 활용하기

Django REST Framework의 Serializer를 활용한 데이터 직렬화 및 커스터마이징 가이드.

Django REST Framework (DRF) Serializer 활용하기

Django REST Framework(DRF)의 Serializer는 데이터 직렬화 및 역직렬화, 유효성 검증, 데이터 구조 커스터마이징을 위한 핵심 도구입니다.

1. Serializer의 기본 개념

Serializer는 다음과 같은 역할을 합니다:

  • 직렬화: 데이터베이스 모델 데이터를 JSON으로 변환하여 클라이언트로 전달.
  • 역직렬화: 클라이언트에서 전달된 JSON 데이터를 파이썬 객체로 변환.
  • 유효성 검사: 데이터의 형식 및 조건을 검증.
1
2
3
4
5
6
from rest_framework import serializers

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()
    created_at = serializers.DateTimeField(read_only=True)

2. 주요 Serializer 필드

Django REST Framework에서 제공하는 주요 Serializer 필드는 데이터를 변환하거나 검증하는 데 유용합니다.

2.1 기본 필드

  • CharField: 문자열 데이터를 처리합니다.
  • IntegerField: 정수 데이터를 처리합니다.
  • BooleanField: Boolean 데이터를 처리합니다.
  • EmailField: 이메일 형식의 문자열을 처리하고 검증합니다.
  • DateField: 날짜 데이터를 처리합니다.
  • DateTimeField: 날짜 및 시간 데이터를 처리합니다.
1
2
3
4
class BasicSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50)
    age = serializers.IntegerField()
    is_active = serializers.BooleanField()

2.2 관계 필드

  • PrimaryKeyRelatedField: 외래 키 관계를 ID로 처리합니다.
  • StringRelatedField: 외래 키 객체의 문자열 표현을 반환합니다.
  • SlugRelatedField: 특정 필드(slug) 값을 기준으로 관계를 처리합니다.
  • HyperlinkedRelatedField: 객체를 URL로 직렬화합니다.
1
2
3
4
5
6
class RelatedSerializer(serializers.ModelSerializer):
    related_field = serializers.StringRelatedField()

    class Meta:
        model = SomeModel
        fields = ['id', 'related_field']

2.3 커스텀 필드

  • SerializerMethodField: 메서드를 사용해 직렬화 데이터를 생성합니다.
1
2
3
4
5
6
7
8
9
class CustomSerializer(serializers.ModelSerializer):
    custom_field = serializers.SerializerMethodField()

    class Meta:
        model = SomeModel
        fields = ['id', 'custom_field']

    def get_custom_field(self, obj):
        return "Custom Value"

2.4 필드 옵션

  • read_only: 필드가 읽기 전용임을 명시합니다.
  • write_only: 필드가 쓰기 전용임을 명시합니다.
  • required: 필드가 필수인지 여부를 설정합니다.
  • default: 필드의 기본값을 설정합니다.
  • validators: 커스텀 검증 로직을 추가할 수 있습니다.
1
2
3
class OptionSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=50, required=True, default="No Name")
    email = serializers.EmailField(validators=[custom_validator])

3. 상황별 Serializer 활용하기

3.1 Article에 Comment 추가하기

Article 모델에서 관련된 Comment 모델 데이터를 포함하려면 중첩 관계(Nested Relationships)를 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from rest_framework import serializers
from .models import Article, Comment

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"
        read_only_fields = ("article",)

class ArticleSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True, read_only=True)

    class Meta:
        model = Article
        fields = "__all__"

여기서 comments 필드는 CommentSerializer를 사용해 데이터를 표현합니다. many=True로 설정하여 여러 개의 댓글을 처리할 수 있도록 합니다.

3.2 댓글 수 필드 추가하기

클라이언트에서 댓글 수를 표시해야 할 때, 추가 필드를 정의하여 제공할 수 있습니다.

1
2
3
4
5
6
7
class ArticleSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True, read_only=True)
    comments_count = serializers.IntegerField(source="comments.count", read_only=True)

    class Meta:
        model = Article
        fields = "__all__"
  • source 속성: 필드의 값을 가져오기 위해 사용. comments.count를 사용하여 댓글 개수를 반환합니다.
  • read_only=True: 클라이언트가 이 필드를 수정하지 못하도록 설정합니다.

3.3 커스텀 데이터 추가하기: SerializerMethodField

동적인 데이터를 추가하려면 SerializerMethodField를 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.contrib.auth.models import User
from django.utils.timezone import now
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    days_since_joined = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = '__all__'

    def get_days_since_joined(self, obj):
        return (now() - obj.date_joined).days
  • get_<field_name> 메서드: 커스텀 데이터를 계산하여 반환합니다.

3.4 응답 구조 변경하기: to_representation

to_representation 메서드를 오버라이드하여 응답 데이터를 원하는 형태로 커스터마이징할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"
        read_only_fields = ("article",)

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret.pop("article")  # 'article' 필드 제거
        return ret

to_representation은 직렬화 후 데이터를 수정할 수 있는 강력한 도구입니다.

3.5 Serializer 상속 활용하기

Serializer 상속을 통해 기본 구조를 재사용하고, 상세 조회에서만 특정 필드를 추가하거나 수정할 수 있습니다.

serializers.py

1
2
3
4
5
6
7
8
9
10
11
from rest_framework import serializers
from .models import Article, Comment

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = "__all__"

class ArticleDetailSerializer(ArticleSerializer):
    comments = CommentSerializer(many=True, read_only=True)
    comments_count = serializers.IntegerField(source="comments.count", read_only=True)

views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.status import HTTP_201_CREATED
from django.shortcuts import get_object_or_404
from .models import Article
from .serializers import ArticleSerializer, ArticleDetailSerializer

class ArticleListCreateAPIView(APIView):
    def get(self, request):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data, status=HTTP_201_CREATED)

class ArticleDetailAPIView(APIView):
    def get_object(self, pk):
        return get_object_or_404(Article, pk=pk)

    def get(self, request, pk):
        article = self.get_object(pk)
        serializer = ArticleDetailSerializer(article)
        return Response(serializer.data)

    def put(self, request, pk):
        article = self.get_object(pk)
        serializer = ArticleDetailSerializer(article, data=request.data, partial=True)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)

이 방식으로 게시글 목록과 상세 조회에서 서로 다른 직렬화 구조를 제공합니다.

This post is licensed under CC BY 4.0 by the author.