TemplateLoader自作のススメ
http://d.hatena.ne.jp/jbking/20060310/p1
で困ってるようですがTemplate_Loaderを自作してみたらどう?って話です。
でいつもの通りQuickHack。
(ソース読めの領域です)
TEMPLATE_LOADERSの簡単な仕様
Template_Loaderは"settings.py"に書くわけだけど
デフォルトでは
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source', # 'django.template.loaders.eggs.load_template_source', )
となっています。
確か上から順にloaderを適用していき該当のTemplateを探します。
django.template.loaders.app_directories.load_template_source:抜粋
・・・・ def get_template_sources(template_name, template_dirs=None): for template_dir in app_template_dirs: yield os.path.join(template_dir, template_name) + settings.TEMPLATE_FILE_EXTENSION ・・・・
dir内のファイルをかったぱしから漁る仕様になっています。
ここにもあるように拡張子は
settings.TEMPLATE_FILE_EXTENSION
となっています。
で実際の値はというと・・・・
django.conf.g;obal_settings:抜粋
# Extension on all templates. TEMPLATE_FILE_EXTENSION = '.html'
となっており".html"のみをtemplateとして扱う仕様になっています。
うーん、基本的にDjangoのtemplateはhtmlに依存していないので(タグとか見ていない)もっといろんな事に使いたいよね。
LOADERの自作
で自作。
元ネタがあるのでそこだけちょいといじればいいんでない?
自作ローダーjisaku.py
from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.template import TemplateDoesNotExist import os app_template_dirs = [] for app in settings.INSTALLED_APPS: i = app.rfind('.') if i == -1: m, a = app, None else: m, a = app[:i], app[i+1:] try: if a is None: mod = __import__(m, '', '', []) else: mod = getattr(__import__(m, '', '', [a]), a) except ImportError, e: raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0]) template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates') if os.path.isdir(template_dir): app_template_dirs.append(template_dir) app_template_dirs = tuple(app_template_dirs) def get_template_sources(template_name, template_dirs=None): for template_dir in app_template_dirs: # yield os.path.join(template_dir, template_name) + settings.TEMPLATE_FILE_EXTENSION yield os.path.join(template_dir, template_name) + settings.HOGEHOGE_FILE_EXTENSION def load_template_source(template_name, template_dirs=None): for filepath in get_template_sources(template_name, template_dirs): try: return (open(filepath).read(), filepath) except IOError: pass raise TemplateDoesNotExist, template_name load_template_source.is_usable = True
自Project内の"template""templates"って名前のDir配下を読みに行きます。
今回は自分のProjectの"settings.py"に
# Extension on all templates. HOGEHOGE_FILE_EXTENSION = '.mail_template'
と
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source', #自作loaderを追加 'jisaku.load_template_source', )
を追加すれば使えるはずです。
もっと柔軟にしたければ
def get_template_sources(template_name, template_dirs=None): for template_dir in app_template_dirs: # yield os.path.join(template_dir, template_name) + settings.TEMPLATE_FILE_EXTENSION yield os.path.join(template_dir, template_name)
として
template_name = "%s/%s_form.%s" % ( 'hogehoge', 'comment','template' ) t = template_loader.get_template( template_name )
のように拡張子込みでtemplateをゲットするのもありです。
拡張子がひとつな理由
ソースを見てなんとなーく感じただけですが
load処理抜粋
def load_template_source(template_name, template_dirs=None): for filepath in get_template_sources(template_name, template_dirs): try: return (open(filepath).read(), filepath) except IOError: pass raise TemplateDoesNotExist, template_name load_template_source.is_usable = True
見てもわかるように単純に開けるかどうかどうかを全ファイルに対して行う仕様です。
やっぱり意図しないファイルが開かないように推奨してんだろうなあと。
上記より不必要なTemplateLoaderは使わない方がパフォーマンス的によさげです。
(もちろんキャッシュ化はしてますけど。一回目がけっこー時間かかるかなと)
うくく。