メインのページを作っていきます(ちなみにここら辺から頭の中がごちゃごちゃしてきた)。
ちなみに現時点での画面はこんな感じ。
URLの設定
まずはURLconfの設定から。今回は http://shift-maker/2014/5/15/shift/ みたいなURLにして年月の数値を組み込んで、その数値をビュー関数に持って行くことでデータに接続する感じにしたいので以下のようになりました。
url.py
#...
month_url = r'(?P<year_num>\d+)\-(?P<month_num>\d+)' # 使い回す予感がしたので変数として定義した。年と月の数値をyear_num,month_numとしてviews.pyに持っていける。
urlpatterns += patterns('schedule.views',
url(r'^$', 'home', name="Home"), # ところでこのname属性の意味が意味一つ分からない(とりあえず設定しているが)
url(r'^%s/shift/$' % (month_url,),'a_month_shift',name="MonthShift"),
)
#...
ホームページは深く考えずおまけで設定しておきました。
2.ビュー関数
毎月のシフト制作ページを作る場合、その月の内容(日付とか曜日など)を取得しなければならないのですが、Pythonにはcalendarという便利なモジュールがあるのでそれを活用しています。
今回はowner/models.pyのGroupScheduleモデル内にget_calendarという関数として書いてあります。
schedule/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render,redirect
@login_required
def home(req):
from datetime import datetime
now = datetime.now()
return redirect( '/%s-%s/shift/' % (now.year,now.month,) ) # 自動的に今月のシフト画面にリダイレクト
@login_required
def a_month_shift(req,year_num,month_num):
from owner.models import GroupSchedule
from schedule.models import WorkTime,MonthShift,StaffSchedule,NgShift,GuestSchedule
from datetime import date
year,month = int(year_num),int(month_num)
try:
groupschedule = GroupSchedule.objects.get(owner=req.user)
except GroupSchedule.DoesNotExist: # シフト設定が出来てなければ
return redirect('/owner/schedule/edit') # 設定画面へ
monthshift,created = groupschedule.monthshift_set.get_or_create(year=year,month=month,groupschedule=req.user.groupschedule) # get_or_createはいちいちtry文を書かずに済む便利なショートカット。左辺が二つあることに注意(二つ目が何かは今のところ不明)
if req.method == 'POST':
posted = req.POST
s_year,s_month,s_day = int(posted['year']),int(posted['month']),int(posted['day']) # s_というのはstaffschedule_の略。日付情報をPOSTデータから受け取り・・・
s_date = date( year=s_year,month=s_month,day=s_day ) # dateオブジェクトとして変数化
try: # POSTされた日付とスタッフ情報からStaffScheduleを取得するか・・・
s_schedule = StaffSchedule.objects.get( date=s_date,staff=int(posted['staff']) )
except StaffSchedule.DoesNotExist: # 無ければ作成
from staff.models import Staff
s_schedule = StaffSchedule(date=s_date)
s_schedule.staff = Staff.objects.get( id=int(posted['staff']) )
s_schedule.monthshift = monthshift
s_schedule.worktime = WorkTime.objects.get( id=int(posted['shift']) ) # StaffScheduleのWorkTimeを確定し・・・
s_schedule.save() # 保存
month_cal = groupschedule.get_calendar(year,month) # GroupScheduleモデルに定義したget_calendarから月情報を取得
return render(req,'schedule/a_month_shift.html',{
'year':year_num, # そのままページタイトルなどに使う
'month':month_num, # 同上
'month_cal':month_cal, # カレンダー情報
'monthshift':monthshift, # まだ使っていないが
'weekdays':['月','火','水','木','金','土','日',], # 曜日の表示方法(デフォルトだとSundayとかになるので馴染みづらい)
'staffs':groupschedule.staff_set.order_by('id'),
'worktimes':groupschedule.worktime_set.order_by('id'),
})
テンプレート
あとはそれっぽくテンプレートを書きます。まずはアプリケーション用のベースを作りました(しかし分ける必要があったのかは微妙)。
templates/schedule/bases/base_a_month.html
{% extends 'bases/base.html' %}
{% block title %} {{ year_num }}-{{ month_num }} {% endblock %}
{% block main %}
<!--ここから-->
<a href="/logout">Log out</a>
<a href="/staff/new"><button class="btn btn-success">Add New Staff</button></a>
<!--ここまではテキトーに入れたのでレイアウトがガタガタ-->
<ul class="pager">
<li class="previous">
{% ifnotequal month '1' %}
<a href="/{{ year }}-{{ month|add:'-1' }}/shift">前月</a>
{% else %}
<a href="/{{ year|add:'-1' }}-12/shift">前月</a>
{% endifnotequal %}
</li>
<li class="next">
{% ifnotequal month '12' %}
<a href="/{{ year }}-{{ month|add:"1" }}/shift">次月</a>
{% else %}
<a href="/{{ year|add:'1' }}-1/shift">次月</a>
{% endifnotequal %}
</li>
</ul>
<h1><small>{{ year }}-</small>{{ month }}</h1> <!--見出し。何年の何月?-->
<table class="table table-bordered {% block t_class %}{% endblock %}">
{% block t_main %}
<!--ここにメインコンテンツを入れる-->
{% endblock %}
</table>
{% endblock main %}
で、以下がメインコンテンツです。
templates/schedule/a_month_shift.html
{% extends "schedule/bases/base_a_month.html" %}
{% block title %} Shift:{{ year }}/{{ month }}-{{ month|add:1 }} {% endblock %}
{% block t_main %}
<script type="text/javascript" src="{{ STATIC_URL }}js/a_month_shift.js"></script>
<link type="text/css" rel="stylesheet" href="{{ STATIC_URL }}css/a_month_shift.css"> <!--現時点では作っていないが-->
{% load schedule_controler %} {# 自作したフィルターの読み込み #}
<thead>
<tr align="center" class="info"> <!--日付-->
<th rowspan="2"></th>
{% for cal in month_cal %} {# カレンダーを一日ずつ表示 #}
<th class="day_{{ cal.day }}">{{ cal.day }}</th>
{% endfor %}
{% for worktime in worktimes %} {# 登録してあるWorkTimeを一つずつ表示(勤務時間ごとの統計をするための見出し) #}
<th rowspan="2">{{ worktime.title }}</th>
{% endfor %}
</tr>
<tr class="info"> <!--曜日-->
{% for cal in month_cal %}
<th class="day_{{ cal.day }}">{{ weekdays|index_is:cal.weekday }}</th> {# index_isは自作フィルター #}
{% endfor %}
</tr>
</thead>
<tbody>
{% for staff in staffs %}
<tr align="center">
<th class="info" staff_id="{{ staff.id }}">{{ staff }}</th> <!--staff_id要素はjsで使う-->
{% for cal in month_cal %}
<td class="day_{{ cal.day }}" id="s{{ staff.id }}d{{ cal.day }}">
{% include 'schedule/parts/dropdown.html' %} {# ドロップダウンでのWorkTime選択部分をパーツとして別ファイルに作成してあるので、それをここで読み込む感じ #}
</td>
{% endfor %}
{% for worktime in worktimes %}
<td>
{% with staff.staffschedule_set|worktime_filter:worktime as worktime_set %} {# worktime_filterと・・・ #}
{% with worktime_set|monthshift_filter:monthshift as month_worktime_set %} {# monthshift_filterも自作 #}
{{ month_worktime_set.count }} {# countというのは組み込みの便利メソッドで、ここではWorkTimeごとの統計をするために使用 #}
{% endwith %}
{% endwith %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
{% endblock t_main %}
いくつかの箇所で自作フィルターを使用していますが、これはアプリケーションディレクトリ直下に templatetags というディレクトリを新たに用意しそこに作成すると呼び出せるようになります。参考:http://docs.djangoproject.jp/en/latest/howto/custom-template-tags.html
それらの自作フィルターを書いた schedule_controler.py や a_month_shift.js 、 dropdown.html などは長くなりそうなので次回にしようと思います。