Sometimes we want to render items as cells in table with fixed row-count and computable col-count shape and vice versa. It's not difficult to do it with compute odd and even row, col index, but more common way is to use some reshape function. Theare are simple TAG for it: "table", with use reshape function and FILTER "flatindex" wich can use to get flat index in nested loops (may use with table like in this example).
Example of usage:
{# List filials must exists in context! #}
{% load table %}
<table border="0" width="100%">
{% table filials "3x?" %}
{% for row in table_obj %}
<tr>
{% for record in row %}
{% if record %}
<td class="mf_table_cell" onclick="selcell('filial_{{forloop|flatindex}}')">
<img src="/art/filial.gif" style="margin-bottom: 4px;"/><br/>
<span id="filial_{{forloop|flatindex}}" class="mf_table_unselcell">{{ record }}</span>
</td>
{% else %}
<td class="mf_table_cell">
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
{% endtable %}
</table>
/best regards Yosifov Pavel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | # 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
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.