1. Django Tutorial(Airbnb) - 상세 페이지 구현

ID짱재·2021년 8월 6일
1

Django

목록 보기
17/43
post-thumbnail

🌈 상세 페이지 구현

🔥 FBV로 상세페이지 구현

🔥 CBV로 상세페이지 구현


1. FBV로 상세페이지 구현

1) url dispatcher

  • 객실 목록 중 하나를 클릭하여 진입하면 나타나는 상세페이지를 구현하기 위해서 urls.py를 통해 경로(url)와 로직(view)를 연결시켰어요.
  • 우선 "http://127.0.0.1:8000/rooms/.."으로 url이 request되면, rooms/urls.py에서 해당 경로에 대한 로직을 탐색하도록 inlcude 했어요.
# urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
    path("", include("core.urls", namespace="core")),
    path("rooms/", include("rooms.urls", namespace="rooms")), # 👈 이곳입니다:)
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  • url dispatcher는 url에 변수를 담을 수 있게 만들어 줍니다. path converters를 통해 str, int, slug, uuid, path 등으로 url의 값을 변환하여 View로 전달할 수 있어요. 즉, "http://127.0.0.1:8000/rooms/2"로 접근하면 2를 받아서 View로 전달합니다.
# rooms/urls.py
from django.urls import path
from . import views
app_name = "rooms"
urlpatterns = [
    path("<int:pk>", views.room_detail, name="detail"),
]
  • 이 PK 값을 view.py에서 사용하기 위해서 해당 함수에서 argument를 받아줘야해요.
  • "http://127.0.0.1:8000/rooms/94817436"로 request를 요청하고, "room_detail" 함수에서 pk값을 출력해보니, console에 94817436이 제대로 출력었어요:)
from django.views.generic import ListView
from django.shortcuts import render
from . import models
...
...
def room_detail(request, pk):
    print(pk) # 94817436
    return render(request, "rooms/detail.html")

2) get_absolute_url

  • models.py에서 get_absolute_url을 오버라이딩 하면, Admin Panel에서 바로 절대경로의 해당 웹페이지로 이동할 수 있는 버튼을 주어줘요.
  • 매번 Admin Panel에서 pk값을 확인한 뒤, 해당 경로를 직접 찾아들어가는 수고로움을 덜어줍니다.
  • get_absolute_url에서 namespace와 name값을 통해 간단히 경로를 지정하려면 reverse가 필요합니다.
    • 🔎 from django.urls import reverse
  • 상세목록일 경우, pk값이 필요하기 때문에 kwargs를 통해 url 변수가 뒤에 붙을 수 있도록 합니다.
    • 🔎 reverse("[namespace값]:[name값]", kwargs={"pk": self.pk})
# rooms/models.py
from django.db import models
from django.urls import reverse
from django_countries.fields import CountryField
from core import models as core_models
class Room(core_models.TimeStampedModel):
    """Room Model Definifion"""
    ...
    ...
    def get_absolute_url(self):
        return reverse("rooms:detail", kwargs={"pk": self.pk})

3) DoesNotExis vs Http404()

  • 상세 목록은 해당 객실정보에 대한 object가 필요하기 때문에 get을 사용해 pk값을 기준으로 context를 만들어 전달해주면 됩니다.
  • 대다수의 사용자는 링크를 통해 상세목록에 접근하지만,, url에 직접 pk를 넣어 접근하는 사용자가 있을 수도 있어요. 만일 존재하지 않는 pk값을 url로 요청하면 어떤 결과가 벌어질까요?
  • DoesNotExis란 에러가 발생합니다. 이를 처리해주기 위해, DoesNotExis가 발생할 경우 home으로 이동할 수 있도록 redirect를 해줍시다.
  • 또한 reverse는 namespace와 name으로 경로를 쉽게 잡아주는데,, 특히, View와 Model에서 자주 활용됩니다!
    • 🔎 return redirect(reverse("[namespace]:[name]"))
from django.urls import reverse 👈 reverse 가져와요:)
from django.shortcuts import redirect, render
from . import models
    ...
    ...
def room_detail(request, pk):
    try:  # 👈 존재하는 pk값으로 접근하는 경우,
        room = models.Room.objects.get(pk=pk)
        context = {"room": room}
        return render(request, "rooms/detail.html", context)
    except models.Room.DoesNotExist: # 👈 존재하지 않는 pk로 접근할 경우,
        return redirect(reverse("core:home"))
  • Http404()를 활용하는 방법도 존재해요. Http404()는 사용자에게 잘못된 페이지에 접근되었다는 것을 웹페이지를 통해 알려줄 수 있어요!
  • Http404를 import한 뒤, pk값이 존재하지 않는다면 Http404()를 raise해주면 손쉽게 가능합니다.
    • 🔎 raise Http404()
