서론

    DjangoRestFramework(이하 DRF)로 사이트를 구현하다 보면 해시태그와 같이 SlugRelatedField에서 get_or_create 연산을 해야 하는 경우가 생긴다.
    하지만 DRF의 SlugRelatedField에서는 이걸 지원하지 않는다.
    우리에게는 class 상속이 있다! 상속을 통해 이 문제를 해결해보자.

     

    본론

    내가 작성한 코드는 이렇게 된다.

    class QuestionSerializer(serializers.ModelSerializer):
        owner = serializers.StringRelatedField(source='owner.profile.nickname', read_only=True)
        answer = AnswerSerializer(many=True, source='answer_set', read_only=True)
        topic = SlugRelatedGetOrCreateField(
            slug_field='content', many=True, queryset=QuestionTopic.objects.all()
        )
    
        class Meta:
            model = Question
            fields = ('id', 'subject', 'content', 'created_at', 'updated_at',
                      'topic', 'owner', 'owner_id', 'answer', 'hit')

    topic 라는 필드는 List[str] 으로 구성된다. 하지만 QuestionSerializer.save() method를 실행할 때 문제가 생긴다.

    기존의 SlugRelatedField는 topics = QuestionTopic.objects.get() 을 수행한 뒤 topics 안에 topic의 item이 없다면 Error를 띄운다.
    하지만 우리가 원하는 것은 item이 없다면 만드는 것이다!!!

    구글링을 통해 찾은 해법은 다음과 같다.

    StackOverflow 에선 SlugRelatedField 를 상속한 SlugRelatedGetOrCreateField class를 만들고, 이걸 적용한다는 해법을 제시한다.

    class SlugRelatedGetOrCreateField(serializers.SlugRelatedField):
        def to_internal_value(self, data):
            queryset = self.get_queryset()
            try:
                return queryset.get_or_create(**{self.slug_field: data})[0]
            except (TypeError, ValueError):
                self.fail("invalid")

    마법처럼 문제가 해결되었다...

    결론

    DRF도 많은 사람이 사용하다보니 문제에 대해 많은 해법이 제시되어 있었다.
    하지만 이 해법 중 나에게 맞는 해법을 찾는건 노력이 조금 들었다.

    하지만 한글로 된 문서는 적었기에 내가 해결한 과정을 남겨 다른 사람들이 조금 더 보기 쉽도록 만들고 싶었다.
    여러분도 이 글을 보며 도움이 되길 바란다.

    Posted by dalbodeule