开发者

Not resetting cycle on multiple template render()

I have made a tag that render a custom template based on the model type. I needed this because I wanted to show more detail than the django.views.generic.list_detail.object_list let me show for a single object, and I have multiple objects of different kinds. Here is the code:

The templatetags/extra.py:

from django import template
register = template.Library()

def render_item_list(parser, token):
    try:
        tag_name, item_list = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires exactly one arguments" %     token.split_contents()[0]
    return RenderItemListNode(item_list)

class RenderItemListNode(template.Node):
    def __init__(self, item_list):
        self.item_list = template.Variable(item_list)

    def render(self, context):
        list_html = ''

        for item in self.item_list.resolve(context):
            context.update({'item':item})
            list_html += template.loader.get_template("list/%s_item.html" % item.__class__.__name__.lower()).render(context)

    return list_html

register.tag('render_item_list', render_item_list)

My problem is that the template uses a {{ cycle }} and the values are reset with every render() call.

I'm probably going to add to my own tag the cycle values, but I want to see if there is a better solution, like not resetting the cycle value across render() calls or even a different approach than this tag of mine.

More code:

index.html:

{% extends "base.html" %}
{% load extra %}
{% block content %}
   {% render_item_list item_list %}
{% endblock %}

object_item.html snippet:

<div class="{{ cycle 'odd' 'even' }}" >
    ...
</div>

-- Edit: Here is my new version of the tag, that can be used inside a for lo开发者_StackOverflow社区op:

def render_item(parser, token):
    try:
        tag_name, item = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.split_contents()[0]
    return RenderItemNode(item)

class RenderItemNode(template.Node):
    def __init__(self, item):
        self.item = template.Variable(item)

    def render(self, context):
        item = self.item.resolve(context)
        return template.loader.get_template("list/%s_item.html" % item.__class__.__name__.lower()).render(template.Context({'item':item}))

register.tag('render_item', render_item)


Change your object_item.html to look like this:

{% for item in item_list %}
<div class="{{ cycle 'odd' 'even' }}" >
    ...
</div>
{% endfor %}

And then change the render() definition on your RenderItemListNode:

def render(self, context):
    item_list = self.item_list.resolve(context)
    list_html = template.loader.get_template("list/%s_item.html" % item.__class__.__name__.lower()).render({'item_list':item_list})
return list_html


The reason this is happening is that the cycle tag works when it's inside a for loop - in your template, there isn't a for loop, so the cycle isn't updating.

If you want to use the cycle as it is, you could try rendering the entire list of objects in your template, and then have your template do a for loop over them - instead of doing a loop in your code.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