# table.py -- tag and filter implementation from django import template from django.shortcuts import render_to_response from django.template.loader import get_template def reshape( lst, ncols, nrows, horiz=True ): """Change shape of list lst (like APL, J, K, NumPy). Return list of lists: ncols x nrows. horiz - is the table direction (horizontal or vertical if horiz is False). Empty cells will be with '' """ if not ncols and not nrows: return lst w = ncols or len(lst)/nrows + (1 if len(lst)%nrows else 0) h = nrows or len(lst)/ncols + (1 if len(lst)%ncols else 0) if horiz: flatten = lambda irow, icol: icol + irow*w else: flatten = lambda irow, icol: irow + icol*h rows = [] for irow in range( h ): col = [] for icol in range( w ): iflat = flatten( irow, icol ) el = '' if iflat >= len(lst) else lst[iflat] col.append( el ) rows.append( col ) return rows register = template.Library() @register.tag def table( parser, token ): """ Push in context 'table_obj' object - list of lists, result of reshape function (see it)""" try: # lst - name of the list in the context, shape is string like 'H:4x?'|'V:2x2'|'?x3' # 'H' - horiz direction, 'V' - vertical direction, '?' - computable size, digit - # fixed size (see reshape function!) tag, lst, shape = token.split_contents() except ValueError: sx = 'tag %r requires two arguments'%token.contents[0] raise template.TemplateSyntaxError( sx ) shape = shape[1:-1].upper() # cut .. from ".." if shape.startswith( 'V:' ): horiz = False shape = shape[2:] elif shape.startswith( 'H:' ): horiz = True shape = shape[2:] else: horiz = True w,h = shape.split( 'X' ) w = None if w == '?' else int(w) h = None if h == '?' else int(h) if not h and not w: raise template.TemplateSyntaxError( 'only one axis may be unknown (?)' ) nodes = parser.parse( ('endtable',) ) parser.delete_first_token() return TableNode( nodes, lst, w, h, horiz ) class TableNode( template.Node ): def __init__( self, nodes, lst, w, h, horiz ): self.nodes = nodes self.lst = lst self.w = w self.h = h self.horiz = horiz def render( self, context ): # get list from context by it's name res = reshape( context[self.lst], self.w, self.h, self.horiz ) context.push() context[ 'table_obj' ] = res txt = self.nodes.render( context ) context.pop() return txt @register.filter def flatindex( forloop ): """Existed in the nested loops return flat index (index of flat list). For example: like in C N-th dimension array may look like flat array with ONE, flat index. This tag generate this flat index for nested loops in django template (see nested {% for...%})""" loop = forloop level = 0 ret = 0 nestedlen = 1 while True: if level == 0: ret += loop['counter0'] # length of current level * size of previous levels is # "weight" of ranking level. Ranking level add # nestedlen to flatindex if move by 1 (like hypercube). nestedlen *= loop['counter0'] + loop['revcounter0'] + 1 else: ret += loop['counter0']*nestedlen # go to next-up level parentloop = loop.get('parentloop', None) if parentloop: loop = parentloop else: break level += 1 return ret