Package turbogears :: Package toolbox :: Package catwalk

Source Code for Package turbogears.toolbox.catwalk

   1  """CatWalk - model browser for TurboGears""" 
   2   
   3  __version__ = "0.9.4" 
   4  __author__ = "Ronald Jaramillo" 
   5  __email__ = "ronald@checkandhsare.com" 
   6  __copyright__ = "Copyright 2005 Ronald Jaramillo" 
   7  __license__ = "MIT" 
   8   
   9  from browse import Browse 
  10  import cPickle as pickle 
  11  import datetime 
  12  import os 
  13  import re 
  14  import socket 
  15  import struct 
  16  import time 
  17   
  18  import pkg_resources 
  19   
  20  import cherrypy 
  21   
  22  try: 
  23      import sqlobject 
  24  except ImportError: 
  25      sqlobject = None 
  26   
  27  import turbogears 
  28  from turbogears import expose, identity 
  29   
  30   
  31  date_parser = re.compile(r"""^ 
  32      (?P<year>\d{4,4}) 
  33      (?: 
  34          - 
  35          (?P<month>\d{1,2}) 
  36          (?: 
  37              - 
  38              (?P<day>\d{1,2}) 
  39              (?: 
  40                  T 
  41                  (?P<hour>\d{1,2}) 
  42                  : 
  43                  (?P<minute>\d{1,2}) 
  44                  (?: 
  45                      : 
  46                      (?P<second>\d{1,2}) 
  47                      (?: 
  48                          \. 
  49                          (?P<dec_second>\d+)? 
  50                      )? 
  51                  )? 
  52                  (?: 
  53                      Z 
  54                      | 
  55                      (?: 
  56                          (?P<tz_sign>[+-]) 
  57                          (?P<tz_hour>\d{1,2}) 
  58                          : 
  59                          (?P<tz_min>\d{2,2}) 
  60                      ) 
  61                  ) 
  62              )? 
  63          )? 
  64      )? 
  65  $""", re.VERBOSE) 
  66   
  67   
