본문 바로가기
파이썬(Python)/장고(Django)

[기초] 파이썬 장고 REST API - Serializer relations

by 기계공학 주인장 2024. 2. 18.
반응형

이전 포스팅에서 Nested Relationships에 대해 알아봤습니다.

 

https://android-developer.tistory.com/86

 

[기초] 파이썬 장고 REST API - Nested Relationships

이전 포스팅에서 Relationships에 대해 알아봤습니다. https://android-developer.tistory.com/85 [기초] 파이썬 장고 REST API - Relationship 설정하기 이전 포스팅에서 Model Serializers를 사용하여 Model을 사용하는 방법

android-developer.tistory.com

 

Nested Relationships는 다른 Model의 데이터를 참조하는 것이였는데요.

 

만약 해당 Model의 특정 부분의 정보만 갖고 싶다면 어떻게해야할까요?

 

Serializer relations을 사용하면 해당 Model의 특정 부분만 가져올 수 있습니다.

 

 

Serializer relations - Django REST framework

relations.py Data structures, not algorithms, are central to programming. — Rob Pike Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse re

www.django-rest-framework.org

 

이번 포스팅에선 Serializer relations의 모든 API를 알아보는 것이 아니라 자주 사용하는 일부 API에 대해 알아보겠습니다.

  • StringRelatedField
  • PrimaryKeyRelatedField
  • HyperlinkedRelatedField

StringRelatedField

해당 Model__str__ 의 반환값을 얻어올 수 있습니다.

 

예를 들면 models.py에서 다음과 같은 __str__ 함수를 확인할 수 있습니다.

 

from django.db import models


class StreamPlatform(models.Model):
    # Model(=DB)에서 사용할 Column 정의
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=50)
    about = models.TextField(max_length=200)
    website = models.URLField(max_length=100)

    def __str__(self):
        return self.name


class Movie(models.Model):
    # Model(=DB)에서 사용할 Column 정의
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=50)
    description = models.TextField(max_length=200)
    # StreamPlatform은 여러 개의 Movie를 가질 수 있음
    platform = models.ForeignKey(StreamPlatform, on_delete=models.CASCADE, related_name='movielist')
    active = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

 

간단하게 기존에 있던 MovieSerializerStringRelatedField로 바꾸는 것만으로도 사용할 수 있다.

 

변경전에는 movielist 전체가 출력되지만

 

다음과 같이 코드를 변경하면

 

from rest_framework import serializers
from watchlist_app.models import Movie, StreamPlatform
        
class MovieSerializer(serializers.ModelSerializer):
    len_name = serializers.SerializerMethodField()
    
    class Meta:
        model = Movie
        # 모든 Field를 사용하게 한다.
        fields = "__all__"
        # 사용하고 싶은 Field를 지정하고 싶으면 다음과 같이 한다
        # fields = ['id', 'name', 'description']
        
        # 또는 특정 Field만 제외하고싶다면 다음과 같이 한다.
        # exclude = ['activity']
        
    def get_len_name(self, object):
        return len(object.name)
        
    def validate(self, data):
        if data['name'] == data['description']:
            raise serializers.ValidationError("이름과 내용이 같아선 안됩니다.")
        else:
            return data
    
    # field level validation
    # validate_필드 이름으로 만들면 자동으로 오버라이드 해준다.
    def validate_name(self, value):
        if len(value) < 2:
        	raise serializers.ValidationError("이름이 너무 짧습니다.")
        else :
            return value
        
class StreamPlatfromSerializer(serializers.ModelSerializer):
    # related_name에서 정의한 이름과 똑같은 이름으로 변수를 정의한다.
    # movielist = MovieSerializer(many=True, read_only=True)
    
    # StringRelatedField 사용
    movielist = serializers.StringRelatedField(many=True)
    
    class Meta:
        model = StreamPlatform
        fields = "__all__"

 

다음과 같이 movie의 title만 출력되는 것을 알 수 있다. (title이 출력되는 이유는 __str__에서 name을 출력하도록 했기 때문)

name만 출력된다.

 

참고로 현재 Movie 모델은 다음과 같다.

 

 


PrimaryKeyRelatedField

위에서 StringRelatedField를 사용하여 __str__의 결과를 얻어올 수 있었다.

 

PrimaryKeyRelatedField를 사용하면 각 아이템의 key 값을 얻어올 수 있다.

 

 

Serializer relations - Django REST framework

relations.py Data structures, not algorithms, are central to programming. — Rob Pike Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse re

www.django-rest-framework.org

 

StringRelatedFieldPrimaryKeyRelatedField로 바꿔주면된다.

 

class StreamPlatfromSerializer(serializers.ModelSerializer):
    # related_name에서 정의한 이름과 똑같은 이름으로 변수를 정의한다.
    # movielist = MovieSerializer(many=True, read_only=True)
    
    # PrimaryKeyRelatedField 사용
    movielist = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    
    class Meta:
        model = StreamPlatform
        fields = "__all__"

 


HyperlinkedRelatedField

사실 Movie 모델에는 해당 Movie의 위치가 담긴 url이 존재한다.

 

그렇다면 해당 url만 얻고싶을 때는 어떻게 할까?

 

HyperlinkedRelatedField를 사용하면 간단하게 url만 얻을 수 있다.

 

 

Serializer relations - Django REST framework

relations.py Data structures, not algorithms, are central to programming. — Rob Pike Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse re

www.django-rest-framework.org

 

다음과 같이 바꿔준다.

 

class StreamPlatfromSerializer(serializers.ModelSerializer):
    # related_name에서 정의한 이름과 똑같은 이름으로 변수를 정의한다.
    # movielist = MovieSerializer(many=True, read_only=True)
    
    # StringRelatedField 사용
    movielist = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='movie-detail' # urls.py에서 지정한 name으로 설정
    )
    
    class Meta:
        model = StreamPlatform
        fields = "__all__"

 

참고로 view_name은 urls.py에서 정의한 name을 사용한다.

 

 

결과는 다음과 같이 나온다.

 

그럼 다음과 같은 에러가 발생하는 것을 볼 수 있다.

 

 

말 그대로 HyperlinkedRelatedField는 context가 필요하다는 뜻이다.

 

views.py 부분에 다음과 같이 context를 넘겨주도록 변경한다.

# api/views.py

class StreamPlatformAV(APIView):
    def get(self, request):
        platform = StreamPlatform.objects.all()
        serializer = StreamPlatfromSerializer(platform, many=True, context={'request': request})
        return Response(serializer.data)
    
    def post(self, request):
        serializer = StreamPlatfromSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

 

그리고 다시 프로젝트를 실행하면 다음과 같은 화면을 얻을 수 있다.

 

 

그리고 해당 url로 이동해보면 다음과 같은 화면을 얻을 수 있다.

 

 

 

반응형


"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


댓글