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

Python Django

概要

Djangoで、シンプルな予約サイトの作成シリーズの1つです。今回はマイページのカレンダーや、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'),
]

前に作ったカレンダーと同様、指定した年月日を基準に表示する場合と、何も指定しない場合(当日から)の2つ用意しておきます。

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

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

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


# 追加
class MyPageCalendar(OnlyStaffMixin, StaffCalendar):
    template_name = 'booking/my_page_calendar.html'

カレンダーの作成処理自体は、以前作ったものと同様です。ただし今回は、自分のマイページカレンダーは自分しか見れないようにしたいと思います。

今回はURL内にStaffのpkが含まれているので、そのpk、もといStaffはログインユーザーに紐づいているものか?をチェックすれば良さそうです。それをしているのが、次のMixinですね。

class OnlyStaffMixin(UserPassesTestMixin):
    raise_exception = True

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

後は、このMixinをマイページカレンダービューに使っているだけです。

テンプレートファイルは、少し以前と変えています。booking/my_page_calendar.htmlとして作ります。

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

{% block content %}

    <h1>{{ staff.store.name }}店 {{ staff.name }}</h1>
    <p>{{ start_day }} - {{ end_day }}</p>
    <table class="table table-bordered text-center" style="table-layout: fixed;width: 100%" border="1">
        <tr>
            <td><a href="{% url 'booking:my_page_calendar' staff.pk before.year before.month before.day %}">前週</a></td>
            {% for day in days %}
                {% if day in public_holidays %}
                    <th style="background-color: yellow">{{ day | date:"d(D)" }}
                {% elif day.weekday == 5 %}
                    <th style="color: blue;">{{ day | date:"d(D)" }}
                {% elif day.weekday == 6 %}
                    <th style="color: red;">{{ day | date:"d(D)" }}
                {% else %}
                    <th>{{ day | date:"d(D)" }}
                {% endif %}
                <br><a href="">詳細</a>
            {% endfor %}
            <td><a href="{% url 'booking:my_page_calendar' staff.pk next.year next.month next.day %}">次週</a></td>
        </tr>

        {% for hour, schedules in calendar.items %}
            <tr style="font-size:12px">
                <td>
                    {{ hour }}:00
                </td>
                {% for dt, book in schedules.items %}
                    <td>
                        {% if book %}
                            ○
                        {% else %}
                            ×
                        {% endif %}
                    </td>

                {% endfor %}
                <td>
                    {{ hour }}:00
                </td>
            </tr>
        {% endfor %}

    </table>
{% endblock %}

マイページのカレンダー

前と違う部分が幾つかあります。まず、当日以前でも〇や×として表示されていて、過去の日の予約状況も確認できるようにしてみました。それと、各日の部分に「詳細」というリンクを作っています。これを押すことで、その日の予約詳細ページに移動するようにします。

最後に、マイページトップのスタッフをクリックで、これらのカレンダーページに移動できるようにしておきましょう。booking/my_page.htmlです。

        {% for staff in staff_list %}
            <li><a href="{% url 'booking:my_page_calendar' staff.pk %}">{{ staff }}</a></li>
        {% empty %}
            <li>まだ店舗がありません。</li>
        {% endfor %}

一日の予約状況詳細ページ

各日の、予約状況詳細ページを作っていきます。

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

そして、booking/views.pyです。

class MyPageDayDetail(OnlyStaffMixin, generic.TemplateView):
    template_name = 'booking/my_page_day_detail.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        pk = self.kwargs['pk']
        staff = get_object_or_404(Staff, pk=pk)
        year = self.kwargs.get('year')
        month = self.kwargs.get('month')
        day = self.kwargs.get('day')
        date = datetime.date(year=year, month=month, day=day)

        # 9時から17時まで1時間刻みのカレンダーを作る
        calendar = {}
        for hour in range(9, 18):
            calendar[hour] = []

        # カレンダー表示する最初と最後の日時の間にある予約を取得する
        start_time = datetime.datetime.combine(date, datetime.time(hour=9, minute=0, second=0))
        end_time = datetime.datetime.combine(date, datetime.time(hour=17, minute=0, second=0))
        for schedule in Schedule.objects.filter(staff=staff).exclude(Q(start__gt=end_time) | Q(end__lt=start_time)):
            local_dt = timezone.localtime(schedule.start)
            booking_date = local_dt.date()
            booking_hour = local_dt.hour
            if booking_hour in calendar:
                calendar[booking_hour].append(schedule)

        context['calendar'] = calendar
        context['staff'] = staff
        return context

予約状況のカレンダー作成と処理は似ていて、あれを1日のみにした感じです。

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 %}
                            {{ s.name }}
                        {% endfor %}
                    {% else %}
                    {% endif %}
                </td>
            </tr>
        {% endfor %}

    </table>
{% endblock %}

その日の予約状況が表示されます。このページは、今後改良します。予約をクリックで予約内容の変更・削除とか、休暇を入れれるようにするつもりです。

最後に、カレンダーぺージの詳細リンク部分を、今作ったビューにしましょう。booking/my_page_calendar.htmlを編集します。

<a href="{% url 'booking:my_page_day_detail' staff.pk day.year day.month day.day %}">詳細</a>

Relation Posts

Comment

記事にコメントする

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