スポンサーサイト

0

    一定期間更新がないため広告を表示しています


    • 2014.12.23 Tuesday
    • -
    • -
    • -
    • -
    • -
    • by スポンサードリンク

    djangoテンプレート上でmodelのメソッドに引数を渡す方法(djangoで出勤簿アプリ試作中♪)

    0
      久しぶりの更新^^;;
      GW明けに至急の仕事と打ち合わせが立て続けに入って、なかなかdjangoの研究(?)が進められませんでした。

      さて、昨日ようやく仕事が一段落ついた(納品物にOKもらって、請求書送付!)ので、突然の思いつきでdjangoで出勤簿アプリを作ってみることにしました。
      「出勤簿」、現在私はどこにも出勤せず自宅で仕事をしているので不要なんですが、昔(と言っても6年前)、学生時代のバイト先で、Excelフォーマットに手入力・手計算→→出勤・退勤時間だけ入力すれば後はExcel関数&マクロで自動計算に改造して、感謝された思い出のあるアプリです。
      完成度が高いものができれば、小規模事業所にWEBとセットで売れないかな?という魂胆もあり^^;挑戦してみました。

      modelは単純。
      ■社員…氏名(Char)・所属(Charにchoicesを設定)・退職者か?(Boolean)
      ■出退勤データ…どの社員のデータか?(社員のForeignKey)・日付(Date)・出勤時間(Time)・退勤時間(Time)・勤務時数(Time)・備考(Text)

      機能は、ひとまず
      ・社員1人1人のタイムカードを入力(←contrib.adminで)
      ・社員1人1人の月次集計表示「Aさんは○月、何時間働いたかな?」
      ・所属ごとの月次集計表示「Z部の皆さん(Aさん・Bさん・Cさん)は○月、それぞれ何時間働いたかな?」
      だけ。

      modelで変わった設定した部分。
      ・社員にカスタムマネジャ設定。退職者を除く社員リスト取得用。
      ・出退勤データのsaveをオーバーライド。


      model Data(models.Model):
      …(中略)…
      def save(self):
      import datetime
      delta_start_time = datetime.timedelta(
      hours=self.start_time.hour,minutes=self.start_time.minute)
      delta_end_time = datetime.timedelta(
      hours=self.end_time.hour,minutes=self.end_time.minute)
      self.hours=delta_end_time - delta_start_time


      ※時数計算の部分は「python time calculation」でぐぐって見つけた海外のpython MLから、timedeltaを使えばいいとわかったので、timedeltaを使って計算しています。

      さて、後はおなじみの、
      syncdb

      urls書き

      views書き書き(今回の件に関してgeneric viewを使う方法は思いつかなかった)

      テンプレートHTML書き


      で。
      ここまで来てハタと気づく。
      モデルのメソッドはプロパティ扱いで呼び出せるけど、引数を与えられない…@djangoのテンプレートシステム

      #symfonyではその辺いい加減と言うかテケトーというか、MVCの分離にそこまで厳格じゃないので、いよいよ困ったらテンプレートの中でPHPネイティブ関数を呼び出して実行させることも可能。(in_arrayでif分岐作っちゃったりとか余裕)


      これで、何が困るかと言うと
      ・所属ごとの月次集計表示「Z部の皆さん(Aさん・Bさん・Cさん)は○月、それぞれ何時間働いたかな?」
      これをやるときに、社員のリストをforで廻して、社員ごとに○月の労働時間数を表示したいという無謀なアイディアがあったので何とかして「○月」の集計だよ、という印を渡したい。


      {% for staff in staff_list %}
      {{ staff.name }}:{{ staff.get_monthly_total(year=y,month=m) }}
      {% endfor %}


      という感じにしたいのだが、当然エラー^^;;


      こうして、テンプレート上のループ内でモデルのメソッドに変数を渡す方法の研究を始める羽目になったのでした。丸1日かかりましたが、たった今何とかできました^^;

      以下が解決版コードです。細かいエラー処理とかは省略していますので、再利用する方はその辺ご自身でどぞ。
      ■models.py


      class Staff(models.Model):
      …中略…
      def get_monthly_total(
      self, year=datetime.now().year, month=datetime.now().month):
      data_records = Data.objects.all().filter(
      date__year=year, date__month=month, staff=self)
      import datetime
      total = datetime.timedelta()
      for data in data_records:
      total +=
      datetime.timedelta(hours=data.end_time.hour, minutes=data.end_time.minute)
      - datetime.timedelta(hours=data.start_time.hour, minutes=data.start_time.minute)
      return total



      ■views.py


      …前略…
      def monthly_total_of_section(
      request, year=datetime.now().year, month=datetime.now().month):
      staff_list = Staff.objects.all()
      year_and_month = year + '/' + month ★1-1
      return render_to_response('monthly_total_of_section.html',
      { 'staff_list':staff_list, 'year_and_month':year_and_month })
      …後略…



      ■templatetags/custom_filters.py


      …前略…
      @register.filter()
      def get_monthly_total_of_this_staff(value,args):
      from string import split, atoi
      from myproject.myapp.models import Staff
      list = args.split('/')  ★1-2
      m = list.pop()
      y = list.pop()
      return
      Staff.objects.get(pk=value).get_monthly_total(year=atoi(y), month=atoi(m)) ★2



      ■テンプレートのHTML

      {% load custom_filters %}
      {% for staff in staff_list %}
      {{ staff.name }}:{{ staff.id|get_monthly_total_of_this_staff:year_and_month }}
      {% endfor %}


      一見しておわかりの通り、使ったものはテンプレートのカスタムフィルタです。

      まず、カスタムタグの仕事か、カスタムフィルタの仕事か迷ったのですが、
      ・テンプレート内から引数を取れる
      という点でフィルタかなと判断しました。

      次にプチハマリしたのが、カスタムフィルタに渡す引数は1つだけという点でした。
      django/template/_init_.pyのコードをかなり読んだんですが、どうも2つ以上の引数を渡してカスタムフィルタは作れないっぽいのです(事実、デフォルトのフィルタも2つの引数を取るものは無い)
      仕方ないので、「PHPにも文字列を配列に区切る関数があるぐらいだから、きっとpythonにもあるはず!」という根拠のない自信のもと(爆)、引数は区切り文字入り文字列で1つだけ渡すことに決めました(★1-1)。
      それから文字列を配列(みたいなの)に区切る関数を調べたら(python string splitでググる)やはりstring.split()を発見(★1-2)。

      「今度こそどうだ!?」といきなりrunserverしてテンプレートの表示を試みる(無謀にもほどがあるYO!)
      結果はエラー(T_T)
      理由は、その時まだ★2の位置でyとmにatoiをかけてなかったため、「__yearの照合には文字列じゃなくて数値が必要なの!」と怒られたのでした^^;
      ローカルのpython shell(IDLE)ちゃんで、文字列の'2007/5'をsplit()してみると、確かにスプリット結果のリスト内で各要素は文字列として扱われている様子。(printしたら'2007' '5'となりました)
      ここで(PHPでは意識しないで済んだ)文字列⇔数値の変換を入れる必要があると気づき、またまた「文字列 数値 変換 python」「string integer convert python」とググり、atoiの存在を知りました^^

      で、先ほどのコードを書いてrunserverすると、見事に月次集計が♪

      教訓:
      Excelでできることは大抵Pythonでもできる。絶対に途中であきらめないこと。


      スポンサーサイト

      0

        • 2014.12.23 Tuesday
        • -
        • 10:22
        • -
        • -
        • -
        • -
        • by スポンサードリンク

        コメント
        コメントする








           
        この記事のトラックバックURL
        トラックバック

        PR

        calendar

        S M T W T F S
              1
        2345678
        9101112131415
        16171819202122
        23242526272829
        3031     
        << July 2017 >>

        twitter

        selected entries

        categories

        archives

        recent comment

        • 結局CodeIgniter用汎用Modelクラス&汎用CRUDスクリプトを書きました
          プログラマー
        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
          よし
        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
          ななうぇぶ
        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
          よし
        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
          よし
        • WindowsのPCで開発するphperがxhprofを使う方法
          ななうぇぶ
        • WindowsのPCで開発するphperがxhprofを使う方法
          川本
        • [バッドノウハウ]Symfony2で別テーブルの集計項目を一覧に含めたいとき
          よし
        • Symfony Advent Calendar JP 2012 day 14 - vendorをcomposerで管理しているプロジェクトにcomposerを使わずにバンドルを追加したときのautoloadの書き方
          77web
        • Symfony Advent Calendar JP 2012 day 14 - vendorをcomposerで管理しているプロジェクトにcomposerを使わずにバンドルを追加したときのautoloadの書き方
          ktz

        recent trackback

        • HTMLの表(TABLE)のセル(TD)に斜線を引くjavascriptライブラリ slash.js 作っちゃいました
          常山日記
        • django対symfony 日本語メール送信(その1 symfony編)
          CPA-LABテクニカル
        • CodeIgniterでユーザー認証
          されどLAMPな日々
        • 久々にdjangoを最新版にしたらHTMLがエスケープされちゃった!!(解決済み)
          常山日記
        • FastCGIを諦めてmod_pythonを使う。Apacheのアップグレード
          サーバー用語集
        • さくらインターネット、sqlite3でdjango@CGI版を使う際の設定メモ
          常山日記
        • さくらインターネット スタンダードプランでdjango使ってる方、DBは?
          mitszoの日記
        • python多次元リストをsort(並べ替え)する方法?
          mitszoの日記
        • フォームから送信した値とrequest.POSTの挙動($_POST@PHPとの比較)
          Humming Via Kitchen
        • 日本語テキストをtruncate@django(Python全般にも??)
          常山日記

        recommend

        links

        profile

        search this site.

        others

        mobile

        qrcode

        powered

        無料ブログ作成サービス JUGEM