Lina's Toolbox

[Django] 뷰 함수 호출 안될 때 해결 방법 (URL path collision) 본문

스파르타 내일 배움 캠프 AI 웹개발 과정/troubleshooting

[Django] 뷰 함수 호출 안될 때 해결 방법 (URL path collision)

Woolina 2024. 8. 23. 05:32

중고 거래 사이트를 장고 프레임워크를 사용하여 개발 중이다.

그런데 상품 정렬 기능을 개발하던 중... 정렬 버튼을 아무리 눌러도 결과가 반영되지 않는 문제가 발생했다.

 

원인 파악

쿼리 여러번 확인하고, 템플릿 url 링크 확인, 템플릿 상속 문제,캐시 문제까지 2시간 가량 별의 별것을 다 확인해봤지만 원인이 아니였다.

 

<!-- templates/products/products.html -->

{% block sorting %}
<div class="sort-options mb-4 text-end"> <!-- Changed to text-end for right alignment -->
    <ul class="sort-list list-unstyled d-inline-flex">
        <li class="sort-item me-3">
            <a href="{% url 'products:product_list' %}?sort=latest" class="sort-link {% if request.GET.sort == 'latest' %}active{% endif %}">
                최신순
            </a>
        </li>
        <li class="sort-item">
            <a href="{% url 'products:product_list' %}?sort=popular" class="sort-link {% if request.GET.sort == 'popular' %}active{% endif %}">
                인기순
            </a>
        </li>
    </ul>
</div>
{% endblock sorting %}

 

 

해당 버튼을 누를 때마다 터미널 창을 확인해보면,

[22/Aug/2024 19:33:51] "GET /products/?sort=popular HTTP/1.1" 200 11998
[22/Aug/2024 19:34:03] "GET /products/?sort=latest HTTP/1.1" 200 11998

/products/?sort=popular/products/?sort=latest URL에 대해 200 OK 응답이 반환되고 있다는 것은

현재 Django 개발 서버가 정상적으로 실행되고 있으며,

뷰도 정상 호출하고 있다는 의미인데..

 

# products/views.py

from django.shortcuts import render
from django.db.models import Count
from .models import Product

def product_list(request):
    print("product_list view called")  # 뷰 호출 확인용
    
    sort_by = request.GET.get('sort', 'latest')
    
    if sort_by == 'popular':
        products = Product.objects.annotate(
            likes_count=Count('like_users')
        ).order_by('-likes_count', '-view_cnt')
        print(products.query)  # 쿼리 출력
    else:
        products = Product.objects.order_by('-created_at')
    
    context = {
        'products': products,
        'sort_by': sort_by
    }

    return render(request, 'products/product_list.html', context)

내 코드는 분명 이렇게 product_list뷰에 들어오자마자 print("product_list view called")를 해주는데

터미널에 출력되지 않는다..

 

다른 뷰에서 print문을 써주어 확인해봤는데,

다른 뷰를 호출하면 터미널에 print문이 출력됐다.

이 뷰만  호출이 안된다는 건데...

 

from django.http import HttpResponse

def product_list(request):
    # 디버깅을 위한 직접 응답
    return HttpResponse("product_list view called")

    # 기존 코드
    # print("product_list view called")
    # sort_by = request.GET.get('sort', 'latest')
    # ...

이렇게도 확인해봤지만 여전히 안뜬다. ㅠㅠ

내 뷰 함수가 여전히  호출되지 않고 있음을 의미.

 

# products/urls.py

from django.urls import path
from . import views

app_name = "products"

urlpatterns = [
    path("", views.products, name="products"),
    path("create/", views.create, name="create"),
    path("<int:pk>/", views.product_detail, name="product_detail"),
    path("", views.product_list, name="product_list"),
    path("<int:pk>/delete/", views.delete, name="delete"),
    path("<int:pk>/update/", views.update, name="update"),
    path("<int:pk>/comments/", views.comment_create, name="comment_create"),
    path(
        "<int:pk>/comments/<int:comment_pk>/delete/",
        views.comment_delete,
        name="comment_delete",
    ),
    path("<int:pk>/like/", views.like, name="like"),
    path("index/", views.index, name="index"),
]

아무리 봐도 뭔가 URL 매핑에 문제가 있는 것 같아, 템플릿과 urls.py를 살펴보다가..

urls.py에서 뭔가 이상한 걸  발견.

path("") 가 두개잖아? 여기서 충돌 나는거 아님?

 

결론은 맞았따..


해결 방법

 

urls.py에서 빈 문자열 ("")로 두 개의 URL 패턴이 정의되어 있어서 문제가 발생하는 것이였다.

Django는 URL 패턴이 일치하는 첫 번째 패턴을 사용하므로, product_list가 실행되지 않은 것.

 

path("", views.product_list, name='product_list')로 설정되어 있는 경우, URL이 빈 문자열로 정의되어 있으므로,

기본적으로 루트 URL인 /을 처리하는 뷰로 연결된다..

이 경우, /products/ URL을 product_list 뷰로 연결하기 위해 urls.py를 수정해야한다. 

 

# products/views.py

urlpatterns = [
    path("", views.products, name="products"),
    path("products/", views.product_list, name="product_list"),
]

 

이렇게, 

path("", views.product_list, name="product_list"), 

→ path("products/", views.product_list, name="product_list"),

 

수정해줬더니 이제 정상 작동한다!!!

애꿎은 쿼리만 계속 괴롭혔네..