[DRF] Tag pk를 name으로 변경(StringRelatedField) & Image URL 변경(get_serializer_context)

Jinhyung Rhee·2022년 8월 18일
0

수정해야 할 부분1 : 포스트 상세 페이지 Category, Tag 값을 pk에서 name으로 변경 (PostRetrieveSerializer)

  • Django Shell로 확인

    >>> from api2.serializers import *
    >>> PostRetrieveSerializer()
    PostRetrieveSerializer():
        id = IntegerField(label='ID', read_only=True)
        title = CharField(label='TITLE', max_length=50)
        description = CharField(allow_blank=True, help_text='simple one-line text.', label='DESCRIPTION', max_length=100, required=False)
        image = ImageField(allow_null=True, label='IMAGE', max_length=100, required=False)
        content = CharField(label='CONTENT', style={'base_template': 'textarea.html'})
        update_dt = DateTimeField(label='UPDATE DT', read_only=True)
        like = IntegerField(label='LIKE', required=False)
        category = PrimaryKeyRelatedField(allow_null=True, queryset=Category.objects.all(), required=False)
        tags = PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all(), required=False)
    • category와 tags가 PrimaryKeyRelatedField로 잡혀있기 때문에 출력시 pk로 나오는 것!
      • category는 ForeignKey 필드
      • tags는 ManyToManyField 필드
      • ForeignKey필드와 ManyToManyField에 대해서 DRF에서는 자동으로 PrimaryKeyRelatedField로 잡아줌!
    • TODO : '포스트 상세 페이지'에서 두 필드(category, tags)에 대해서 pk가 아닌 name으로 표현되도록 오버라이딩!
  • DRF 공식문서 확인 (Serializer relations)

    • DRF에서 ForeignKey, ManyToManyField, OneToOneField, GenericForeignKey 필드를 사용하는 경우 StringRelatedField⭐, PrimaryKeyRelatedField⭐, HyperlinkedRelatedField, SlugRelatedField, HyperlinkedIdentityField 등을 사용할 수 있음!

    • PrimayrKeyRelatedField

      • PrimaryKeyRelatedField로 정의한 경우, 출력이 pk값으로 표현됨!
    • StringRelatedField

      • StringRelatedField로 정의한 경우, 출력을 string으로 표현 가능!
      • 출력에 표현되는 문자열은 __str__메서드에 표현된(정의된) 문자열임!

코드 적용

  • 기존에 정의된 models.py

    class Category(models.Model):
        name = models.CharField(max_length=50, unique=True)
        description = models.CharField('DESCRIPTION', max_length=100, blank=True, help_text='simple one-line text.')
    
        def __str__(self):
            return self.name
    
    class Tag(models.Model):
        name = models.CharField(max_length=50)
    
        def __str__(self):
            return self.name
    • __str__(self) 메서드에 name 속성을 사용하고 있으므로, StringRelatedField를 사용하면 pk가 아닌 name으로 표현 가능!
  • serializers.py 수정 : PostRetrieveSerializer

    class PostRetrieveSerializer(serializers.ModelSerializer):
        # 기존의 필드를 serializer 내부에서 오버라이딩하여 사용⭐
        category = serializers.StringRelatedField()
        tags = serializers.StringRelatedField(many=True)
        class Meta:
            model = Post
            # fields = '__all__'
            exclude = ['create_dt']
    • tags = serializers.StringRelatedField(many=True) : Tag는 List 형식으로 복수(ManyToManyField)로 사용되기 때문에 many=True 인자 필요!
  • veiws.py : 데이터를 공급해주는 view는 변경사항이 없음. 수정X (→ 출력 형식만 바뀌는 것이기 때문!)

결과

수정해야 할 부분2 : 포스트 상세 페이지 Image URL을 장고 표준으로 변경

  • views.py : get_serializer_context(self) 메서드 오버라이딩

    def get_prev_next(instance):
      try:
        prev = instance.get_previous_by_update_dt()
      except instance.DoesNotExist:
        prev = None
    
      try:
        next_ = instance.get_next_by_update_dt()
      except instance.DoesNotExit:
        next_ = None
    
      return prev, next_
    
    class PostRetrieveAPIView(RetrieveAPIView):
      queryset = Post.objects.all()
      serializer_class = PostSerializerDetail
    
      def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            prevInstance, nextInstance = get_prev_next(instance)
            commentList = instance.comment_set.all()
            data = {
              'post' : instance,
              'prevPost' : prevInstance,
              'nextPost' : nextInstance,
              'commentList' : commentList,
            }
            serializer = self.get_serializer(instance=data)
            return Response(serializer.data)
    
      # override
      def get_serializer_context(self):
            """
            Extra context provided to the serializer class.
            """
            return {
                'request': None,
                'format': self.format_kwarg,
                'view': self
            }

    결과

Reference

https://www.django-rest-framework.org/api-guide/relations/#stringrelatedfield
https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-drf/dashboard

profile
기록하는 습관

0개의 댓글