from django.http import Http404 👈 Http404 가져와요:)
from django.shortcuts import render
from . import models
    ...
    ...
def room_detail(request, pk):
    try:  # 👈 존재하는 pk값으로 접근하는 경우,
        room = models.Room.objects.get(pk=pk)
        context = {"room": room}
        return render(request, "rooms/detail.html", context)
    except models.Room.DoesNotExist: # 👈 존재하지 않는 pk로 접근할 경우,
        raise Http404()

  • 위 처럼 나오는 것은 DEBUG=True 모드이기 때문이에요, 실제 서비스를 할 떄는 DEBUG=False를 사용해요.
# settgins.py
DEBUG = False
ALLOWED_HOSTS = "*"  # 👈 DEBUG=False로 TEST할 때, 모두 허용으로 바꿔주세요:) 
  • Http404() 페이지를 직접 만들어서 이런 상황에 사용자에게 전달할 수도 있어요. Django는 templates 디렉토리 바로 아래 있는 "404.html"을 자동으로 찾아 띄어줍니다. 즉, View에서 "raise Http404()"를 지정한 것만으로 templates 디렉토리에서 "404.html"을 찾아 띄어주는 거에요:)
# 404.html
{% extends "base.html" %}
{% block page_title %}
    Not found
{% endblock page_title %}
{% block content %}
    <h1>Not found... Plz...</h1>
{% endblock content %}

4) 템플릿에서 ForeignKey & ManyToManyField 사용하기

  • 템플릿 변수로 room을 전달했기 떄문에 room을 통해 DB에 접근할 수 있어요:)
  • 객실명, 설명, superhost여부, amenities, facilities, house_rules을 아래처럼 나타낼 수 있어요.
{% extends "base.html" %}
    {% block page_title %}
        {{room.name}}
    {% endblock page_title %}
    {% block content %}
    <div>
        <h1>{{room.name}}</h1>
        <h3>{{room.description}}</h3>
    </div>
    <div>
        <h2>
            By : {{room.host.username}} 👈 ForeignKey로 host 표시
            {% if room.host.superhost %} 👈 superhost라면 (superhost) 명시
                (superhost)
            {% endif %}
        </h2>
        <h3>Amenities</h3>
        <ul>
            {% for i in room.amenities.all %} 👈 ManyToManyField 사용
                <li>{{i}}</li>
            {% endfor %}
        </ul>
        <h3>Facilities</h3>
        <ul>
        {% for i in room.facilities.all %} 👈 ManyToManyField 사용
            <li>{{i}}</li>
        {% endfor %}
        </ul>
        <h3>House Rules</h3>
        <ul>
            {% for i in room.house_rules.all %}  👈 ManyToManyField 사용
                <li>{{i}}</li>
            {% endfor %}
        </ul>
    </div>
    {% endblock content %}


2. CBV로 상세페이지 구현

1) DetailView

  • 목록을 만들 때 ListView를 상속받아 사용하는 것처럼, 상세보기는 DetailView를 상속받아 구현할 수 있어요.
  • ListView가 [모델명]_list.html를 찾았던것 처럼, DetailView는 [모델명]_detail.html 템플릿 찾고 있기 때문에 파일명을 수정해주어야 합니다. CBV는 별도의 render가 없기 때문에 Django에서 스스로 찾고있는 있는 템플릿명으르 사용하면 됩니다. 어떤 템플릿을 찾고 있는지 에러 메시지에 나오기 때문에 쉽게 알 수 있어요.
  • FBV에서 사용했던 템플릿을 파일명만 수정해서 그대로 사용하면 되는데요,, CBV를 사용하기 때문에 'rooms/url.py'에 CBV를 사용한다는 것을 as.view()로 알려줄께요:)
# rooms/url.py
from django.urls import path
from . import views
app_name = "rooms"
urlpatterns = [
    path("<int:pk>", views.RoomDetail.as_view(), name="detail"), # 👈 CBV 사용
]
  • CBV를 사용하면 View에서 argument를 받을 필요가 없어요, urls.py에서 argument가 존재하는 것을 보고 DetailView에서 알아서 해당 pk값을 처리합니다.
# rooms/views.py
from django.views.generic import ListView, DetailView
from . import models
...
...
class RoomDetail(DetailView):
    """RoomDetail Definition"""    
    model = models.Room

  • 뿐만아니라 Http404()를 import하지도 않고, try 구문을 통해 처리하지 않았는데도 알아서 404.html파일을 찾아 처리해줍니다. 이렇듯 CBV를 사용하면, 코드가 확연히 줄어들지만 어떻게 동작하는지 로직을 직관적으로 이해하는데는 어려움이 있을 수 있겠어요:)
profile
Keep Going, Keep Coding!

0개의 댓글