def save(self, *args, **kwargs): """ Apply sourcefile and namespaces to newly created Reports. sourcefiles will be parsed into the following namespaces: 'config.reports.1_overall' --> 'default' 'steelscript.netshark.appfwk.reports.3_shark' --> 'netshark' 'steelscript.appfwk.business_hours.reports.x_rpt' --> 'business_hours' """ if not self.sourcefile: mod = get_module() self.filepath = mod.__file__ modname = get_module_name(mod) self.sourcefile = get_sourcefile(modname) if not self.namespace: self.namespace = get_namespace(self.sourcefile) if not self.slug: self.slug = slugify(self.sourcefile.split('.')[-1]) super(Report, self).save(*args, **kwargs)
def create(cls, name, **kwargs): """Create a table. :param str name: Unique identifier for this table Standard keyword arguments: :param int rows: set maximum number of rows to save after sorting (defaults to -1, no maximum) :param bool resample: if True, timeseries data returned by the data source will be resampled to ``criteria.resample_resolution`` or ``criteria.resolution`` :param dict field_map: a dictionary mapping fields by keyword to either a new keyword or to a map of field values to customize for the given field field_map = {'qos': 'qos_1'} or field_map = {'qos': { 'keyword': 'qos_1', 'label': 'QoS 1', 'default': 'AF' } } This is used to remap fields defined by standard tables to allow the same table to be used multiple times in the same report but with different criteria via different keywords. Additional table and field options keyword arguments may be provided that are unique to the specific data source table being instantiatied: ``table_options`` These options define subclass-specific options that allow customization of a table instance. Table options are *not* visible to users running reports via the UI. Option values are provided at table creation and are considered static for the life of this table instance. ``field_options`` Most tables are designed to take input from the user via table fields. The user fills in values for each table field and the set of input becomes the report *criteria*. Field options allow the report writer to customize the aspects of table fields such as the initial value of a form field or the list of choices in a drop-down selection field. """ name = slugify(unicode(name)) # process subclass assigned options table_options = copy.deepcopy(cls.TABLE_OPTIONS) field_options = copy.deepcopy(cls.FIELD_OPTIONS) if hasattr(cls, '_ANALYSIS_TABLE_OPTIONS'): table_options.update(cls._ANALYSIS_TABLE_OPTIONS) field_options.update(cls._ANALYSIS_FIELD_OPTIONS) keys = kwargs.keys() # The field_map mapping is stored in table_options for reference # later when building criteria for this table table_options['field_map'] = {} to = dict((k, kwargs.pop(k)) for k in keys if k in table_options) table_options.update(**to) fo = dict((k, kwargs.pop(k)) for k in keys if k in field_options) field_options.update(**fo) table_options = cls.process_options(table_options) if table_options: options = JsonDict(default=table_options) else: options = None # process normal model kwargs keys = kwargs.keys() tkeys = [f.name for f in Table._meta.local_fields] table_kwargs = dict((k, kwargs.pop(k)) for k in keys if k in tkeys) if kwargs: raise AttributeError('Invalid keyword arguments: %s' % str(kwargs)) # Table property '_query_class' may be either a string name # or an actual class reference. Convert to string name for storage queryclassname = cls._query_class if inspect.isclass(queryclassname): queryclassname = queryclassname.__name__ sourcefile = table_kwargs.get('sourcefile', get_sourcefile(get_module_name())) namespace = table_kwargs.get('namespace', get_namespace(sourcefile)) if len(Table.objects.filter(name=name, namespace=namespace, sourcefile=sourcefile)) > 0: msg = ("Table '%s' already exists in namespace '%s' " "(sourcefile '%s')") % (name, namespace, sourcefile) raise ValueError(msg) table_kwargs['namespace'] = namespace table_kwargs['sourcefile'] = sourcefile logger.debug('Creating table %s' % name) t = cls(name=name, module=cls.__module__, queryclassname=queryclassname, options=options, **table_kwargs) try: t.save() except DatabaseError as e: if 'no such table' in str(e): msg = str(e) + ' -- did you forget class Meta: proxy=True?' raise DatabaseError(msg) raise # post process table *instance* now that its been initialized t.post_process_table(field_options) # if field_map has been specified, go through attached fields and # change them accordingly for keyword, mapped in (t.options.field_map or {}).iteritems(): try: field = t.fields.get(keyword=keyword) if isinstance(mapped, basestring): field.keyword = mapped else: for k, v in mapped.iteritems(): if not hasattr(field, k): raise AttributeError( "Invalid attribute for field '%s': %s" % (field.keyword, k)) setattr(field, k, v) field.save() except ObjectDoesNotExist: raise AttributeError( 'field_map references invalid field: %s' % keyword) return t
def create(cls, name, **kwargs): """Create a table. :param str name: Unique identifier for this table Standard keyword arguments: :param int rows: set maximum number of rows to save after sorting (defaults to -1, no maximum) :param bool resample: if True, timeseries data returned by the data source will be resampled to ``criteria.resample_resolution`` or ``criteria.resolution`` :param dict field_map: a dictionary mapping fields by keyword to either a new keyword or to a map of field values to customize for the given field field_map = {'qos': 'qos_1'} or field_map = {'qos': { 'keyword': 'qos_1', 'label': 'QoS 1', 'default': 'AF' } } This is used to remap fields defined by standard tables to allow the same table to be used multiple times in the same report but with different criteria via different keywords. Additional table and field options keyword arguments may be provided that are unique to the specific data source table being instantiatied: ``table_options`` These options define subclass-specific options that allow customization of a table instance. Table options are *not* visible to users running reports via the UI. Option values are provided at table creation and are considered static for the life of this table instance. ``field_options`` Most tables are designed to take input from the user via table fields. The user fills in values for each table field and the set of input becomes the report *criteria*. Field options allow the report writer to customize the aspects of table fields such as the initial value of a form field or the list of choices in a drop-down selection field. """ name = slugify(unicode(name)) # process subclass assigned options table_options = copy.deepcopy(cls.TABLE_OPTIONS) field_options = copy.deepcopy(cls.FIELD_OPTIONS) if hasattr(cls, '_ANALYSIS_TABLE_OPTIONS'): table_options.update(cls._ANALYSIS_TABLE_OPTIONS) field_options.update(cls._ANALYSIS_FIELD_OPTIONS) keys = kwargs.keys() # The field_map mapping is stored in table_options for reference # later when building criteria for this table table_options['field_map'] = {} to = dict((k, kwargs.pop(k)) for k in keys if k in table_options) table_options.update(**to) fo = dict((k, kwargs.pop(k)) for k in keys if k in field_options) field_options.update(**fo) table_options = cls.process_options(table_options) if table_options: options = JsonDict(default=table_options) else: options = None # process normal model kwargs keys = kwargs.keys() tkeys = [f.name for f in Table._meta.local_fields] table_kwargs = dict((k, kwargs.pop(k)) for k in keys if k in tkeys) if kwargs: raise AttributeError('Invalid keyword arguments: %s' % str(kwargs)) # Table property '_query_class' may be either a string name # or an actual class reference. Convert to string name for storage queryclassname = cls._query_class if inspect.isclass(queryclassname): queryclassname = queryclassname.__name__ sourcefile = table_kwargs.get('sourcefile', get_sourcefile(get_module_name())) namespace = table_kwargs.get('namespace', get_namespace(sourcefile)) if len( Table.objects.filter(name=name, namespace=namespace, sourcefile=sourcefile)) > 0: msg = ("Table '%s' already exists in namespace '%s' " "(sourcefile '%s')") % (name, namespace, sourcefile) raise ValueError(msg) table_kwargs['namespace'] = namespace table_kwargs['sourcefile'] = sourcefile logger.debug('Creating table %s' % name) t = cls(name=name, module=cls.__module__, queryclassname=queryclassname, options=options, **table_kwargs) try: t.save() except DatabaseError as e: if 'no such table' in str(e): msg = str(e) + ' -- did you forget class Meta: proxy=True?' raise DatabaseError(msg) raise # post process table *instance* now that its been initialized t.post_process_table(field_options) # if field_map has been specified, go through attached fields and # change them accordingly for keyword, mapped in (t.options.field_map or {}).iteritems(): try: field = t.fields.get(keyword=keyword) if isinstance(mapped, basestring): field.keyword = mapped else: for k, v in mapped.iteritems(): if not hasattr(field, k): raise AttributeError( "Invalid attribute for field '%s': %s" % (field.keyword, k)) setattr(field, k, v) field.save() except ObjectDoesNotExist: raise AttributeError('field_map references invalid field: %s' % keyword) return t