장고 템플릿 if 구문에서 외래키 역참조가 제대로 되지 않았던 이유
오늘은 Django 프로젝트에서 if 구문을 사용할 때 발생한 문제에 대해 깊이 고민하는 시간을 가졌다. 특정 조건인 {% if object.user in request.user.blocking.all %}가 예상대로 작동하지 않았고, 그 이유를 찾는 데 어려움을 겪었다. 처음에는 왜 이 조건이 실패하는지 도무지 이해할 수 없었다.
고민 끝에 알게 된 것은, object.user와 request.user.blocking.all 간의 데이터 타입 불일치가 원인이라는 점이었다. object.user는 특정 사용자를 나타내는 객체인데 반해, request.user.blocking.all은 사용자가 차단한 모든 유저의 리스트를 반환하는 쿼리셋이어서, 두 값이 서로 다른 데이터 타입이었다. 객체를 직접 비교하려 하니 조건문이 실패하는 것이 당연한 결과였다.
처음에 이 문제를 해결하기 위해 간단한 접근 방법을 생각했다. 데이터 타입을 맞추는 것이었고, object.user의 ID와 차단된 사용자의 ID를 비교하기로 했다. 아래와 같은 코드를 작성했다.
if object.user.id in request.user.blocking.values_list('id', flat=True):
# 차단된 사용자임을 확인
이 코드를 사용하면 object.user의 ID가 차단된 사용자들의 ID 리스트에 포함되는지를 확인할 수 있었다. 이 방법은 간단하면서도 데이터 타입 불일치 문제를 해결할 수 있었지만, 좀 더 직관적인 방법이 필요하다고 생각했다.
그러던 중, DetailView에서 get_context_data 메서드를 활용해볼 수 있겠다는 아이디어가 떠올랐다. 이 메서드를 통해 현재 뷰에서 조회된 객체의 유저와 로그인한 사용자가 차단한 유저를 더 명확하게 비교할 수 있을 것 같았다. 다음과 같이 코드를 작성해 보았다.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
for item in self.request.user.blocking.all():
if self.get_object().user == item.blocked:
context['is_blocked'] = True
break
return context
이 코드를 작성하며 느낀 점은, for 문을 통해 차단된 사용자 하나하나를 확인하는 방식이 더 직관적이라는 것이었다. 각 차단된 유저의 blocked 속성과 현재 조회된 객체의 유저를 직접 비교함으로써 조건이 명확하게 처리되었고, 차단 여부를 context에 담아 템플릿에서 쉽게 활용할 수 있었다.
오늘 이 문제를 해결하면서 깨달은 것은, 코드가 간단한 게 항상 최선은 아니라는 점이다. 데이터 타입을 ID로 맞추는 것은 빠른 해결책일 수 있지만, 더 명확하고 안전한 방법이 필요할 때는 객체 자체를 비교하는 접근이 더 나을 수 있음을 배웠다. 이렇게 작은 문제 해결 과정을 통해 코딩의 깊이를 느끼게 되었고, 앞으로의 작업에도 큰 도움이 될 것이라 확신한다.