From cd9bd799ed0ddeafc997dadc0717c00989f5a807 Mon Sep 17 00:00:00 2001 From: Renaud Le Gac <legac@cppm.in2p3.fr> Date: Tue, 23 Oct 2012 20:14:55 +0200 Subject: [PATCH] Improved version of the Selector with many more fonctionalities. --- modules/plugin_dbui/report.py | 129 +++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 26 deletions(-) diff --git a/modules/plugin_dbui/report.py b/modules/plugin_dbui/report.py index 7220f5e7..9027eb63 100644 --- a/modules/plugin_dbui/report.py +++ b/modules/plugin_dbui/report.py @@ -1,19 +1,24 @@ """ Base tools to build report -A database report relies on four main components: - - A selector form allowing the user to defined conditions. - It can be build using a virtual database, - - The Selector class to decode the selected values and to build query. - - A controller to extract value from the selector and - to interrogate the database. +A database report relies on three main components: + - A selector table and its form to allow the user to defined conditions. + It can be build using a virtual database. + - The Selector running in a controller to decode the user requirement + and to select records in the database. - A view to render the selected records. A powerful mechanism is also in place to render the report in different format like HTML, CSV, .... It relies on the Selector class, on the IFRAME and -on the view. +on the view: + + selector = Selector(virtdb.myselector, extfield='format') + iframe = selector.download() + if iframe: + return iframe """ +from datetime import date, datetime, time from gluon import current from gluon.html import IFRAME, URL from gluon.storage import Storage @@ -28,25 +33,27 @@ class Selector(Storage): Decode the data send by the selector widget. Build the query for a given table of the database. + Select Rows for a given table of the database. + + This class handle table and its foreign keys. + The basic query handles the selector constraints + and the inner join for foreign keys. Additional + constraints can be added via the method add_query. All fields of the selector are attributes of this class. They can be accessed via myselector.myfield or myselector['myfield']. + There type are those defined in the model (virtdb.myselector) A mechanism is provide to download the report in different format which can be selected by the user. It relies on the extfield and - on the method download. Inside a controller: - - selector = Selector(db, extfield='format') - iframe = selector.download() - if iframe: - return iframe + on the method download. """ - def __init__(self, db, extfield='format'): + def __init__(self, table, extfield='format'): - self._db = db self._ext_field = extfield self._extension = None + self._extra_queries = [] # Decode the current request for key in current.request.vars: @@ -55,14 +62,50 @@ class Selector(Storage): if len(t) != 2 : continue - field = t[1] - if field == self._ext_field: + fieldname = t[1] + if fieldname == self._ext_field: self._extension = current.request.vars[key] + + # ignore field id + elif fieldname == 'id': + continue + + val = current.request.vars[key] + + if not val: + self[fieldname] = val + continue + + # convert the selector value according to field type + fieldtype = table[fieldname].type + + if fieldtype == 'boolean': + val = val == 'true' or val == 'True' + + elif fieldtype == 'date': + ds = datetime.strptime(val, '%Y-%m-%dT%H:%M:%S') + val = date(ds.year, ds.month, ds.day) + + elif fieldtype == 'datetime': + val = datetime.strptime(val, '%Y-%m-%dT%H:%M:%S') + + elif fieldtype == 'double': + val = float(val) - elif field != 'id': - self[field] = current.request.vars[key] + elif fieldtype == 'integer': + val = int(val) + elif fieldtype == 'time': + ds = datetime.strptime(val, '%H:%M:%S') + val = time(ds.hour, ds.minute, ds.second) + + self[fieldname] = val + + def append_query(self, query): + self._extra_queries.append(query) + + def as_dict(self): """Return the selector fields and their values as a dictionary. @@ -128,17 +171,18 @@ class Selector(Storage): return li - def query(self, tablename, exclude_fields=()): - """Build the database query for the table tablename - including inner join for foreign keys and selector constraints. + def query(self, table, exclude_fields=()): + """Build the database query for the database table + including inner join for foreign keys, selector constraints + and extra queries. The latter can be add via the append_query + method. The extfield and fields in the exclude_fields tuple are not take into account. """ - db = self._db + db = table._db query = None - table = self._db[tablename] # inner join for foreign keys if is_table_with_foreign_fields(table): @@ -159,11 +203,44 @@ class Selector(Storage): fieldname == self._ext_field: continue - q = db[tablename][fieldname] == self[fieldname] + q = table[fieldname] == self[fieldname] if query: query = (query) & (q) else: query = q - return query \ No newline at end of file + # append the extra queries + for q in self._extra_queries: + query = (query) & (q) + + return query + + + def select(self, table, exclude_fields=(), **kwargs): + """Select the record of the table according to the selector constraints + and to the extra queries. + + The extfield and fields in the exclude_fields tuple are + not take into account. + + It returns Rows which contains foreign tables columns. + + The keyword arguments are those of the select orderby, groupby, .... + + """ + db = table._db + columns = [table.ALL] + + # columns for foreign tables + if is_table_with_foreign_fields(table): + for field in table: + if is_foreign_field(field): + k_table, k_field, k_id = get_foreign_field(field) + columns.append(db[k_table].ALL) + + # query handling selector constraints + query = self.query(table, exclude_fields=exclude_fields) + + # retrieve the selected records + return db(query).select(*columns, **kwargs) -- GitLab