2009-05-10 9 views
36

Pythonのgetattr()メソッドは、事前に特定の属性の名前がわからない場合に便利です。djangoテンプレートでgetattr()スタイルのルックアップを実行する

この機能もテンプレートには便利ですが、これを行う方法は決して分かりません。動的属性の参照を実行できる組み込みタグまたは非組み込みタグはありますか?

+0

あなたのテンプレートであまりにも多くをやっているのだろうかと思います。 getattrは時にはPythonコードで黒い魔法のように感じるので、確かにテンプレートにコードの臭いがあります! –

答えて

53

私は最近カスタムテンプレートタグとしてwrite this codeも持っていました。すべてのルックアップシナリオを処理するために、最初に標準的な属性ルックアップを行い、辞書ルックアップを試みた後、getitemルックアップ(リストを動作させる)を試み、次に標準のDjangoテンプレート動作に従います。オブジェクトが見つかりません。

(今だけでなく、リストのインデックス検索を処理するために、2009年8月26日更新)

# app/templatetags/getattribute.py 

import re 
from django import template 
from django.conf import settings 

numeric_test = re.compile("^\d+$") 
register = template.Library() 

def getattribute(value, arg): 
    """Gets an attribute of an object dynamically from a string name""" 

    if hasattr(value, str(arg)): 
     return getattr(value, arg) 
    elif hasattr(value, 'has_key') and value.has_key(arg): 
     return value[arg] 
    elif numeric_test.match(str(arg)) and len(value) > int(arg): 
     return value[int(arg)] 
    else: 
     return settings.TEMPLATE_STRING_IF_INVALID 

register.filter('getattribute', getattribute) 

テンプレートの使用:GETとGETATTRの区別を維持

{% load getattribute %} 
{{ object|getattribute:dynamic_string_var }} 


+0

鮮やかな - ありがとう! – starsinmypockets

+0

ここに何かがありません - 第2節と第3節の目的は何ですか? 'hasattr(value、 'has_key')'の場合、 'value.arg'を使ってテンプレートにアクセスできませんか?同様に配列の場合、 'value.i'はi番目の要素を取得します。関数がこれらの冗長なケースを処理するだけなのですか? – Symmetric

+1

Djangoは、 '{{value.arg}}'を実行するとオブジェクトの属性(1節)、辞書のキー(2節)、リストの索引(3節)、デフォルトでは空の文字列になります。したがって、 '{{value | getattribute:dynamic_arg_name}}'は純粋なPythonの意味では "getattribute"ではありませんが、通常のDjangoルックアップと同じように動作します。 – fotinakis

0

組み込みのタグはありませんが、write your ownにはあまりにも難しくありません。

2

私はそうは思わない。しかし、context dictの属性を返すためにcustom template tagと書くのは難しくありません。これが繰り返されている状態でない限り、それは、おそらくあなたのビューではなく、テンプレートでこれを行うことも簡単だということ

class GetAttrNode(template.Node): 
    def __init__(self, attr_name): 
     self.attr_name = attr_name 

    def render(self, context): 
     try: 
      return context[self.attr_name] 
     except: 
      # (better yet, return an exception here) 
      return '' 

@register.tag 
def get_attr(parser, token): 
    return GetAttrNode(token) 

注:あなたは、単に文字列を返すようにしようとしている場合は、このような何かを試してみてください多くの場合、あなたのデータにあります。

2

私は問題のモデルにメソッドを追加しましたが、そのメソッドはテンプレートの属性のようにアクセスできます。

ビルド済みのタグで属性を動的に検索することができれば、これは素晴らしいことだと思います。なぜなら、これは私たちのテンプレートに常に多くの問題が残っているからです。

2

@register.filter(name='get') 
def get(o, index): 
    try: 
     return o[index] 
    except: 
     return settings.TEMPLATE_STRING_IF_INVALID 


@register.filter(name='getattr') 
def getattrfilter(o, attr): 
    try: 
     return getattr(o, attr) 
    except: 
     return settings.TEMPLATE_STRING_IF_INVALID 
0

そのスニペットは私の日を節約しましたが、私はそれをリレーションにまたがる必要があったので、私はargを "。"で分割するように変更しました。再帰的に値を取得します。 それは1行で行うことができます: return getattribute(getattribute(value,str(arg).split(".")[0]),".".join(str(arg).split(".")[1:])) 私は可読性のために4でそれを残しました。 誰かがこれを使用してくれることを願っています。

import re 
from django import template 
from django.conf import settings 

numeric_test = re.compile("^\d+$") 
register = template.Library() 

def getattribute(value, arg): 
"""Gets an attribute of an object dynamically AND recursively from a string name""" 
    if "." in str(arg): 
     firstarg = str(arg).split(".")[0] 
     value = getattribute(value,firstarg) 
     arg = ".".join(str(arg).split(".")[1:]) 
     return getattribute(value,arg) 
    if hasattr(value, str(arg)): 
     return getattr(value, arg) 
    elif hasattr(value, 'has_key') and value.has_key(arg): 
     return value[arg] 
    elif numeric_test.match(str(arg)) and len(value) > int(arg): 
     return value[int(arg)] 
    else: 
     #return settings.TEMPLATE_STRING_IF_INVALID 
     return 'no attr.' + str(arg) + 'for:' + str(value) 

register.filter('getattribute', getattribute) 
関連する問題