web/django

Django serializer 활용하기 - advanced

민사민서 2024. 5. 14. 16:53

[Reminder] What is serializer?

Django의 Serializer는 Django에서 모델 인스턴스나 쿼리셋을 다양한 데이터 형식으로 변환하는 데 사용됩니다. 이를 통해 Django 애플리케이션에서 데이터를 직렬화하고 역직렬화하며 클라이언트와 서버 간의 데이터 교환에 사용됩니다.

 

One-To-One , One-To-Many , Many-To-Many 관계가 형성된 상태에서의 serializer 작성은 더 신경써야 할 부분이 있다

 

User - UserProfile 모델 간 OneToOne 관계 (필드 추가해 확장한 Wrapper 클래스 느낌이다)

from rest_framework import ModelSerializer
from django.contrib.auth.models import User
from .models import UserProfile

class UserIdUsernameSerializer(ModelSerializer):
  class Meta:
    model = User
    fields = ['id', 'username']

class UserSerializer(ModelSerializer):
  class Meta:
    model = User
    fields = ['id', 'username', 'password', 'email']

class UserProfileSerializer(ModelSerializer):
  user = UserSerializer(read_only=True)
  class Meta:
    model = UserProfile
    fields = "__all__"

account/serializers.py 를 이렇게 새로 생성했다

- class Meta: 에서는 어떤 모델에 대해서, 그리고 그 모델의 어떤 필드들을 serialize하는 대상으로 할 것인지 설정

- UserProfileSerializer 내부에서 UserSerializer 를 중첩해서 호출

 

왜??

class UserProfile(models.Model):
  user = models.OneToOneField(User, on_delete=models.CASCADE)
  college = models.CharField(max_length=32, blank=True)
  major = models.CharField(max_length=32, blank=True)

UserProfile 모델은 User 모델과 OneToOne 매핑되어있고, user라는 외래키(maybe user_id) 필드를 가진다

이 상황에서 Serializer에서 모든 필드를 출력하면 User 모델에 저장된 User 정보 중 user_id 말고는 가져오지 못한다

따라서 중첩해서 Serializer를 호출함으로써 모든 데이터를 가져옴

 

from rest_framework import serializers

class SignUpRequestSerializer(serializers.Serializer):
  email = serializers.EmailField()
  password = serializers.CharField()
  username = serializers.CharField()
  college = serializers.CharField()
  major = serializers.CharField()

class SignInRequestSerializer(serializers.Serializer):
  email = serializers.EmailField()
  username = serializers.CharField()
  password = serializers.CharField()

accounts/request_serializers.py

- 특정 모델에 직접 연결되지 않고, 데이터를 직접 정의하고 검증하기 위해 사용

- 주로 API 요청과 응답에서 특정 필드들만 검증하거나 사용할 때 유용

- 회원 가입 요청 시 필요한 필드를 정의하고, 로그인 요청 시 필요한 필드를 정의

 

Post - User 모델은 ManyToMany 관계를 가졌고, 중간에 중계 테이블 Like를 가졌다.

 

Like 모델에 대한 serializer를 만들어보자. 마찬가지로 Serializer의 중첩을 활용한다~~

from rest_framework.serializers import ModelSerializer
from .models import Post, Like
from account.serializers import UserProfileSerializer

class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = "__all__"

class LikeSerializer(ModelSerializer):
    user = UserProfileSerializer(read_only=True)
    post = PostSerializer(read_only=True)
    class Meta:
        model = Like
        fields = "__all__"

post/serializers.py

 

Tag와 Post 모델도 ManyToMany 관계를 가진다

class Post(models.Model):
    title = models.CharField(max_length=256)
    content = models.TextField()
    created_at = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
    like_users = models.ManyToManyField(User,blank=True,related_name='like_posts',through='Like')
    tags = models.ManyToManyField(Tag, blank=True, related_name="posts")

// 복습차 확인해보면 ManyToManyField로 매핑되었고, 중계테이블은 Django가 자동으로 생성해줌

 

from rest_framework.serializers import ModelSerializer
from .models import Tag

class TagSerializer(ModelSerializer):
  class Meta:
    model = Tag
    fields = "__all__"

tags/serializers.py 를 이렇게 새로 만들고

 

from tag.serializers import TagSerializer

class PostSerializer(ModelSerializer):
    tags = TagSerializer(many=True, read_only=True)
    class Meta:
        model = Post
        fields = "__all__"

이런 식으로 PostSerializer 내부에 TagSerializer를 중첩해서 사용한다

 

from rest_framework import serializers
from account.request_serializers import SignInRequestSerializer

class PostListRequestSerializer(serializers.Serializer):
  author = SignInRequestSerializer()
  title = serializers.CharField()
  content = serializers.CharField()
  tags = serializers.ListField(child=serializers.CharField())

class PostDetailRequestSerializer(serializers.Serializer):
  author = SignInRequestSerializer()
  title = serializers.CharField()
  content = serializers.CharField()
  tags = serializers.ListField(child=serializers.CharField())

posts/request_serializers.py

- Post List 요청 시, Post Detail 요청 시 필요한 필드를 정의