2011-07-14 12 views
1

私は、それを含むタグ/部分が何回実行されているかにかかわらず、一度に1ブロックのコードしかレンダリングしないカスタムテンプレートタグを作成しようとしています。Django Do Onceカスタムテンプレートタグ

これは私がそれを実現してきた方法ですが、あなたが見ることができるように、それは少しハックです:

my_partial.html:

{% once mycontent %} 
    this will only show once 
{% endonce%} 

がmy_template.html:

{% load my_tags %} 
{% for i in list %} 
    {% my_partial %} 
{% endfor %} 

my_tags.py:

@register.inclusion_tag('my_partial.html',takes_context=True) 
def my_partial(context): 
    return dict(arbitrary extra data) 

@register.tag(name="once") 
def do_once(parser, token): 
    try: 
     # Splitting by None == splitting by spaces. 
     tag_name, var_name = token.contents.split(None, 1) 
    except ValueError: 
     raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0]) 
    nodelist = parser.parse(('endonce',)) 
    parser.delete_first_token() 
    return DoOnceNode(nodelist, var_name) 

class DoOnceNode(template.Node): 
    def __init__(self, nodelist, var_name): 
     self.nodelist = nodelist 
     self.var_name = '_do_once_'+var_name 
    def render(self, context): 
     request = context['request'] 

     # Make request.GET mutable. 
     request.GET = dict(request.GET) 

     if self.var_name in request.GET: 
      return '' 
     else: 
      request.GET[self.var_name] = 1 
      return self.nodelist.render(context) 

特に、私は可変グローバルスコープとしてrequest.GET辞書を使用しています。それはハックであり、明らかにリクエストオブジェクトが行うように設計されているものではありませんが、動作します。

理想的には、コンテキストのようなものを使用したいと思いますが、このタグの呼び出し間で共有されていないことがわかりました。すなわちself.var_name in contextは常にFalseであり、グローバルスコープとしては役に立たない。

なぜコンテキストが共有されないのは、リクエストが共有されるのと同じですか?それを真に共有するための方法がありますか、またはリクエスト内にグローバルにアクセス可能な変数を格納するために使用できる他のオブジェクトがありますか?

+0

どうますrequest.sessionについて?ちょっとハッキリしていません。 'once'テンプレートタグのユースケースは何ですか? – Tiago

+0

リクエストを超えて何も保存しないので、私はセッションを使用しませんでした。セッションにメタデータを保存すると、要求の範囲外で意味のないデータでデータベースが汚染されます。私の使用例は、通常は隠されているモーダルダイアログのHTMLをインクルードすることです。これは、ページ上で使用されるかもしれないし、使用されないかもしれないいくつかのオプションのウィジェットによって使用されるかもしれません。私は、各ウィジェットに部分的なものを含めることを望みますが、異なる場所に存在する同じIDとの競合を避けるために、一度だけ行います。 – Cerin

答えて

0

私はあなたが達成する必要があるか、あなたのアプローチが本当に最良のアプローチであるかは正確には分かりませんが、あまりにも遠くに行く前にforloop.first変数を調べることをお勧めします。しかし、あなたのアプローチは、最高の状態で一目で厄介なようだが、私はあなたがあなたのニーズにこの作業を行うことができるはず

django for template tag

ほとんどの状況の詳細を知らないので、私は間違っている可能性がそれが不足している場合は、forテンプレートタグ(とそれはforloop変数)のソースは、あなたがやろうとしていることをどのように実装するかについての非常に例示的なものになると思います。

+1

forループは無関係です。私はそれを使って、部分的なものがどのように複数回含まれるかを示しています。アイデアは、タグが初めて使用されたときに覚えておき、それ以降は使用不可にすることです。 – Cerin

0

私はコンテキスト内の変数を保存し、ノードのrenderメソッドで、そのためにチェックしてやってしまった何を:

class CustomNode(template.Node): 
    def render(self, context: dict) -> str: 
     context['already_rendered'] = context.get('already_rendered', set()) 

     if self.__class__ in context['already_rendered']: 
      return '' 

     context['already_rendered'].add(self.__class__) 

     ... 
関連する問題