DjangoRestFramework SlugRelatedField get_or_create
Python/Django
2024. 5. 8. 10:41
서론
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도 많은 사람이 사용하다보니 문제에 대해 많은 해법이 제시되어 있었다.
하지만 이 해법 중 나에게 맞는 해법을 찾는건 노력이 조금 들었다.
하지만 한글로 된 문서는 적었기에 내가 해결한 과정을 남겨 다른 사람들이 조금 더 보기 쉽도록 만들고 싶었다.
여러분도 이 글을 보며 도움이 되길 바란다.