Package turbogears :: Package toolbox :: Package catwalk :: Module browse

Source Code for Module turbogears.toolbox.catwalk.browse

  1  import cherrypy 
  2   
  3  try: 
  4      import sqlobject 
  5  except ImportError: 
  6      sqlobject = None 
  7  else: 
  8      from sqlobject.sqlbuilder import Select, func, AND, IN 
  9   
 10  import turbogears 
 11  from turbogears import expose, controllers 
12 13 14 -class Browse(controllers.Controller):
15
16 - def __getattr__(self, attrib):
17 """Delegate basic methods to CatWalk.""" 18 return getattr(self.catwalk, attrib)
19 20 @expose(template='turbogears.toolbox.catwalk.browse_grid', allow_json=True)
21 - def index(self, object_name, start=0, page_size=10, 22 context='', filters=''):
23 try: 24 start, page_size = int(start), int(page_size) 25 except ValueError: 26 start, page_size = 0, 10 27 if not context: 28 context = object_name 29 headers = [header for header in self.column_headers( 30 object_name, context) if header['visible']] 31 total, rows = self.rows_for_model( 32 object_name, start, page_size, filters) 33 return dict(object_name=object_name, start=start, page_size=page_size, 34 total=total, headers= headers, rows = rows)
35 36 @expose(template='turbogears.toolbox.catwalk.columns', allow_json=True)
37 - def columns(self, object_name, context=''):
38 if not context: 39 context = object_name 40 return dict(object_name=object_name, context = context, 41 columns=self.extended_column_headers(object_name, context))
42 43 @expose(allow_json=True)
44 - def save_columns(self, object_name, context, order, hidden_columns, 45 updated_fk_labels):
46 self.save_column_order(context, order) 47 self.hide_columns(context, hidden_columns) 48 if updated_fk_labels: 49 for updated_fk_label in updated_fk_labels.split('|'): 50 obj, column_name = updated_fk_label.split(':') 51 self.column_label_for_object(obj, column_name) 52 return ("<script>parent.cat_browse.columns_saved('%s','%s');" 53 "</script>" % (object_name, context))
54
55 - def extended_column_headers(self, object_name, context):
56 cols = [{'name': 'id', 'title': '#', 'type': 'SOInteger'}] 57 cols.extend(self.column_labels(object_name, extended=True)) 58 cols.extend(self.join_labels(object_name, extended=True)) 59 cols = self.arrange_columns(cols, context) 60 return cols
61
62 - def column_headers(self, object_name, context):
63 cols = [{'name': 'id', 'title': '#'}] 64 cols.extend(self.column_labels(object_name)) 65 cols.extend(self.join_labels(object_name)) 66 cols = self.arrange_columns(cols, object_name) 67 return cols
68
69 - def arrange_columns(self, headers, context):
70 # arrange order and visibility 71 hidden_columns = self.load_columns_visibility_state(context) 72 order = self.load_column_order(context) 73 for col in headers: 74 col['visible'] = True 75 if col['name'] in hidden_columns: 76 col['visible'] = False 77 if not order: 78 return headers 79 c = {} 80 for col in headers: 81 c[col['name']] = col 82 if col['name'] not in order: 83 order.append(col['name']) 84 rearrenged = [] 85 for name in order: 86 if name not in c.keys(): 87 continue 88 rearrenged.append(c[name]) 89 return rearrenged
90
91 - def prepare_filter(self, obj, filter):
92 for column in obj.sqlmeta.columns.values(): 93 if column.origName == filter[0]: 94 return getattr(obj.q, column.name) == filter[1] 95 # if we got so far we couldn't find the column, bark at the moon 96 msg = ('filter_column_error.' 97 ' Could not find the column for filter: %s' % filter[0]) 98 raise cherrypy.HTTPRedirect(turbogears.url('/error', msg=msg))
99
100 - def filtered_query(self, obj, filters):
101 if not ':' in filters: # there should at least be a semicolon 102 msg = ('filter_format_error.' 103 ' The format is column_name:value, not %s' % filters) 104 raise cherrypy.HTTPRedirect(turbogears.url('/error', msg=msg)) 105 106 filters = [filter.split(':') for filter in filters.split(',')] 107 conditions = tuple([self.prepare_filter(obj, filter) 108 for filter in filters]) 109 return obj.select(AND(* conditions))
110
111 - def rows_for_model(self, object_name, start, page_size, filters):
112 rows = {} 113 obj = self.load_object(object_name) 114 115 if filters: 116 query = self.filtered_query(obj, filters) 117 else: 118 query = obj.select() 119 120 total = query.count() 121 if page_size: 122 results = query[start:start+page_size] 123 else: 124 results = query[start:] 125 126 for result in results: 127 rows[result.id] = self.fields(object_name, result) 128 129 relations = self.relation_values(object_name, rows) 130 rows = self.merge_relation_values(rows, relations) 131 rows = self.foreign_key_alias_value(object_name, rows) 132 return total, rows
133
134 - def relation_values(self, object_name, rows):
135 joins = {} 136 ids = rows.keys() 137 if not ids: 138 return joins 139 140 obj = self.load_object(object_name) 141 conn = obj._connection 142 for column in obj.sqlmeta.joins: 143 query = None 144 coltype = self.get_column_type(column) 145 if coltype in ('SOMultipleJoin', 'SOSQLMultipleJoin'): 146 query = conn.sqlrepr(Select([ 147 column.soClass.q.id, 148 func.Count(column.otherClass.q.id)], 149 where=AND( 150 column.soClass.q.id==self.join_foreign_key(column), 151 IN(column.soClass.q.id, ids)), 152 groupBy=column.soClass.q.id)) 153 154 elif coltype in ('SORelatedJoin', 'SOSQLRelatedJoin'): 155 d = (column.intermediateTable, 156 column.joinColumn, 157 column.intermediateTable, 158 column.otherColumn, 159 column.intermediateTable, 160 column.intermediateTable, 161 column.joinColumn, 162 ','.join(['%s' % x for x in ids]), 163 column.intermediateTable, 164 column.joinColumn) 165 166 query = ("SELECT %s.%s, Count(%s.%s) FROM %s" 167 " WHERE %s.%s IN(%s) GROUP BY %s.%s" % d) 168 169 elif coltype == 'SOSingleJoin': 170 alias = self.load_label_column_for_object(column.otherClassName) 171 query = conn.sqlrepr(Select([ 172 column.soClass.q.id, getattr(column.otherClass.q, alias)], 173 where=AND( 174 column.soClass.q.id==self.join_foreign_key(column), 175 IN(column.soClass.q.id,ids)))) 176 177 if not query: 178 continue 179 joins[column.joinMethodName] = conn.queryAll(query) 180 return joins
181
182 - def foreign_key_alias_value(self, object_name, rows):
183 for column in self.foreign_key_columns(object_name): 184 alias = self.load_label_column_for_object(column.foreignKey) 185 if alias == 'id': 186 continue 187 column_name = column.name.replace('ID', '') 188 fk_values = self.foreign_key_query(column, alias, 189 [x[column_name] for x in rows]) 190 for row in rows: 191 row[column_name] = fk_values.get(row[column_name], '') 192 return rows
193
194 - def foreign_key_query(self, column, alias, ids):
195 if not ids: 196 return {} 197 sql_object = self.load_object(column.foreignKey) 198 conn = sql_object._connection 199 query = conn.sqlrepr(Select( 200 [sql_object.q.id, getattr(sql_object.q, alias)], 201 where=IN(sql_object.q.id, ids))) 202 fk_values = {} 203 for id, alias in conn.queryAll(query): 204 fk_values[str(id)] = self.encode_label(alias) 205 return fk_values
206
207 - def join_foreign_key(self, column):
208 try: 209 foreign_key = '%sID' % column.joinColumn.rsplit('_', 1)[0] 210 return getattr(column.otherClass.q, foreign_key) 211 except AttributeError: 212 raise AttributeError("Key %r in %s pointing to %s not found.\n" 213 "You may need to rename it or use the joinColumn argument." 214 % (foreign_key, 215 column.otherClass.__name__, column.soClass.__name__,))
216
217 - def column_label_options(self, column):
218 foreign_key_labels = [{'name': 'id', 'title': '#'}] 219 foreign_key_labels.extend(self.column_labels(column.foreignKey)) 220 return foreign_key_labels
221
222 - def column_labels(self, object_name, extended=False):
223 cols = [] 224 sql_object = self.load_object(object_name) 225 for column_name in sql_object.sqlmeta.columns: 226 column = sql_object.sqlmeta.columns[column_name] 227 if sql_object._inheritable and column_name == 'childName': 228 continue 229 cols.append({'name': column.name, 230 'title': self.column_title(column)}) 231 col = cols[-1] 232 if isinstance(column, sqlobject.col.SOForeignKey): 233 col['name'] = col['name'].replace('ID', '') 234 if extended: 235 col['type'] = self.get_column_type(column) 236 if isinstance(column, sqlobject.col.SOForeignKey): 237 col['column_label'] = self.load_label_column_for_object( 238 column.foreignKey) 239 col['label_options'] = self.column_label_options(column) 240 col['other_class_name'] = column.foreignKey 241 return cols
242
243 - def join_labels(self, object_name, extended=False):
244 cols = [] 245 sql_object = self.load_object(object_name) 246 for col in sql_object.sqlmeta.joins: 247 cols.append({'name': col.joinMethodName, 'title': ''}) 248 if extended: 249 cols[-1]['type'] = self.get_column_type(col) 250 cols[-1]['other_class_name'] = col.otherClassName 251 return cols
252
253 - def merge_relation_values(self, rows, relations):
254 for field_name in relations: 255 for id, value in relations[field_name]: 256 if id not in rows: 257 continue 258 rows[id][field_name] = self.encode_label(value) 259 keys = rows.keys() 260 keys.sort() 261 return [rows[x] for x in keys]
262
263 - def foreign_key_columns(self, object_name):
264 foreign_keys = [] 265 sql_object = self.load_object(object_name) 266 for column_name in sql_object.sqlmeta.columns: 267 column = sql_object.sqlmeta.columns[column_name] 268 if sql_object._inheritable and column_name == 'childName': 269 continue 270 if isinstance(column, sqlobject.col.SOForeignKey): 271 foreign_keys.append(column) 272 return foreign_keys
273
274 - def field_value(self, result, column):
275 value = getattr(result, column.name) 276 if value is not None: 277 value = self.encode_label(value) 278 return value
279
280 - def fields(self, object_name, result):
281 obj = self.load_object(object_name) 282 props = {} 283 props['id'] = result.id 284 for column_name in obj.sqlmeta.columns: 285 column = obj.sqlmeta.columns[column_name] 286 if obj._inheritable and column_name == 'childName': 287 continue 288 column_name = column.name 289 if isinstance(column, sqlobject.col.SOForeignKey): 290 column_name = column_name.replace('ID', '') 291 props[column_name] = self.field_value(result, column) 292 return props.copy()
293