Project using python/Cloning Airbnb

django 'reserve a room' by FBV

Cog Factory 2021. 3. 13. 11:16

url 설정

config/urls.py

urlpatterns = [
    path("reservations/", include("reservations.urls", namespace="reservations"))
]

rooms/urls.py

from django.urls import path
from reservations import views

app_name = "reservations"

urlpatterns = [
    path(
        "<int:room_pk>/create/<int:year>-<int:month>-<int:day>/",
        views.createReservation,
        name="create",
    ),
]

FBV(Function Based View)

rooms/views.py

# reservations/views.py


import datetime
from django.shortcuts import redirect, reverse
from django.contrib.auth.decorators import login_required
from django.contrib import messages

from reservations import models as reservation_models
from rooms import models as room_models


class CreateError(Exception):
    pass


@login_required
def createReservation(request, room_pk, year, month, day):
    try:
        room = room_models.Room.objects.get(pk=room_pk)
        date_obj = datetime.datetime(year, month, day)
        reservation_models.BookedDay.objects.get(day=date_obj, reservation__room=room)
        raise CreateError()
    except (room_models.Room.DoesNotExist, CreateError):
        messages.error(request, "Can't reserve that room")
        return redirect(reverse("core:home"))
    except reservation_models.BookedDay.DoesNotExist:
        reservation_models.Reservation.objects.create(
            status=reservation_models.Reservation.STATUS_PENDING,
            guest=request.user,
            room=room,
            check_in=date_obj,
            check_out=date_obj + datetime.timedelta(days=1),
        )

        messages.success(request, f"Reserve {room} successfully")
        return redirect(reverse("rooms:room-detail", kwargs={"pk": room_pk}))

utils/cal.py

# utils/cal.py


import calendar
from django.utils import timezone


class Day:
    def __init__(self, year, month, day, past):
        self.year = year
        self.month = month
        self.day = day
        self.past = past

    def __str__(self):
        return str(self.day)


class Calendar(calendar.Calendar):
    def __init__(self, year, month):
        super().__init__(firstweekday=6)
        self.year = year
        self.month = month
        self.day_names = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
        self.months = (
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December",
        )

    def get_month(self):
        return self.months[self.month - 1]

    def get_days(self):
        weeks = self.monthdays2calendar(self.year, self.month)
        days = []
        for week in weeks:
            for day, _ in week:
                now = timezone.now()
                this_month = now.month
                today = now.day
                past = False

                if this_month == self.month:
                    if day <= today:
                        past = True

                new_day = Day(year=self.year, month=self.month, day=day, past=past)
                days.append(new_day)
        return days

rooms/models.py

# rooms/models.py

class Room(core_models.TimeStampedModel):
    def get_calendar(self):
        now = timezone.now()
        year = now.year
        month = now.month
        next_month = month + 1

        if next_month == 13:
            next_month = 1
            next_year = year + 1
        else:
            next_year = year

        this_month_cal = Calendar(year, month)
        next_month_cal = Calendar(next_year, next_month)
        return [this_month_cal, next_month_cal]

templates

mixins/calendar.html

{% load is_booked %}

{% for cal in room.get_calendar %}
    <div class="{{w|default:'w-full'}} mb-10 rounded-lg shadow-lg p-5">
        <h3 class="font-bold text-lg flex justify-center mb-4">{{cal.get_month}} / {{cal.year}}</h3>
        <div class="cal-grid gap-x-1 mb-4">
        {% for day in cal.day_names %}
            <span class="font-medium">{{day}}</span>
        {% endfor %}
        </div>
        <div class="cal-grid gap-1">
        {% for day in cal.get_days %}
            {% is_booked room day as is_booked_bool%}
            {% if day.day == 0 %}
                <span></span>
            {% else %}
                {% if day.past %}
                    <span class="py-1 px-2 w-8 text-center text-base rounded bg-gray-200 text-white cursor-pointer line-through">{{day.day}}</span>   
                {% elif is_booked_bool %}
                    {% if day.day in days %}
                        <span class="py-1 px-2 w-8 text-center text-base rounded bg-green-500 text-white cursor-pointer">{{day.day}}</span>
                    {% else %}
                        <span class="py-1 px-2 w-8 text-center text-base rounded bg-gray-200 text-white cursor-pointer line-through">{{day.day}}</span>   
                    {% endif %}
                {% elif page == "reservation_page" %}
                    <span class="py-1 px-2 w-8 text-center text-base rounded bg-gray-400 text-white cursor-pointer hover:bg-red-400">{{day.day}}</span>
                {% else %}
                    <a href="{% url 'reservations:create' room.pk day.year day.month day.day %}" class="py-1 px-2 w-8 text-center text-base rounded bg-gray-400 text-white cursor-pointer hover:bg-red-400">{{day.day}}</a>
                {% endif %}
            {% endif %}
        {% endfor %}
        </div>
    </div>
{% endfor %}

reservations/templatetags/is_booked.py

from datetime import datetime
from django import template
from reservations import models as reservation_models

register = template.Library()


@register.simple_tag
def is_booked(room, day):
    if day.day == 0:
        return
    try:
        date_obj = datetime(year=day.year, month=day.month, day=day.day)
        reservation_models.BookedDay.objects.get(reservation__room=room, day=date_obj)
        return True
    except reservation_models.BookedDay.DoesNotExist:
        return False

참고 자료

  • 노마드 코더의 Airbnb 클론 강의
  • calendar

소스 코드

Calaendar : github.com/zpskek/airbnb-clone-v3/commit/aba16150b4b8cb445e2a345b55eaf05c929b0e0b

create-reservation : github.com/zpskek/airbnb-clone-v3/commit/c6e00500747d94d7407773dedd30ac2b36195ecc