予約サイト、マイページ作成③

Python Django

概要

Djangoで、シンプルな予約サイトの作成シリーズの1つです。今回はマイページに、休暇の追加や予約の更新、削除機能をつけていきます。

予約の更新

予約更新の様子

booking/urls.pyを次のようにします。

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'),

    path('login/', LoginView.as_view(template_name='admin/login.html'), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('mypage/', views.MyPage.as_view(), name='my_page'),
    path('mypage/<int:pk>/', views.MyPageWithPk.as_view(), name='my_page_with_pk'),
    path('mypage/<int:pk>/calendar/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/calendar/<int:year>/<int:month>/<int:day>/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/config/<int:year>/<int:month>/<int:day>/', views.MyPageDayDetail.as_view(), name='my_page_day_detail'),

    # 追加
    path('mypage/schedule/<int:pk>/', views.MyPageSchedule.as_view(), name='my_page_schedule'),
]

booking/views.pyに、次のコードを追加します。

from django.urls import reverse_lazy  # 追加

# 追加
class OnlyScheduleMixin(UserPassesTestMixin):
    raise_exception = True

    def test_func(self):
        schedule = get_object_or_404(Schedule, pk=self.kwargs['pk'])
        return schedule.staff.user == self.request.user or self.request.user.is_superuser


# 追加
class MyPageSchedule(OnlyScheduleMixin, generic.UpdateView):
    model = Schedule
    fields = ('start', 'end', 'name')
    success_url = reverse_lazy('booking:my_page')

更新なので、UpdateViewを使います。また、自分が担当する予約は自分だけ(もしくはスーパーユーザーも)見れるように、新しいMixinを作ります。これはURLにあるScheduleのpkをもとに、その予約が自分担当ならばTrueを返します。

bookinh/schedule_form.htmlを作りましょう。

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

{% block content %}

    <h1>{{ schedule.staff.store.name }}店 {{ schedule.staff.name }}</h1>
    <form action="" method="POST">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit">送信</button>
    </form>
{% endblock %}

一日の予約状況詳細ページや、マイページのトップに表示していた予約をリンクにして、この更新ページに飛ぶようにしましょう。

booking/my_page.htmlは、次のように書き換えます。

<a href="{% url 'booking:my_page_schedule' schedule.pk %}">{{ schedule }}</a>

booking/my_page_day_detail.htmlも書き換えます。

<a href="{% url 'booking:my_page_schedule' s.pk %}">{{ s.name }}</a>

予約の削除

更新ページも作ったので、そのページに削除ボタンも作ってみます。まず、booking/urls.pyです。

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'),

    path('login/', LoginView.as_view(template_name='admin/login.html'), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('mypage/', views.MyPage.as_view(), name='my_page'),
    path('mypage/<int:pk>/', views.MyPageWithPk.as_view(), name='my_page_with_pk'),
    path('mypage/<int:pk>/calendar/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/calendar/<int:year>/<int:month>/<int:day>/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/config/<int:year>/<int:month>/<int:day>/', views.MyPageDayDetail.as_view(), name='my_page_day_detail'),
    path('mypage/schedule/<int:pk>/', views.MyPageSchedule.as_view(), name='my_page_schedule'),

    # 追加
    path('mypage/schedule/<int:pk>/delete/', views.MyPageScheduleDelete.as_view(), name='my_page_schedule_delete'),
]

booking/views.pyに、削除ビューを追加します。

# 追加
class MyPageScheduleDelete(OnlyScheduleMixin, generic.DeleteView):
    model = Schedule
    success_url = reverse_lazy('booking:my_page')

削除処理は更新ページのボタンで行います。削除確認ページとかは作らないので、別途テンプレートファイルは作りません。booking/schedule_form.htmlを編集します。

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

{% block content %}

    <h1>{{ schedule.staff.store.name }}店 {{ schedule.staff.name }}</h1>
    <form action="" method="POST">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit">送信</button>
    </form>
    <hr>
    <form action="{% url 'booking:my_page_schedule_delete' schedule.pk %}" method="POST">
        {% csrf_token %}
        <button type="submit">削除</button>
    </form>
{% endblock %}

