def render(self, context): nodelist = NodeList() if context.has_key('parenttable'): parenttable = context['parenttable'] else: parenttable = {} context.push() values = self.get_values(context) len_values = len(values) innernodelist = NodeList() totalrows = int(math.ceil(float(len_values) / float(self.cols))) rowcount = 0 for i, item in enumerate(values): loopctx = { 'counter0': i, 'counter': i + 1, 'rowcounter0': (i / self.cols), 'rowcounter': ((i / self.cols) + 1), 'firstrow': (i < self.cols), 'lastrow': (i > len_values - self.cols), 'firstcell': (i == 0), 'lastcell': (i == len_values - 1), 'evencol': (i % 2) == 0, 'oddcol': (i % 2) == 1, 'parenttable': parenttable, } context[self.cellvar] = item loopctx['oddrow'] = False loopctx['evenrow'] = False loopctx['lastcellinrow'] = False loopctx["startrow"] = False loopctx["endrow"] = loopctx["lastcell"] if totalrows == 1 and i == len_values - 1: loopctx['lastcellinrow'] = True elif i == (len_values - 1): loopctx['lastcellinrow'] = True if i % self.cols == 0: nodelist.append(innernodelist.render(context)) innernodelist = NodeList() loopctx["startrow"] = True if (rowcount + 1) % 2 == 0: loopctx["oddrow"] = False loopctx["evenrow"] = True else: loopctx["oddrow"] = True loopctx["evenrow"] = False elif (i + 1) % self.cols == 0: loopctx['lastcellinrow'] = True loopctx["endrow"] = True rowcount += 1 context['table'] = loopctx for node in self.cellnodes: innernodelist.append(node.render(context)) if innernodelist and len(innernodelist) > 0: nodelist.append(innernodelist.render(context)) context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() if context.has_key('parenttable'): parenttable = context['parenttable'] else: parenttable = {} context.push() values = self.get_values(context) len_values = len(values) innernodelist = NodeList() totalrows = int(math.ceil(float(len_values) / float(self.cols))) rowcount = 0 for i, item in enumerate(values): loopctx = { 'counter0':i, 'counter':i+1, 'rowcounter0':(i/self.cols), 'rowcounter':((i/self.cols)+1), 'firstrow':(i<self.cols), 'lastrow':(i>len_values-self.cols), 'firstcell':(i==0), 'lastcell':(i==len_values-1), 'evencol':(i%2)==0, 'oddcol':(i%2)==1, 'parenttable':parenttable, } context[self.cellvar] = item loopctx['oddrow'] = False loopctx['evenrow'] = False loopctx['lastcellinrow'] = False loopctx["startrow"] = False loopctx["endrow"] = loopctx["lastcell"] if totalrows == 1 and i == len_values-1: loopctx['lastcellinrow'] = True elif i == (len_values-1): loopctx['lastcellinrow'] = True if i % self.cols == 0: nodelist.append(innernodelist.render(context)) innernodelist = NodeList() loopctx["startrow"] = True if (rowcount+1)%2==0: loopctx["oddrow"] = False loopctx["evenrow"] = True else: loopctx["oddrow"] = True loopctx["evenrow"] = False elif (i+1) % self.cols==0: loopctx['lastcellinrow'] = True loopctx["endrow"] = True rowcount += 1 context['table'] = loopctx for node in self.cellnodes: innernodelist.append(node.render(context)) if innernodelist and len(innernodelist)>0: nodelist.append(innernodelist.render(context)) context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() context.push() try: start = self.start.resolve(context) except VariableDoesNotExist: return '' except AttributeError: start = self.start try: end = self.end.resolve(context) except VariableDoesNotExist: return '' except AttributeError: end = self.end try: step = self.step.resolve(context) except VariableDoesNotExist: return '' except AttributeError: step = self.step for i in range(start, end, step): context[self.var_name] = i for node in self.nodelist_loop: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def render(self, context): #resolve cube from context try: cube = self.cube.resolve(context, False) except VariableDoesNotExist: return '' #resolve dimensions dimensions = [] for dimension in self.dimensions: matched = re.match('(?P<quote>"|\')(?P<literal>\w+)(?P=quote)', dimension) if matched: dimensions.append(str(matched.group('literal'))) else: try: dimensions.append(str(Variable(dimension).resolve(context))) except VariableDoesNotExist: return '' #loop subcubes and render nodes nodelist = NodeList() for subcube in cube.subcubes(*dimensions): context[self.subcube_var] = subcube for node in self.nodelist: nodelist.append(node.render(context)) return nodelist.render(context)
def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() if self.is_reversed: values = reversed(values) unpack = len(self.loopvars) > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) pop_context = False if unpack: # If there are multiple loop variables, unpack the item into # them. try: unpacked_vars = dict(zip(self.loopvars, item)) except TypeError: pass else: pop_context = True context.update(unpacked_vars) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if pop_context: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() context.push() try: start = self.start.resolve(context) except VariableDoesNotExist: return '' except AttributeError: start = self.start try: end = self.end.resolve(context) except VariableDoesNotExist: return '' except AttributeError: end = self.end try: step = self.step.resolve(context) except VariableDoesNotExist: return '' except AttributeError: step = self.step for i in xrange(start, end+1, step): context[self.var_name] = i for node in self.nodelist_loop: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def render(self, context): actual_form = self.form_var.resolve(context) bindings = get_bindings(actual_form) # bindings.reverse() # bind in reverse order ... nodelist = NodeList() js_info = get_js_info(actual_form) # Add the script to activate this form nodelist.append( HtmlContent( """ <script> %s $(document).ready(function(){ // new ManagementForm(parentForm, childTemplate, initialForms); %s }); </script> """ % (js_info, "\n".join(bindings)) ) ) nodelist.append(HtmlContent("</div>")) return nodelist.render(context)
def render (self, context): nodelist = NodeList () for i in range (int(self.value)): context['percentage'] = {'iter': i} for node in self.nodelist_loop: nodelist.append (node.render(context)) return nodelist.render (context)
def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() if self.is_reversed: values = reversed(values) unpack = len(self.loopvars) > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) pop_context = False if unpack: # If there are multiple loop variables, unpack the item into # them. try: unpacked_vars = dict(zip(self.loopvars, item)) except TypeError: pass else: pop_context = True context.update(unpacked_vars) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if pop_context: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)
class ThumbnailNode(ThumbnailNodeBase): child_nodelists = ('nodelist_file', 'nodelist_empty') error_msg = ('Syntax error. Expected: ``thumbnail source geometry ' '[key1=val1 key2=val2...] as var``') def __init__(self, parser, token): bits = token.split_contents() if len(bits) < 5 or bits[-2] != 'as': raise TemplateSyntaxError(self.error_msg) self.file_ = parser.compile_filter(bits[1]) self.geometry = parser.compile_filter(bits[2]) self.options = [] for bit in bits[3:-2]: m = kw_pat.match(bit) if not m: raise TemplateSyntaxError(self.error_msg) key = smart_str(m.group('key')) expr = parser.compile_filter(m.group('value')) self.options.append((key, expr)) self.as_var = bits[-1] self.nodelist_file = parser.parse(('empty', 'endthumbnail',)) if parser.next_token().contents == 'empty': self.nodelist_empty = parser.parse(('endthumbnail',)) parser.delete_first_token() else: self.nodelist_empty = NodeList() def _render(self, context): file_ = self.file_.resolve(context) geometry = self.geometry.resolve(context) options = {} for key, expr in self.options: noresolve = {'True': True, 'False': False, 'None': None} value = noresolve.get(unicode(expr), expr.resolve(context)) if key == 'options': options.update(value) else: options[key] = value if settings.THUMBNAIL_DUMMY: thumbnail = DummyImageFile(geometry) elif file_: thumbnail = default.backend.get_thumbnail( file_, geometry, **options ) else: return self.nodelist_empty.render(context) context.push() context[self.as_var] = thumbnail output = self.nodelist_file.render(context) context.pop() return output def __repr__(self): return "<ThumbnailNode>" def __iter__(self): for node in self.nodelist_file: yield node for node in self.nodelist_empty: yield node
def render(self, context, depth=0, values=False): nodelist = NodeList() if 'recurseloop' in context: parentloop = context['recurseloop'] else: parentloop = {} context.push() # On the first recursion pass, we have no values if not values: try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) # Create a recurseloop value in the context. We'll update counters on each iteration just below. loop_dict = context['recurseloop'] = {'parent': parentloop} loop_dict['depth'] = depth + 1 loop_dict['depth0'] = depth for i, item in enumerate(values): # Add the additional arguments to the context # They come in the form of {'name':(initial,increment)} # As for now only numbers are supported, but also strings can be multiplied for k, v in self.kwargs.iteritems(): context[k] = v[0] + v[1] * depth # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i + 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) context[self.loopvar] = item for node in self.nodelist_first: nodelist.append(node.render(context)) if len(getattr(item, self.children_name)): nodelist.append( self.render(context, depth + 1, getattr(item, self.children_name))) for node in self.nodelist_second: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def render(self, context): if (type(self.value) == StringType): context[self.key] = self.value else: nodelist = NodeList() for node in self.value: nodelist.append(node.render(context)) context[self.key] = nodelist.render(context) return ""
def do_render(self, context, sequence): nodelist = NodeList() context.push() for item in sequence: context[self.repeatvar.token] = item for node in self.nodelist: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def render(self, context, depth=0, values=False): nodelist = NodeList() if 'recurseloop' in context: parentloop = context['recurseloop'] else: parentloop = {} context.push() # On the first recursion pass, we have no values if not values: try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) # Create a recurseloop value in the context. We'll update counters on each iteration just below. loop_dict = context['recurseloop'] = {'parent': parentloop} loop_dict['depth'] = depth + 1 loop_dict['depth0'] = depth for i, item in enumerate(values): # Add the additional arguments to the context # They come in the form of {'name':(initial,increment)} # As for now only numbers are supported, but also strings can be multiplied for k,v in self.kwargs.iteritems(): context[k] = v[0] + v[1]*depth # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) context[ self.loopvar ] = item for node in self.nodelist_first: nodelist.append( node.render(context) ) if len( getattr( item, self.children_name ) ): nodelist.append( self.render( context, depth+1, getattr( item, self.children_name ) ) ) for node in self.nodelist_second: nodelist.append( node.render(context) ) context.pop() return nodelist.render(context)
def render_mixers(self, context): nodelist = NodeList() inner_nodelist = self.inner_nodelist context.push() for mixer in self.mixers: context['mixer'] = mixer.template.render(context) nodelist.append(inner_nodelist.render(context)) context.pop() return nodelist.render(context)
def render_mixers(self, context): nodelist = NodeList() inner_nodelist = self.inner_nodelist context.push() for mixer in self.mixers: context['mixer'] = mixer.template.render(context) nodelist.append(inner_nodelist.render(context)) context.pop() return nodelist.render(context)
def render(self, context): content_type_id = self.content_type_id.resolve(context) content_type = ContentType.objects.get_for_id(content_type_id) if hasattr(content_type.model_class(), 'get_absolute_url'): pk = self.pk.resolve(context) nodelist = NodeList() nodelist.append(LINK_FORMAT % (content_type.pk, pk)) nodelist.append(self.inner_nodelist.render(context)) nodelist.append('</a>') return nodelist.render(context) else: return self.inner_nodelist.render(context)
def render(self, context): content_type_id = self.content_type_id.resolve(context) content_type = ContentType.objects.get_for_id(content_type_id) if hasattr(content_type.model_class(), 'get_absolute_url'): pk = self.pk.resolve(context) nodelist = NodeList() #nodelist.append(LINK_FORMAT % (content_type.pk, pk)) nodelist.append(self.inner_nodelist.render(context)) nodelist.append('</a>') return nodelist.render(context) else: return self.inner_nodelist.render(context)
def render(self, context): nodelist = NodeList() if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if self.reversed: values = reversed(values) unpack = len(self.loopvars) > 1 for i, item in enumerate(values): context['forloop'] = { # Shortcuts for current loop iteration number. 'counter0': i, 'counter': i+1, # Reverse counter iteration numbers. 'revcounter': len_values - i, 'revcounter0': len_values - i - 1, # Boolean values designating first and last times through loop. 'first': (i == 0), 'last': (i == len_values - 1), 'parentloop': parentloop, } if unpack: # If there are multiple loop variables, unpack the item into # them. context.update(dict(zip(self.loopvars, item))) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if unpack: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() sidebar_list = Sidebar.all().order("order").fetch(100) context.push() for sidebar in sidebar_list: context.push() context["sidebar"] = sidebar for node in self.nodelist_loop: nodelist.append(node.render(context)) context.pop() context.pop() return nodelist.render(context)
class ThumbnailNode(thumbnail.ThumbnailNodeBase): child_nodelists = ("nodelist_file", "nodelist_empty") error_msg = "Syntax error. Expected: ``thumbnail source preset as var``" preset_error = "Preset %s not found." def __init__(self, parser, token): bits = token.split_contents() if len(bits) != 5 or bits[-2] != "as": raise TemplateSyntaxError(self.error_msg) self.file_ = parser.compile_filter(bits[1]) self.preset = parser.compile_filter(bits[2]) self.as_var = bits[-1] self.nodelist_file = parser.parse(("empty", "endthumbnail")) if parser.next_token().contents == "empty": self.nodelist_empty = parser.parse(("endthumbnail",)) parser.delete_first_token() else: self.nodelist_empty = NodeList() def _render(self, context): file_ = self.file_.resolve(context) preset_name = self.preset.resolve(context) preset = Preset.objects.get(name=preset_name) if settings.THUMBNAIL_DUMMY: thumbnail = DummyImageFile(preset.geometry) elif file_: thumbnail = default.backend.get_thumbnail(file_, preset.geometry, **preset.get_options()) else: return self.nodelist_empty.render(context) context.push() context[self.as_var] = thumbnail output = self.nodelist_file.render(context) context.pop() return output def __repr__(self): return "<ImageCacheNode>" def __iter__(self): for node in self.nodelist_file: yield node for node in self.nodelist_empty: yield node
def render(self, context): nodelist = NodeList() if context.has_key('forloop'): parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if self.reversed: # From http://www.python.org/doc/current/tut/node11.html def reverse(data): for index in range(len(data) - 1, -1, -1): yield data[index] values = reverse(values) for i, item in enumerate(values): context['forloop'] = { # shortcuts for current loop iteration number 'counter0': i, 'counter': i + 1, # reverse counter iteration numbers 'revcounter': len_values - i, 'revcounter0': len_values - i - 1, # boolean values designating first and last times through loop 'first': (i == 0), 'last': (i == len_values - 1), 'parentloop': parentloop, } context[self.loopvar] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() if context.has_key('forloop'): parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if self.reversed: # From http://www.python.org/doc/current/tut/node11.html def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index] values = reverse(values) for i, item in enumerate(values): context['forloop'] = { # shortcuts for current loop iteration number 'counter0': i, 'counter': i+1, # reverse counter iteration numbers 'revcounter': len_values - i, 'revcounter0': len_values - i - 1, # boolean values designating first and last times through loop 'first': (i == 0), 'last': (i == len_values - 1), 'parentloop': parentloop, } context[self.loopvar] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) context.pop() return nodelist.render(context)
def forcomment(context, nodelist, filediff, review=None): """ Loops over a list of comments beloning to a filediff. This will populate a special ``comment`` variable for use in the content. This is of the type :model:`reviews.Comment`. """ new_nodelist = NodeList() context.push() if not review: comments = filediff.comments.all() else: comments = filediff.comments.filter(review=review) for comment in comments: context['comment'] = comment for node in nodelist: new_nodelist.append(node.render(context)) context.pop() return new_nodelist.render(context)
def forcomment(context, nodelist, filediff, review=None): """ Loops over a list of comments beloning to a filediff. This will populate a special ``comment`` variable for use in the content. This is of the type :model:`reviews.Comment`. """ new_nodelist = NodeList() context.push() if not review: comments = filediff.comments.all() else: comments = filediff.comments.filter(review=review) for comment in comments: context['comment'] = comment for node in nodelist: new_nodelist.append(node.render(context)) context.pop() return new_nodelist.render(context)
class ForNode(Node): child_nodelists = ('nodelist_loop', 'nodelist_empty') def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None): self.loopvars, self.sequence = loopvars, sequence self.is_reversed = is_reversed self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} with context.push(): values = self.sequence.resolve(context, ignore_failures=True) if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) # Empty render if len_values < 1: return self.nodelist_empty.render(context) nodelist = [] if self.is_reversed: values = reversed(values) num_loopvars = len(self.loopvars) unpack = num_loopvars > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i + 1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) pop_context = False if unpack: # If there are multiple loop variables, unpack the item into # them. try: len_item = len(item) except TypeError: # not an iterable len_item = 1 # Check loop variable count before unpacking if num_loopvars != len_item: raise ValueError( "Need {} values to unpack in for loop; got {}. " .format(num_loopvars, len_item), ) unpacked_vars = dict(zip(self.loopvars, item)) pop_context = True context.update(unpacked_vars) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render_annotated(context)) if pop_context: # Pop the loop variables pushed on to the context to avoid # the context ending up in an inconsistent state when other # tags (e.g., include and with) push data to context. context.pop() return mark_safe(''.join(nodelist))
class IfBlockNode(BlockNode): def __init__(self, name, nodelist, parent=None, check_node=None): self.name, self.nodelist, self.parent = name, nodelist, parent self.original_nodelist = NodeList() self.final_nodelist = NodeList() self.original_nodelist.extend( self.nodelist ) self.final_nodelist.extend( self.nodelist ) self.check_node = check_node self.index = None for i, node in enumerate( nodelist ): if isinstance(node, self.check_node.__class__): if node.filter_expression.token == self.check_node.filter_expression.token: self.index = i break def __repr__(self): return "<MyBlock Node: %s. Contents: %r>" % (self.name, self.nodelist) def render(self, context): result = '' if self.parent: p = self pre = [] post = [] while p.parent: p = p.parent if p.nodelist == self.original_nodelist: p.nodelist = NodeList() else: index = None found = False for i, node in enumerate( p.nodelist ): if isinstance(node, self.check_node.__class__): if node.filter_expression.token == self.check_node.filter_expression.token: index = i found = True if found: pre[0:0] = p.nodelist[:index] post.extend(p.nodelist[index+1:]) p.nodelist = NodeList() if pre: self.final_nodelist[self.index:self.index] = pre self.index += len(pre) if post: self.final_nodelist[self.index+1:self.index+1] = post context.push() # Save context in case of block.super(). self.context = context context['block'] = self pre_result = self.nodelist.render(context) context['blockoutput'] = pre_result result = self.final_nodelist.render(context) context.pop() return result def super(self): if self.parent: return mark_safe(self.parent.render(self.context)) return '' def add_parent(self, nodelist): if self.parent: self.parent.add_parent(nodelist) else: self.parent = BlockNode(self.name, nodelist)
def render(self, context): """ This class has to be able to deal with two classes essentially... NestedModelForm and BaseFormset. Key thing to note here is that when we get a BaseFormset, what is happening is that the form associated with that BaseFormset has children. """ top_level = self.top_level actual_form = self.form_var.resolve(context) is_formset = issubclass(actual_form.__class__, BaseFormSet) form_name = get_form_name(actual_form) if not is_formset else get_form_name(actual_form.parent_form) # print("== Rendering %s (Formset: %s) " % (form_name, is_formset)) if self.helper is not None: actual_helper = self.helper_var.resolve(context) else: actual_helper = get_default_helper() if not hasattr(actual_form, "helper") else actual_form.helper if actual_helper.form_tag: actual_helper.form_tag = False # raise template.TemplateSyntaxError("form_tag cannot be True on the helper, please go and rectify that") # Place a link on the formset back to its parent form if not is_formset and hasattr(actual_form, "inline_form"): actual_form.inline_form.parent_form = actual_form """ Basically we create a node list and all the following things to it: - <div id='{form_name}_form_div' class='form-container'> - HtmlContent - Fields from the parent form - The inline form which prints the children and management form (hidden) - <div id='{form_name}_children_div' class='form-children'> --- Kids printed here --- </div> - <div id='{form_name}_management_form_div' class='management-form-div'> - Management form (hidden) - Inline actions form (if one exists) - </div> - </div> Then we return nodelist.render """ # Add the forms to the nodelist nodelist = NodeList() # Add the main form to our node list # === PRINT THE PARENT FORM if not is_formset: form_div_class = "%s_form_div" % form_name # print("Creating form div class: %s" %form_div_class) nodelist.append(HtmlContent("<div id='%s' class='form-container'>" % form_div_class)) nodelist.append(CrispyFormNode(form=self.form, helper=self.helper)) # === PRINT THE KIDS if is_formset: # e.g. BuildingFormSet # We need to add each form AND print the management form # Add a DIV for the children children_div_class = "%s_children_div" % form_name nodelist.append(HtmlContent("<div id='%s' class='form-children'>" % children_div_class)) for child_index in range(len(actual_form.forms)): child_form = actual_form.forms[child_index] if not hasattr(child_form, "helper"): child_form.helper = get_default_helper() child_form_name = "%s_%s" % (get_form_name(child_form), child_index) # print(" Adding %s to the nodelist" % child_form_name) child_form_helper_name = "%s_helper" % child_form_name context[child_form_name] = child_form context[child_form_helper_name] = child_form.helper process_helper(child_form.helper) if hasattr(child_form, "inline_form"): # print(" %s is a NestedModelForm, wrapping it in a nested node" % child_form_name) nodelist.append(NestedFormNode(child_form_name, child_form_helper_name, top_level=False)) else: # print(" %s (%s) is NOT a NestedModelForm, wrapping it in a crispy node" % (child_form_name, child_form.__class__)) nodelist.append(CrispyFormNode(child_form_name, child_form_helper_name)) nodelist.append(HtmlContent("</div>")) # We need to print the management form for these kids management_form_helper = FormHelper() management_form_helper.form_tag = False management_form_helper.disable_csrf = True management_form = actual_form.management_form context["%s_management_form" % form_name] = management_form context["%s_management_form_helper" % form_name] = management_form_helper # Place a data binding on the management form for KnockoutJS fields = management_form.fields fields["TOTAL_FORMS"].widget.attrs["data-bind"] = "value: totalForms" fields["INITIAL_FORMS"].widget.attrs["data-bind"] = "value: initialForms" fields["MAX_NUM_FORMS"].widget.attrs["data-bind"] = "value: maxForms" # Let Crispy handle the printing of this... # print("Adding %s management_form to the node list" % form_name) # Add a div for the management form management_form_div_class = get_management_form_div_name(actual_form.parent_form) nodelist.append(HtmlContent("<div id='%s' class='management-form-div'>" % management_form_div_class)) nodelist.append(CrispyFormNode("%s_management_form" % form_name, "%s_management_form_helper" % form_name)) # Check if there is an inline form if hasattr(actual_form, "actions_form") and actual_form.actions_form is not None: inline_actions_form_name = "%s-inline_actions_form" % get_form_name(actual_form.actions_form) inline_actions_form_helper_name = "%s-helper" % inline_actions_form_name context[inline_actions_form_name] = actual_form.actions_form context[inline_actions_form_helper_name] = actual_form.actions_form().helper nodelist.append(CrispyFormNode(form=inline_actions_form_name, helper=inline_actions_form_helper_name)) nodelist.append(HtmlContent("</div>")) else: # not a formset """ We have two cases to deal with here: - BlockForm - it has an inline form that we need to print here - TenantForm - no inline form to worry about... If it has an inline form, note that we need to make a NestedModelNode """ if hasattr(actual_form, "inline_form"): context["%s_inline_form" % form_name] = actual_form.inline_form nodelist.append(NestedFormNode("%s_inline_form" % form_name, self.helper, top_level=False)) if not is_formset: # we didn't add this if it was a formset nodelist.append(HtmlContent("</div>")) # for the form if top_level: # print out ALL the script templates nodelist.append(KnockoutFormTemplate(self.form)) return nodelist.render(context)
class ForNode(Node): def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None): self.loopvars, self.sequence = loopvars, sequence self.is_reversed = is_reversed self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty def __repr__(self): reversed_text = self.is_reversed and ' reversed' or '' return "<For Node: for %s in %s, tail_len: %d%s>" % \ (', '.join(self.loopvars), self.sequence, len(self.nodelist_loop), reversed_text) def __iter__(self): for node in self.nodelist_loop: yield node for node in self.nodelist_empty: yield node def get_nodes_by_type(self, nodetype): nodes = [] if isinstance(self, nodetype): nodes.append(self) nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype)) nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype)) return nodes def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() if self.is_reversed: values = reversed(values) unpack = len(self.loopvars) > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i + 1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) if unpack: # If there are multiple loop variables, unpack the item into # them. context.update(dict(zip(self.loopvars, item))) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if unpack: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)
def render(self, context): nodelist = NodeList() form = self.form_var.resolve(context) child_forms = [] # recursively find all inline_form that need to get printed while hasattr(form, "child_form"): child_forms.append((form.child_form, form)) form = form.child_form() """ All the nested forms we print out will have this general structure - <div id='{form_name}_form_div' class='form-container'> - HtmlContent - Fields from the parent form - The inline form which prints the children and management form (hidden) - <div id='{form_name}_children_div' class='form-children'> --- Kids printed here --- </div> - <div id='{form_name}_management_form_div' class='management-form-div'> - Management form (hidden) - Inline actions form (if one exists) - </div> - </div> """ # Loop through each and get the knockout templates for each for child_form, parent_form in child_forms: child_form = child_form() if isinstance(child_form, type) else child_form child_form.fields["delete_button"] = SubmitButtonField() # Add knockoutjs bindings to the child form fields for field_name, field in child_form.fields.iteritems(): attr = "{'id' : 'id_' + prefix + '-' + index + '-%s', 'name' : prefix + '-' + index + '-%s'}" % ( field_name, field_name, ) field.widget.attrs["data-bind"] = mark_safe("attr: %s" % attr) form_name = get_form_name(child_form) template_name = get_form_template_name(child_form) context["child_%s" % form_name] = child_form context["child_%s_helper" % form_name] = get_default_helper() # print out the script for the template nodelist.append(HtmlContent('<script type="text/html" id="%s">' % template_name)) form_container_attrs = "{'id': '%s_form_div' }" % get_form_name( child_form, prefix="' + prefix + '-' + index + '" ) nodelist.append( HtmlContent('<div data-bind="attr: %s" class="form-container">' % mark_safe(form_container_attrs)) ) nodelist.append(CrispyFormNode(form="child_%s" % form_name, helper="child_%s_helper" % form_name)) if hasattr(child_form, "inline_form"): # then print the management form as well """ If our child has a child (e.g. building has tenants) then print the management form for it's child (tenant) """ # first we need to actually print the div to hold the kids form_children_attrs = "{'id': '%s_children_div' }" % get_form_name( child_form, prefix="' + prefix + '-' + index +'" ) nodelist.append( HtmlContent( """ <div data-bind="attr: %s" class="form-children"></div> """ % mark_safe(form_children_attrs) ) ) management_form_div_class = get_management_form_div_name( parent_form, prefix="' + prefix + '-' + index + '" ) management_form_div_attrs = "{'id' : '%s'}" % management_form_div_class nodelist.append( HtmlContent( """ <div data-bind="attr: %s" class='management-form-div'> """ % management_form_div_attrs ) ) formset = child_form.inline_form grand_child_management_form = child_form.inline_form.management_form # Tweak it and adds Knockout bindings parent_prefix = parent_form.inline_form.prefix child_prefix = child_form.inline_form.prefix fields = grand_child_management_form.fields for field_name, field in fields.iteritems(): attr = ( "{'id' : 'id_' + prefix + '-' + index + '-%s-%s', 'name' : prefix + '-' + index + '-%s-%s'}" % (child_prefix, field_name, child_prefix, field_name) ) if field_name == "TOTAL_FORMS": attr = ( "{'id' : 'id_' + prefix + '-' + index + '-%s-%s', 'name' : prefix + '-' + index + '-%s-%s', 'value': totalForms }" % (child_prefix, field_name, child_prefix, field_name) ) field.widget.attrs["data-bind"] = mark_safe("attr: %s" % attr) context["child_%s_management_form" % form_name] = grand_child_management_form context["child_%s_management_form_helper" % form_name] = get_default_helper() nodelist.append( CrispyFormNode( "child_%s_management_form" % form_name, "child_%s_management_form_helper" % form_name ) ) if hasattr(formset, "actions_form") and formset.actions_form is not None: inline_actions_form_name = "%s-inline_actions_form" % get_form_name(child_form) inline_actions_form_helper_name = "%s-helper" % inline_actions_form_name context[inline_actions_form_name] = formset.actions_form context[inline_actions_form_helper_name] = formset.actions_form().helper nodelist.append( CrispyFormNode(form=inline_actions_form_name, helper=inline_actions_form_helper_name) ) nodelist.append(HtmlContent("</div>")) # end of the management form div nodelist.append(HtmlContent("</div>")) # end of form-cotnainer nodelist.append(HtmlContent("</script>")) return nodelist.render(context)
class ForNode(Node): child_nodelists = ("nodelist_loop", "nodelist_empty") def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None): self.loopvars, self.sequence = loopvars, sequence self.is_reversed = is_reversed self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty def __repr__(self): reversed_text = self.is_reversed and " reversed" or "" return "<For Node: for %s in %s, tail_len: %d%s>" % ( ", ".join(self.loopvars), self.sequence, len(self.nodelist_loop), reversed_text, ) def __iter__(self): for node in self.nodelist_loop: yield node for node in self.nodelist_empty: yield node def render(self, context): if "forloop" in context: parentloop = context["forloop"] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, "__len__"): values = list(values) len_values = len(values) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() if self.is_reversed: values = reversed(values) unpack = len(self.loopvars) > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context["forloop"] = {"parentloop": parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict["counter0"] = i loop_dict["counter"] = i + 1 # Reverse counter iteration numbers. loop_dict["revcounter"] = len_values - i loop_dict["revcounter0"] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict["first"] = i == 0 loop_dict["last"] = i == len_values - 1 pop_context = False if unpack: # If there are multiple loop variables, unpack the item into # them. try: unpacked_vars = dict(zip(self.loopvars, item)) except TypeError: pass else: pop_context = True context.update(unpacked_vars) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if pop_context: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)
class ForNode(Node): child_nodelists = ('nodelist_loop', 'nodelist_empty') zip = zip get_overall_len = min def __init__(self, loopvars_list, sequence_list, is_reversed_list, nodelist_loop, nodelist_empty=None, zip_func=None): self.loopvars_list, self.sequence_list = loopvars_list, sequence_list self.is_reversed_list = is_reversed_list self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty if zip_func is not None: self.zip = zip_func def __repr__(self): def make_rev_txt(revd): return revd and ' reversed' or '' rev_text_list = [make_rev_txt(revd) for revd in self.is_reversed_list] zip_list = zip(self.loopvars_list, self.sequence_list, rev_text_list) sections = ['%s in %s%s'%(', '.join(l), s, r) for l, s, r in zip_list] return "<For Node: for %s, tail_len: %d>" % \ ('; '.join(sections), len(self.nodelist_loop)) def __iter__(self): for node in self.nodelist_loop: yield node for node in self.nodelist_empty: yield node def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() vals_list = [] len_values_list = [] for s in self.sequence_list: try: values = s.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) vals_list.append(values) len_values_list.append(len(values)) len_values = self.get_overall_len(len_values_list) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() def rev(revd, values): return revd and reversed(values) or values values_list = [rev(*v) for v in zip(self.is_reversed_list, vals_list)] unpack_list = [len(l) > 1 for l in self.loopvars_list] # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, items in enumerate(self.zip(*values_list)): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) uli_zip = zip(unpack_list, self.loopvars_list, items) for unpack, loopvars, item in uli_zip: if unpack: # If there are multiple loop variables, unpack the item # into them. context.update(dict(zip(loopvars, item))) else: context[loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) for unpack in unpack_list: if unpack: # The loop variables were pushed on to the context so pop # them off again. This is necessary because the tag lets # the length of loopvars differ to the length of each set # of items and we don't want to leave any vars from the # previous loop on the context. context.pop() context.pop() return nodelist.render(context)
def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() vals_list = [] len_values_list = [] for s in self.sequence_list: try: values = s.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) vals_list.append(values) len_values_list.append(len(values)) len_values = self.get_overall_len(len_values_list) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() def rev(revd, values): return revd and reversed(values) or values values_list = [rev(*v) for v in zip(self.is_reversed_list, vals_list)] unpack_list = [len(l) > 1 for l in self.loopvars_list] # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, items in enumerate(self.zip(*values_list)): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) uli_zip = zip(unpack_list, self.loopvars_list, items) for unpack, loopvars, item in uli_zip: if unpack: # If there are multiple loop variables, unpack the item # into them. context.update(dict(zip(loopvars, item))) else: context[loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) for unpack in unpack_list: if unpack: # The loop variables were pushed on to the context so pop # them off again. This is necessary because the tag lets # the length of loopvars differ to the length of each set # of items and we don't want to leave any vars from the # previous loop on the context. context.pop() context.pop() return nodelist.render(context)
class ThumbnailNode(ThumbnailNodeBase): child_nodelists = ('nodelist_file', 'nodelist_empty') error_msg = ('Syntax error. Expected: ``thumbnail source geometry ' '[key1=val1 key2=val2...] as var``') def __init__(self, parser, token): bits = token.split_contents() if len(bits) < 5 or bits[-2] != 'as': raise TemplateSyntaxError(self.error_msg) self.file_ = parser.compile_filter(bits[1]) self.geometry = parser.compile_filter(bits[2]) self.options = {} for bit in bits[3:-2]: m = kw_pat.match(bit) if not m: raise TemplateSyntaxError(self.error_msg) key = smart_str(m.group('key')) value = parser.compile_filter(m.group('value')) self.options[key] = value self.as_var = bits[-1] self.nodelist_file = parser.parse(('empty', 'endthumbnail',)) if parser.next_token().contents == 'empty': self.nodelist_empty = parser.parse(('endthumbnail',)) parser.delete_first_token() else: self.nodelist_empty = NodeList() def _render(self, context): file_ = self.file_.resolve(context) geometry = self.geometry.resolve(context) options = {} for key, value in self.options.iteritems(): options[key] = value.resolve(context) try: # geometry may define a thumbnail preset preset = Preset.objects.get(name=geometry) geometry = preset.geometry options.update(preset.get_options()) except ObjectDoesNotExist: pass # geometery is not a preset name, assume it's a geometry string if settings.THUMBNAIL_DUMMY: thumbnail = DummyImageFile(geometry) elif file_: thumbnail = default.backend.get_thumbnail( file_, geometry, **options ) else: return self.nodelist_empty.render(context) context.push() context[self.as_var] = thumbnail output = self.nodelist_file.render(context) context.pop() return output def __repr__(self): return "<ThumbnailNode>" def __iter__(self): for node in self.nodelist_file: yield node for node in self.nodelist_empty: yield node
def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() vals_list = [] len_values_list = [] for s in self.sequence_list: try: values = s.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) vals_list.append(values) len_values_list.append(len(values)) len_values = self.get_overall_len(len_values_list) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() def rev(revd, values): return revd and reversed(values) or values values_list = [rev(*v) for v in zip(self.is_reversed_list, vals_list)] unpack_list = [len(l) > 1 for l in self.loopvars_list] # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, items in enumerate(self.zip(*values_list)): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) uli_zip = zip(unpack_list, self.loopvars_list, items) for unpack, loopvars, item in uli_zip: if unpack: # If there are multiple loop variables, unpack the item # into them. context.update(dict(zip(loopvars, item))) else: context[loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) for unpack in unpack_list: if unpack: # The loop variables were pushed on to the context so pop # them off again. This is necessary because the tag lets # the length of loopvars differ to the length of each set # of items and we don't want to leave any vars from the # previous loop on the context. context.pop() context.pop() return nodelist.render(context)
class ForNode(Node): child_nodelists = ('nodelist_loop', 'nodelist_empty') zip = zip get_overall_len = min def __init__(self, loopvars_list, sequence_list, is_reversed_list, nodelist_loop, nodelist_empty=None, zip_func=None): self.loopvars_list, self.sequence_list = loopvars_list, sequence_list self.is_reversed_list = is_reversed_list self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty if zip_func is not None: self.zip = zip_func def __repr__(self): def make_rev_txt(revd): return revd and ' reversed' or '' rev_text_list = [make_rev_txt(revd) for revd in self.is_reversed] zip_list = zip(self.loopvars_list, self.sequence_list, rev_text_list) sections = ['%s in %s%s'%(', '.join(l), s, r) for l, s, r in zip_list] zip(sections, rev_text_list) return "<For Node: for %s, tail_len: %d%s>" % \ ('; '.join(sections), len(self.nodelist_loop)) def __iter__(self): for node in self.nodelist_loop: yield node for node in self.nodelist_empty: yield node def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() vals_list = [] len_values_list = [] for s in self.sequence_list: try: values = s.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) vals_list.append(values) len_values_list.append(len(values)) len_values = self.get_overall_len(len_values_list) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() def rev(revd, values): return revd and reversed(values) or values values_list = [rev(*v) for v in zip(self.is_reversed_list, vals_list)] unpack_list = [len(l) > 1 for l in self.loopvars_list] # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, items in enumerate(self.zip(*values_list)): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) uli_zip = zip(unpack_list, self.loopvars_list, items) for unpack, loopvars, item in uli_zip: if unpack: # If there are multiple loop variables, unpack the item # into them. context.update(dict(zip(loopvars, item))) else: context[loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) for unpack in unpack_list: if unpack: # The loop variables were pushed on to the context so pop # them off again. This is necessary because the tag lets # the length of loopvars differ to the length of each set # of items and we don't want to leave any vars from the # previous loop on the context. context.pop() context.pop() return nodelist.render(context)
class ForNode(Node): def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None): self.loopvars, self.sequence = loopvars, sequence self.is_reversed = is_reversed self.nodelist_loop = nodelist_loop if nodelist_empty is None: self.nodelist_empty = NodeList() else: self.nodelist_empty = nodelist_empty def __repr__(self): reversed_text = self.is_reversed and ' reversed' or '' return "<For Node: for %s in %s, tail_len: %d%s>" % \ (', '.join(self.loopvars), self.sequence, len(self.nodelist_loop), reversed_text) def __iter__(self): for node in self.nodelist_loop: yield node for node in self.nodelist_empty: yield node def get_nodes_by_type(self, nodetype): nodes = [] if isinstance(self, nodetype): nodes.append(self) nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype)) nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype)) return nodes def render(self, context): if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} context.push() try: values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: values = [] if not hasattr(values, '__len__'): values = list(values) len_values = len(values) if len_values < 1: context.pop() return self.nodelist_empty.render(context) nodelist = NodeList() if self.is_reversed: values = reversed(values) unpack = len(self.loopvars) > 1 # Create a forloop value in the context. We'll update counters on each # iteration just below. loop_dict = context['forloop'] = {'parentloop': parentloop} for i, item in enumerate(values): # Shortcuts for current loop iteration number. loop_dict['counter0'] = i loop_dict['counter'] = i+1 # Reverse counter iteration numbers. loop_dict['revcounter'] = len_values - i loop_dict['revcounter0'] = len_values - i - 1 # Boolean values designating first and last times through loop. loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_values - 1) if unpack: # If there are multiple loop variables, unpack the item into # them. context.update(dict(zip(self.loopvars, item))) else: context[self.loopvars[0]] = item for node in self.nodelist_loop: nodelist.append(node.render(context)) if unpack: # The loop variables were pushed on to the context so pop them # off again. This is necessary because the tag lets the length # of loopvars differ to the length of each set of items and we # don't want to leave any vars from the previous loop on the # context. context.pop() context.pop() return nodelist.render(context)