Login

Reshape list for table, flatten index in nested loops

Author:
aquagnu
Posted:
February 23, 2008
Language:
Python
Version:
.96
Score:
0 (after 0 ratings)

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"> &nbsp; </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

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

Please login first before commenting.