본문 바로가기

Minding's Programming/Django

[Django] RelatedField

728x90
반응형

RelatedField

1. PrimaryKeyRelatedField

 

현재 User List를 살펴보면, 각 유저의 question 필드에 질문 레코드의 id값이 표시되는 것을 확인할 수 있다. 이것은 serializers.py에서 UserSerializer를 설정할 때 PrimaryKeyRelatedField를 사용했기 때문이다.

# mysite/polls_api/serializers.py

class UserSerializer(serializers.ModelSerializer):
    # questions 필드를 명시하는 이유: User 모델과 Question 모델 간의 관계를 보여주기 위함
    questions = serializers.PrimaryKeyRelatedField(many=True, queryset=Question.objects.all())

PK-FK 관계로 이어진 값을 나타내기 때문에, 해당 필드에 id값이 표시되는 것이다.

 

2. StringRelatedField

id값이 아닌 __str__() 함수에 의해 표시되는 문자열로 표시하게 할 수도 있다.

# User 모델과 Question 모델 간의 관계를 보여주는 Serializer
class UserSerializer(serializers.ModelSerializer):
    questions = serializers.StringRelatedField(many=True, read_only=True)

StringRelatedField를 사용하면 Model의 __str__() 함수로 표현되는 문자열로 표시된다.

 

3. SlugRelatedField

자식 모델이 가지고 있는 필드 중 원하는 필드를 하나 골라서 출력하는 방법도 있다.

class UserSerializer(serializers.ModelSerializer):
    questions = serializers.SlugRelatedField(many=True, slug_field='pub_date', read_only=True)

Question 모델의 'pub_date' 필드를 출력하도록 했다. SlugRelatedField를 사용하면 이처럼 원하는 필드를 출력하게 만들 수 있다.

 

4. HyperlinkedRelatedField

해당 모델의 상세 페이지로 이동할 수 있는 하이퍼링크를 출력하게 할 수도 있다.

class UserSerializer(serializers.ModelSerializer):
    questions = serializers.HyperlinkedRelatedField(many=True, view_name='question-detail', read_only=True)

HyperlinkedRelatedField를 사용하면 위처럼 하이퍼링크를 넣을 수 있다. view_name은 urls.py에서 지정한 name을 사용한다.

# 참고 urls.py

from django.urls import path, include
from .views import *

urlpatterns = [
    path('question/', QuestionList.as_view(), name='question-list'),
    path('question/<int:pk>/', QuestionDetail.as_view(), name='question-detail'),
    ...
    ]

 

Related_name 이용하기

모델에서 FK로 상속받는 필드에 related_name을 지정하면 상위 모델에서 그 이름으로 역참조를 할 수 있다는 것을 기억하는가? (User-Question 모델 사이 연결)

 

Choice 모델의 question 필드에도 related_name을 지정해 QuestionSerializer에서 사용할 수 있도록 하려고 한다.

mysite/polls/models.py

class Choice(models.Model):
    # 어떤 질문에 대한 답인지 알아볼 수 있도록 Question 클래스에서 FK를 받아옴
    question = models.ForeignKey(Question, related_name='choices', on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    # 답변의 빈도를 세기 위한 정수 필드
    votes = models.IntegerField(default=0)

    # 문자열을 표시할 때 question_text를 반환
    def __str__(self):
        return f'[{self.question.question_text}] {self.choice_text}'

choices 라는 이름으로 related_name을 지정해줬다.

 

이제 시리얼라이저에 choices가 표시되도록 설정해보자. 우선 ChoiceSerializer부터 생성한 뒤, 그 클래스를 사용해 choices를 QuestionSerializer에서 불러올 것이다.

class ChoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Choice
        fields = ['choice_text', 'votes']

# Question 모델을 보여주는 Serializer
class QuestionSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    choices = ChoiceSerializer(many=True, read_only=True)

    class Meta:
        model = Question
        fields = ['id', 'question_text', 'pub_date', 'owner', 'choices']

위와 같이 코드를 수정한 뒤 Question_list를 다시 살펴보자.

 

위와 같이 해당 질문 레코드에 관계된 답변(choices)이 모두 출력되는 것을 볼 수 있다.

728x90