[PROJECT] AIRBNB CLONING #4

Room Detail API

Room Detail 페이지에서 User가 Superhost인지의 여부, User의 이미지, Amenity와 Facility와 같은 편의시설, Reservation, 체크인 날짜와 숙소의 숙박이 가능한 날짜, 그리고 리뷰와 리뷰에 들어갈 이미지, 호스팅 지역, 숙소 규칙 등의 정보가 들어가야 합니다. 여러개의 API가 한 페이지에 합쳐져 잘게 쪼개서 진행했습니다.

디데일 API 코드는 다음과 같습니다.

config/urls

from django.urls import path, include

urlpatterns = [
    path("rooms", include('rooms.urls')),
]

rooms/urls

from django.urls import path

from rooms.views import RoomDetailView

urlpatterns = [
    path('/<int:room_id>', RoomDetailView.as_view()),
] 

Path Paramter를 적용했습니다. id가 1번인 room의 uri는 /rooms/1이 됩니다.

rooms/views

from django.http  import JsonResponse
from django.views import View

from rooms.models import Room, RoomAmenity, RoomHouseRule

class RoomDetailView(View):
    def get(self, request, room_id):

        if not Room.objects.filter(id=room_id).exists():
            return JsonResponse({'message': 'ROOM_DOES_NOT_EXIST'}, status=404)

        room = Room.objects.select_related('category')\
                           .prefetch_related('room_amenities', 'room_houserules', 'room_images', 'room_schedules').get(id=room_id)
	result = {
            "name"            : room.name,
            "description"     : room.description,
            "district"        : room.district,
            "neighberhood"    : room.neighberhood,
            "price"           : float(room.price),
            "address"         : room.address,
            "guests"          : int(room.guests),
            "beds"            : room.beds,
            "bedrooms"        : room.bedrooms,
            "baths"           : room.baths,
            "latitute"        : float(room.latitute),
            "longitute"       : float(room.longitute),
            "host"            : room.user.nickname,
            "host_image"      : room.user.profile_image,
            "category"        : room.category.type,
            "room_images_url" : [image.image_url for image in room.room_images.all()],
            "check_in"        : [schedule.check_in for schedule in room.room_schedules.all()],
            "room_amenities"  : [{
                    "amenity_id"       : amenity.id,
                    "amenity_name"     : amenity.amenity.name,
                    "amenity_icon_url" : amenity.amenity.icon_url,
                }for amenity in RoomAmenity.objects.filter(room_id=room_id)],
            "check_in_time"  : room.check_in_time,
            "check_out_time" : room.check_out_time,
            "house_rules" : [{
                    "room_rules"     : rules.house_rule.name,
                    "rules_icon_url" : rules.house_rule.icon_url,
                }for rules in RoomHouseRule.objects.filter(room_id=room_id)]    
        }
        return JsonResponse({'message' : result}, status=200)

Django의 ORM을 최적화하기 위해 selected_relatedprefetch_related를 사용하였습니다.

ORM
ORM은 객체(object)와 관계형 데이터베이스(Relational Database)의 데이터를 매핑해주는 것을 의미합니다. 요약하자면 데이터베이스와 객체지향 프로그래밍 언어간의 호환되지 않는 데이터를 변환해주는 프로그래밍 기법입니다.

Django ORM을 사용할 때 Query 개수를 줄일 수 있는 방법으로 select_relatedprefetch_related가 있습니다. 이를 활용하면 불로온 데이터가 모두 캐시에 남아있게 되어 DB에 히트하는 수를 줄여 성능을 향상시킬 수 있는데요!

selected_related
selected_related는 SQL Query 문의 JOIN 을 사용하여 foreign-key(one to one, many to one)를 사용하여 정참조할 때 사용하며 QuerySet을 가져올 때, 미리 related objects까지 불러오는 함수입니다.

이를 활용하여 데이터베이스에 접근하는 빈도를 줄일 수 있습니다.

prefetch_related
selected_related는 하나의 Query로 related Objects들을 불러오지만, Prefetch_related는 main query가 실행이 된 후 별도의 query가 실행이 됩니다.

다음은 몇 개의 쿼리가 찍혔는지, 몇 초가 결렸는지를 확인한 사진입니다.

좋은 웹페이지 즐겨찾기