Hey Ned, On Sat, 2007-12-29 at 08:27 +1100, Malcolm Tredinnick wrote: [...] > def render(self, context): > if context[self.varname] == id(context['forloop']): > return self.nodelist_false.render(context) > context[self.varname] = id(context['forloop']) > return self.nodelist_true.render(context)
This guess is rubbish. The problem is that the context['forloop'] dictionary is a new instance for every iteration of the for-loop, so there's nothing constant about that outer structure we can use. After a bit of sleep, some food and some time spent thinking about this whilst doing other stuff today, there's a better solution (a.k.a one that works) attached to this mail. I've even tested this one. During any for-loop, the only thing that remains constant is the "parentloop" dictionary. That dictionary is created anew every time the *parent* loop steps forwards, but it is referred to by reference for each iteration of the inner loop. So we can stick a marker into the parent loop's data structure (even when there's no parent loop, that data structure is an empty dictionary). So, this implementation does depend a bit on the internals of the ForNode, but that isn't a complete crime. Plus it's been hard to come up with an alternative. Every time I thought of some tricky data structure that seemed to do the trick, I was able to break it. A template fragment such as {% for x in data %} {% if x %} {% iffirst %} yes {% else %} no {% endfirst %} {% else %} fail {% endif %} {% endfor %} given data = (0, 1, 1, 0) twice in succession (without recompiling), or giving data = (0, 1, 1, 0) and data = (0, 0, 1, 0) on successive runs (again, without recompiling) was enough to break most of my attempts. It's also not too hard to extend this to be check whether this is the first time around the parent loop using a similar method, although nested "iffirst" tags seems hard. Best wishes, Malcolm -- Tolkien is hobbit-forming. http://www.pointy-stick.com/blog/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---
from django.template import Node, NodeList, TemplateSyntaxError, Library class IfFirstNode(Node): def __init__(self, nodelist_true, nodelist_false): self.nodelist_true = nodelist_true self.nodelist_false = nodelist_false def __repr__(self): return "<%s>" % self.__class__.__name__ def render(self, context): if '_first' in context['forloop']['parentloop']: return self.nodelist_false.render(context) context['forloop']['parentloop']['_first'] = True return self.nodelist_true.render(context) register = Library() @register.tag def iffirst(parser, token): bits = token.split_contents() if len(bits) != 1: raise TemplateSyntaxError("%r takes no arguments." % bits[0]) nodelist_true = parser.parse(('else', 'endiffirst')) token = parser.next_token() if token.contents == 'else': nodelist_false= parser.parse(('endiffirst',)) parser.delete_first_token() else: nodelist_false = NodeList() return IfFirstNode(nodelist_true, nodelist_false)