下側にform要素が増えましたね。これが削除ボタンです。

休暇の追加

こういった予約サイトのスタッフは、好きな日に休暇を入れたり、曜日ごとの勤務時間とか、月のシフト的なものの登録ができることも多いです。今回はシンプルな休暇機能を実装します。

まず、booking/urls.pyです。

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'),

    path('login/', LoginView.as_view(template_name='admin/login.html'), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('mypage/', views.MyPage.as_view(), name='my_page'),
    path('mypage/<int:pk>/', views.MyPageWithPk.as_view(), name='my_page_with_pk'),
    path('mypage/<int:pk>/calendar/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/calendar/<int:year>/<int:month>/<int:day>/', views.MyPageCalendar.as_view(), name='my_page_calendar'),
    path('mypage/<int:pk>/config/<int:year>/<int:month>/<int:day>/', views.MyPageDayDetail.as_view(), name='my_page_day_detail'),
    path('mypage/schedule/<int:pk>/', views.MyPageSchedule.as_view(), name='my_page_schedule'),
    path('mypage/schedule/<int:pk>/delete/', views.MyPageScheduleDelete.as_view(), name='my_page_schedule_delete'),

    # 追加
    path('mypage/holiday/add/<int:pk>/<int:year>/<int:month>/<int:day>/<int:hour>/', views.my_page_holiday_add, name='my_page_holiday_add'),
]

そしてビューです。今回は関数ビューにしました。

# 追加
from django.core.exceptions import PermissionDenied
from django.views.decorators.http import require_POST


# 追加
@require_POST
def my_page_holiday_add(request, pk, year, month, day, hour):
    staff = get_object_or_404(Staff, pk=pk)
    if staff.user == request.user or request.user.is_superuser:
        start = datetime.datetime(year=year, month=month, day=day, hour=hour)
        end = datetime.datetime(year=year, month=month, day=day, hour=hour + 1)
        Schedule.objects.create(staff=staff, start=start, end=end, name='休暇(システムによる追加)')
        return redirect('booking:my_page_day_detail', pk=pk, year=year, month=month, day=day)

    raise PermissionDenied

他のビューと同様に、自分が担当する予約か、スーパーユーザーのみが呼び出せるビューです。やっていることは非常にシンプルで、予約をシステムで一つ追加しているだけです。その予約者名を「休暇(システムによる追加)」といったものにしているだけ。休暇というか、その時間の枠を自分で埋めている感じですね。

勿論、ここのやり方は他にも色々あります。今回のは極力楽をした、シンプルな実装です。休暇を表すような専用のモデルを作ったり、Scheduleに「通常予約」とか「休暇」とか選べるようなフィールドを作っても良いでしょう。

booking/my_page_day_detail.htmlを編集します。

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

{% block content %}

    <h1>{{ staff.store.name }}店 {{ staff.name }}</h1>
    <p>{{ view.kwargs.year }}年{{ view.kwargs.month }}月{{ view.kwargs.day }}日の予約一覧</p>
    <table class="table table-bordered text-center" style="table-layout: fixed;width: 100%" border="1">
        {% for hour, schedules in calendar.items %}
            <tr style="font-size:12px">
                <td>
                    {{ hour }}:00
                </td>
                <td>
                    {% if schedules %}
                        {% for s in schedules %}
                            <a href="{% url 'booking:my_page_schedule' s.pk %}">{{ s.name }}</a>
                        {% endfor %}
                    {% else %}
                        <form action="{% url 'booking:my_page_holiday_add' staff.pk view.kwargs.year view.kwargs.month view.kwargs.day hour %}"
                              method="POST">
                            {% csrf_token %}
                            <button type="submit">休暇にする</button>
                        </form>
                    {% endif %}
                </td>
            </tr>
        {% endfor %}

    </table>
{% endblock %}

違いは、20行目あたりに休暇ボタンを入れたことです。これで、好きな時間に休暇を入れることができます。休暇にしたら、ちゃんと予約不可の×と表示されますね。

休暇

時間ではなく日の単位で休暇を入れるとかも簡単にできるので、必要だったら作ってみましょう。

Relation Posts

Comment

記事にコメントする

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