時間分岐のテンプレートタグ ifbefore ifafter ifafterbefore

投稿者: ytyng 12 年, 6 ヶ月 前
# -*- coding: utf-8 -*-
"""
時間を判定して表示分岐させるテンプレートタグ
例:
{% ifbefore '2011-12-24 20:00:00' %}
    ここは 2011-12-24 20:00:00 未満に表示される
{% else %}
    ここは 2011-12-24 20:00:00 以後に表示される
{% endifbefore %}

引数は、datetimeの他、
'%Y-%m-%d %H:%M:%S', '%Y-%m-%d', '%H:%M:%S' 形式の日付文字列が使える
"""

import datetime

from django import template
from django.template import Node, NodeList, resolve_variable

register = template.Library()

class IfAfterBeforeNode(Node):
    child_nodelists = ('nodelist_true', 'nodelist_false')
    datestr_format_list = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d', '%H:%M:%S')

    def __init__(self, var_after, var_before, nodelist_true, nodelist_false=None):
        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
        self.var_after = var_after
        self.var_before = var_before
        self.now = datetime.datetime.now()

    def strptime(self, date_string):
        """
        日付文字列をパースしてdatetimeにする。
        パースできなければNone
        """
        date_string = date_string.strip("""'" """)
        for datestr_format in self.datestr_format_list:
            try:
                return datetime.datetime.strptime(date_string, datestr_format)
            except ValueError:
                pass
        return None

    def __repr__(self):
        return "<IfBeforeAfter node>"

    def __iter__(self):
        for node in self.nodelist_true:
            yield node
        for node in self.nodelist_false:
            yield node

    def arg_to_dt_or_none(self, arg, context):
        """
        引数を datetime もしくは none として取得
        self.var_after, self.var_before に使う
        """
        if not arg:
            return None
        try:
            # 引数がdatetimeの場合があるので
            dt = resolve_variable(arg, context)
        except template.VariableDoesNotExist:
            dt  = None
        if dt is None or not isinstance(dt,  datetime.datetime):
            dt = self.strptime(arg)
        return dt

    def render(self, context):

        dt_after  = self.arg_to_dt_or_none(self.var_after,  context)
        dt_before = self.arg_to_dt_or_none(self.var_before, context)

        if dt_after and dt_before:
            if dt_after <= self.now < dt_before:
                return self.nodelist_true.render(context)
            else:
                return self.nodelist_false.render(context)
        elif dt_after:
            if dt_after <= self.now:
                return self.nodelist_true.render(context)
            else:
                return self.nodelist_false.render(context)
        elif dt_before:
            if self.now < dt_before:
                return self.nodelist_true.render(context)
            else:
                return self.nodelist_false.render(context)
        else:
            return u'Parse Error. No after, before'

@register.tag
def ifbefore(parser, token):
    """
    現在日時が"YYYY-MM-DD HH:MM:SS" より前(未満)であればレンダリング
    """
    _tagname, var_before = token.split_contents()
    nodelist_true = parser.parse(('else', 'endifbefore'))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse(('endifbefore',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAfterBeforeNode(None, var_before, nodelist_true, nodelist_false)

@register.tag
def ifafter(parser, token):
    """
    現在日時が"YYYY-MM-DD HH:MM:SS" より後(以上)であればレンダリング
    """
    _tagname, var_after = token.split_contents()
    nodelist_true = parser.parse(('else', 'endifafter'))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse(('endifafter',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAfterBeforeNode(var_after, None, nodelist_true, nodelist_false)

@register.tag
def ifafterbefore(parser, token):
    """
    2つの引数をとり、現在時刻がその以上未満であればレンダリング
    """
    _tagname, var_after, var_before = token.split_contents()

    nodelist_true = parser.parse(('else', 'endifafterbefore'))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse(('endifafterbefore',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAfterBeforeNode(var_after, var_before, nodelist_true, nodelist_false)
現在未評価

コメント

アーカイブ

2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011