From d1ec005924b10e0c738040586acaaa200db9d244 Mon Sep 17 00:00:00 2001 From: niphlod Date: Wed, 11 Mar 2015 00:48:51 +0100 Subject: [PATCH] caches recursive selects for references Why didn't we think before ? References are lazy, but when asked for representation why should we fetch the same referenced record over and over ? NB: the code caches only represent() fetching records from tables, that are the only idempotent represent() calls out there. We could cache every representation only asking for every represent() call to be idempotent. As I feel there will be someone returning random values, I left it out. I'll make a PR soon for pyDAL to fix the same behaviour. --- gluon/sqlhtml.py | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index a248a761..4ded2a6b 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -2626,6 +2626,7 @@ class SQLFORM(FORM): htmltable = TABLE(COLGROUP(*cols), THEAD(head)) tbody = TBODY() numrec = 0 + repr_cache = {} for row in rows: trcols = [] id = row[field_id] @@ -2641,14 +2642,31 @@ class SQLFORM(FORM): value = row[str(field)] maxlength = maxtextlengths.get(str(field), maxtextlength) if field.represent: - try: - value = field.represent(value, row) - except KeyError: + if field.type.startswith('reference'): + if field not in repr_cache: + repr_cache[field] = {} try: - value = field.represent( - value, row[field.tablename]) + nvalue = repr_cache[field][value] except KeyError: - pass + try: + nvalue = field.represent(value, row) + except KeyError: + try: + nvalue = field.represent( + value, row[field.tablename]) + except KeyError: + nvalue = None + repr_cache[field][value] = nvalue + else: + try: + nvalue = field.represent(value, row) + except KeyError: + try: + nvalue = field.represent( + value, row[field.tablename]) + except KeyError: + nvalue = None + value = nvalue elif field.type == 'boolean': value = INPUT(_type="checkbox", _checked=value, _disabled=True) @@ -3118,6 +3136,7 @@ class SQLTABLE(TABLE): components.append(THEAD(TR(*row))) tbody = [] + repr_cache = {} for (rc, record) in enumerate(sqlrows): row = [] if rc % 2 == 1: @@ -3176,7 +3195,11 @@ class SQLTABLE(TABLE): href = '%s/%s?%s' % (linkto, tref, urllib.urlencode({fref: r})) r = A(represent(field, r, record), _href=str(href)) elif field.represent: - r = represent(field, r, record) + if field not in repr_cache: + repr_cache[field] = {} + if r not in repr_cache[field]: + repr_cache[field][r] = represent(field, r, record) + r = repr_cache[field][r] elif linkto and hasattr(field._table, '_primarykey')\ and fieldname in field._table._primarykey: # have to test this with multi-key tables @@ -3293,6 +3316,7 @@ class ExportClass(object): return value represented = [] + repr_cache = {} for record in self.rows: row = [] for col in self.rows.colnames: @@ -3308,7 +3332,14 @@ class ExportClass(object): if field.type == 'blob' and value is not None: value = '' elif field.represent: - value = field.represent(value, record) + if field.type.startswith('reference'): + if field not in repr_cache: + repr_cache[field] = {} + if value not in repr_cache[field]: + repr_cache[field][value] = field.represent(value, record) + value = repr_cache[field][value] + else: + value = field.represent(value, record) row.append(none_exception(value)) represented.append(row)