68 -def parse_datetime(s):
69 """Parse a string and return a datetime object.""" 70 assert isinstance(s, basestring) 71 r = date_parser.search(s) 72 try: 73 a = r.groupdict('0') 74 except: 75 raise ValueError, 'invalid date string format' 76 dt = datetime.datetime( 77 int(a['year']), int(a['month']) or 1, int(a['day']) or 1, 78 # If not given these will default to 00:00:00.0 79 int(a['hour']), int(a['minute']), int(a['second']), 80 # Convert into microseconds 81 int(a['dec_second'])*100000) 82 t = datetime.timedelta(hours=int(a['tz_hour']), minutes=int(a['tz_min'])) 83 if a.get('tz_sign', '+') == "-": 84 return dt + t 85 else: 86 return dt - t
87 88
89 -class CatWalk(turbogears.controllers.Controller):
90 """Model Browser. 91 92 An administration tool for listing, creating, updating or deleting 93 your SQLObject instances. 94 95 """ 96 97 __label__ = "CatWalk" 98 __version__ = "0.9" 99 __author__ = "Ronald Jaramillo" 100 __email__ = "ronald@checkandshare.com" 101 __copyright__ = "Copyright 2005 Ronald Jaramillo" 102 __license__ = "MIT" 103 browse = Browse() 104 need_project = True 105 icon = "/tg_static/images/catwalk.png" 106
107 - def __init__(self, model=None):
108 """CatWalk's initializer. 109 110 @param model: reference to a project model module 111 @type model: yourproject.model 112 113 """ 114 115 try: 116 if not sqlobject: 117 raise ImportError, "The SQLObject package is not installed." 118 if not model: 119 model = turbogears.util.get_model() 120 if not model: 121 raise ImportError, ("No SQLObject model found.\n" 122 "If you are mounting CatWalk to your controller,\n" 123 "remember to import your model and pass a reference to it.") 124 self.model = model 125 if not self.models(): 126 raise ImportError, "The SQLObject model is empty." 127 try: 128 self._connection = model.hub 129 except Exception: 130 self._connection = sqlobject.sqlhub 131 except Exception, e: 132 raise ImportError, ( 133 "CatWalk failed to load your model file.\n" + str(e)) 134 self.browse.catwalk = self 135 turbogears.config.update({'log_debug_info_filter.on': False}) 136 self.register_static_directory()
137
138 - def register_static_directory(self):
139 static_directory = pkg_resources.resource_filename(__name__, 'static') 140 turbogears.config.update({'/tg_toolbox/catwalk': { 141 'static_filter.on': True, 142 'static_filter.dir': static_directory}})
143 144 [expose(format="json")]
145 - def error(self, msg=''):
146 """Generic error handler for json replies.""" 147 return dict(error=msg)
148
149 - def load_object(self, object_name):
150 """Return a class reference from the models module by name. 151 152 @param object_name: name of the object 153 @type object_name: string 154 155 """ 156 try: 157 obj = getattr(self.model, object_name) 158 except: 159 msg = 'Fail to get reference to object %s' % object_name 160 raise cherrypy.HTTPRedirect(turbogears.url('error', msg=msg)) 161 return obj
162
163 - def load_instance(self, object_name, id):
164 """Return and instance of the named object with the requested id""" 165 obj = self.load_object(object_name) 166 try: 167 return obj.get(id) 168 except: 169 msg ='Fail to get instance of object: %s with id: %s' % ( 170 object_name, id) 171 raise cherrypy.HTTPRedirect(turbogears.url('error', msg=msg))
172
173 - def object_field(self, row, column):
174 """Get object field. 175 176 Returns a dict containing the column name and value for the 177 specific column and row, 178 179 @param row: model instance 180 @param column: dict containing columnName, title, type, 181 eventually join, joinMethodName and/or options 182 @type column: dict 183 184 """ 185 if column.get('type', '') == 'SOSingleJoin': 186 try: 187 subject = getattr(row, column['joinMethodName']) 188 value = '%s' % getattr(subject, column['labelColumn']) 189 except Exception: 190 return {'column': column['columnName'], 191 'value': 'None', 'id': '0'} 192 return {'column': column['columnName'], 'value': value} 193 elif column.get('type','') in ('SORelatedJoin', 'SOSQLRelatedJoin'): 194 return self.related_join_count(row, column) 195 elif column.get('type', '') in ('SOMultipleJoin', 'SOSQLMultipleJoin'): 196 return self.multiple_join_count(row, column) 197 elif column.get('type','') == 'SOForeignKey': 198 return self.object_field_for_foreign_key(row, column) 199 elif column.get('type', '') == 'SOStringCol': 200 value = getattr(row, column['columnName']) 201 value = self.encode_label(value) 202 return {'column': column['columnName'], 'value': value} 203 else: 204 try: 205 value = u'%s' % getattr(row, column['columnName']) 206 except UnicodeDecodeError: 207 value = unicode(getattr(row, column['columnName']), 'UTF-8') 208 return {'column': column['columnName'], 'value': value}
209
210 - def multiple_join_count(self, row, column):
211 """Return the total number of related objects.""" 212 try: 213 columnObject = getattr(self.model, column['join']) 214 for clm in columnObject.sqlmeta.columnList: 215 if type(clm) == sqlobject.SOForeignKey: 216 if column['objectName'] == clm.foreignKey: 217 foreign_key = clm 218 fkName = foreign_key.name 219 fkQuery = getattr(columnObject.q, str(fkName)) 220 select = columnObject.select(fkQuery == row.id) 221 value = '%s' % select.count() 222 except Exception: 223 value = '0' 224 return {'column': column['joinMethodName'], 'value': value}
225
226 - def related_join_count(self, row, column):
227 """Return the total number of related objects.""" 228 try: 229 value = '%s' % len(list(getattr(row, column['joinMethodName']))) 230 except Exception: 231 value = '0' 232 return {'column': column['joinMethodName'], 'value': value}
233
234 - def object_field_for_foreign_key(self, row, column):
235 """Return the foreign key value.""" 236 try: 237 name = getattr(row, column['columnName']) 238 value = getattr(name, column['labelColumn']) 239 value = self.encode_label(value) 240 except AttributeError: 241 return {'column': column['columnName'], 242 'value': 'None', 'id': '0'} 243 return {'column': column['columnName'], 244 'value': value, 'id': '%s' % name.id}
245
246 - def update_object(self, object_name, id, values):
247 self.load_object(object_name) 248 instance = self.load_instance(object_name, id) 249 columns = self.object_columns(object_name) 250 parameters = self.extract_parameters(columns, values) 251 instance.set(**parameters)
252 263
264 - def remove_object(self, object_name, id):
265 """Remove the object by id.""" 266 obj = self.load_object(object_name) 267 self.remove_related_joins_if_any(object_name, id) 268 try: 269 obj.delete(id) 270 except: 271 msg = 'Fail to delete instance id: %s for object: %s' % ( 272 id, object_name) 273 raise cherrypy.HTTPRedirect(turbogears.url('error', msg=msg))
274
275 - def extract_parameters(self, cols, values):
276 """Loop trough the columns and extract the values from the dictionary. 277 278 @param cols: column list 279 @param values: dict of submited values 280 281 """ 282 params = {} 283 for col in cols: 284 column_name = col['columnName'] 285 if values.has_key(column_name): 286 if col['type'] == 'SODateTimeCol': 287 dt = values[column_name] 288 try: 289 b = parse_datetime('%sZ' % dt.replace(' ', 'T')) 290 except ValueError: 291 b = None 292 values[column_name] = b 293 elif col['type'] == 'SOBoolCol': 294 try: 295 b = bool(int(values[column_name])) 296 except ValueError: 297 b = False 298 values[column_name] = b 299 elif col['type'] == 'SOFloatCol': 300 try: 301 b = float(values[column_name]) 302 except ValueError: 303 b = 0.0 304 values[column_name] = b 305 elif col['type'] == 'SOIntCol': 306 try: 307 b = int(values[column_name]) 308 except ValueError: 309 b = 0 310 values[column_name] = b 311 elif col['type'] == 'SOForeignKey': 312 self.extract_foreign_key(values, column_name) 313 elif col['type'] in ('SODecimalCol','SOCurrencyCol'): 314 self.extract_decimal_value(values, column_name) 3