予約サイトの、予約送信ページ

Python Django

概要

Djangoで、シンプルな予約サイトの作成シリーズの1つです。前回予約状況のカレンダーページを作りましたので、今回は実際に予約をするためのページ・機能を作っていきます。

予約の様子

URL定義

booking/urls.pyを編集します。

from django.urls import path
from . import views

app_name = 'booking'

urlpatterns = [
    path('', views.StoreList.as_view(), name='store_list'),
    path('store/<int:pk>/staffs/', views.StaffList.as_view(), name='staff_list'),
    path('staff/<int:pk>/calendar/', views.StaffCalendar.as_view(), name='calendar'),
    path('staff/<int:pk>/calendar/<int:year>/<int:month>/<int:day>/', views.StaffCalendar.as_view(), name='calendar'),

    # 追加
    path('staff/<int:pk>/booking/<int:year>/<int:month>/<int:day>/<int:hour>/', views.Booking.as_view(), name='booking'),
]

スタッフのpkと、予約日時、時間をURLに含めるようにしておきます。

ビュー

# これらのimportが増えています
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect


class Booking(generic.CreateView):
    model = Schedule
    fields = ('name',)
    template_name = 'booking/booking.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['staff'] = get_object_or_404(Staff, pk=self.kwargs['pk'])
        return context

    def form_valid(self, form):
        staff = get_object_or_404(Staff, pk=self.kwargs['pk'])
        year = self.kwargs.get('year')
        month = self.kwargs.get('month')
        day = self.kwargs.get('day')
        hour = self.kwargs.get('hour')
        start = datetime.datetime(year=year, month=month, day=day, hour=hour)
        end = datetime.datetime(year=year, month=month, day=day, hour=hour + 1)
        if Schedule.objects.filter(staff=staff, start=start).exists():
            messages.error(self.request, 'すみません、入れ違いで予約がありました。別の日時はどうですか。')
        else:
            schedule = form.save(commit=False)
            schedule.staff = staff
            schedule.start = start
            schedule.end = end
            schedule.save()
        return redirect('booking:calendar', pk=staff.pk, year=year, month=month, day=day)

予約の開始時間と時間帯は、URLに含まれていますね。それを使います。

start = datetime.datetime(year=year, month=month, day=day, hour=hour)

今のところ、この予約サイトでは全ての予約を1時間単位で扱います。予約の開始日時と時間帯がわかれば、終了時間も自然と決まるということです。1時間後ですね。

end = datetime.datetime(year=year, month=month, day=day, hour=hour + 1)

予約開始の日時はロジック上、〇時0分0秒となりますので、その時間の予約が既にあるかどうかの確認も簡単です。既に予約が入っていた場合、これは入れ違いで誰かが予約した場合ですが、メッセージフレームワークを使ってお伝えすることにします。

        if Schedule.objects.filter(staff=staff, start=start).exists():
            messages.error(self.request, 'すみません、入れ違いで予約がありました。別の日時はどうですか。')

問題がなければ予約を作成します。必要ならば、メールの送信などもここで行うことになるでしょう。

        else:
            schedule = form.save(commit=False)
            schedule.staff = staff
            schedule.start = start
            schedule.end = end
            schedule.save()

予約カレンダーからリンクを張る

booking/calendar.htmlを開いて、リンク部分を今回作ったビューにしましょう。

<a href="{% url 'booking:booking' staff.pk dt.year dt.month dt.day hour %}">○</a>

テンプレートファイル

booking/booking.htmlを作ります。

{% extends 'booking/base.html' %}

{% block content %}
    <h1>{{ staff.store.name }}店 {{ staff.name }}</h1>
    <p>{{ view.kwargs.year }}年{{ view.kwargs.month }}月{{ view.kwargs.day }}日 {{ view.kwargs.hour }}時に予約</p>
    <form action="" method="POST">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit">送信</button>
    </form>
{% endblock %}

そんなに難しいことはしていません。{{ view.kwargs.year }}のような記述が気になるかもしれませんが、クラスベースビューはテンプレートファイルで{{ view }}という名前が使えます。これはビューオブジェクトそのものです。ビューの中でself.でアクセスできるものは、ここで同様にアクセスできるということです。self.kwargs['year']は、{{ view.kwargs.year }}ですね。

最後に、入れ違いで予約があった場合はメッセージフレームワークを使ってお伝えするので、そのメッセージを表示するためのコードをbooking/base.htmlに書いておきます。{% block content %}{% endblock %}の上にでも追記しておきましょう。

<!-- この部分を追加 -->
{% for message in messages %}
    <p> {{ message }}</p>
{% endfor %}

{% block content %}{% endblock %}

FAQ

入れ違いでの予約というのは、どういうケースでしょうか

入れ違いの例

上の画像では、10日の9時は〇になっています。予約送信ページに進んで、「送信」ボタンを押すと×に変わりますが、送信ボタンを押すまでは〇のままです。なので、送信ボタンを押すまでに何人かの人が予約送信ページに入ってきてしまう可能性があるということです。

そして、それらの人が送信を押すと、最初のひとり以降は「すみません、入れ違いで予約がありました。別の日時はどうですか。」が表示されることになります。

各時間の予約を2件まで、等にしている場合

次のような感じで、その時間のスケジュールの数を確認するようにしましょう。

        # 既に2件以上の予約があれば、ダメ
        if Schedule.objects.filter(staff=staff, start=start).count() >= 2:
            messages.error(self.request, 'すみません、入れ違いで予約がありました。別の日時はどうですか。')
        else:
            schedule = form.save(commit=False)
            schedule.staff = staff
            schedule.start = start
            schedule.end = end
            schedule.save()
        return redirect('booking:calendar', pk=staff.pk, year=year, month=month, day=day)

Relation Posts

Comment

記事にコメントする

まだコメントはありません。