def get_sql_field_attributes( cls, columns ): """Returns a set of default field attributes based on introspection of the SQLAlchemy columns that form a field :param: columns a list of :class:`sqlalchemy.schema.Column` objects. :return: a dictionary with field attributes By default this method looks at the first column that defines the field and derives a delegate and other field attributes that make sense. """ from camelot.view.field_attributes import _sqlalchemy_to_python_type_ sql_attributes = dict() for column in columns: column_type = column.type for base_class in inspect.getmro( type( column_type ) ): fa = _sqlalchemy_to_python_type_.get( base_class, None ) if fa != None: sql_attributes.update( fa( column_type ) ) break if isinstance( column, (schema.Column) ): sql_attributes['nullable'] = column.nullable sql_attributes['default'] = column.default if column.primary_key: sql_attributes['editable'] = False break return sql_attributes
def get_sql_field_attributes(cls, columns): """Returns a set of default field attributes based on introspection of the SQLAlchemy columns that form a field :param: columns a list of :class:`sqlalchemy.schema.Column` objects. :return: a dictionary with field attributes By default this method looks at the first column that defines the field and derives a delegate and other field attributes that make sense. """ from camelot.view.field_attributes import _sqlalchemy_to_python_type_ sql_attributes = dict() for column in columns: column_type = column.type for base_class in inspect.getmro(type(column_type)): fa = _sqlalchemy_to_python_type_.get(base_class, None) if fa != None: sql_attributes.update(fa(column_type)) break if isinstance(column, (schema.Column)): sql_attributes['nullable'] = column.nullable sql_attributes['default'] = column.default if column.primary_key: sql_attributes['editable'] = False break return sql_attributes
def get_sql_field_attributes(cls, columns): """Returns a set of default field attributes based on introspection of the SQLAlchemy columns that form a field :param: columns a list of :class:`sqlalchemy:sqlalchemy.schema.Column` objects. :return: a dictionary with field attributes By default this method looks at the first column that defines the field and derives a delegate and other field attributes that make sense. """ from camelot.view.field_attributes import _sqlalchemy_to_python_type_ sql_attributes = dict() for column in columns: column_type = column.type sql_attributes['python_type'] = '' sql_attributes['doc'] = '' # PrimaryKey is not in _sqlalchemy_to_python_type_, but its # implementation class probably is if isinstance(column_type, PrimaryKey): column_type = column_type.load_dialect_impl(None) for base_class in inspect.getmro(type(column_type)): fa = _sqlalchemy_to_python_type_.get(base_class, None) if fa is not None: sql_attributes.update(fa(column_type)) break if isinstance(column, (schema.Column)): sql_attributes['nullable'] = column.nullable sql_attributes['default'] = column.default sql_attributes['doc'] = column.doc or '' editable = (column.primary_key is False) # if these fields are editable, they are validated when a form # is closed, while at that time the field is not yet filled # because the foreign key column is only filled after the flush if len(column.foreign_keys): editable = False sql_attributes['editable'] = editable field_admin = getattr(column, '_field_admin', None) if field_admin != None: sql_attributes.update(field_admin.get_field_attributes()) break return sql_attributes
def get_field_attributes(self, field_name): """Get the attributes needed to visualize the field field_name :param field_name: the name of the field :return: a dictionary of attributes needed to visualize the field, those attributes can be: * python_type : the corresponding python type of the object * editable : bool specifying wether the user can edit this field * widget : which widget to be used to render the field * ... """ from sqlalchemy.orm.mapper import _mapper_registry try: return self._field_attributes[field_name] except KeyError: def create_default_getter(field_name): return lambda o:getattr(o, field_name) from camelot.view.controls import delegates # # Default attributes for all fields # attributes = dict( python_type = str, to_string = to_string, field_name = field_name, getter = create_default_getter(field_name), length = None, tooltip = None, background_color = None, #minimal_column_width = 12, editable = False, nullable = True, widget = 'str', blank = True, delegate = delegates.PlainTextDelegate, validator_list = [], name = ugettext_lazy(field_name.replace('_', ' ').capitalize()) ) # # Field attributes forced by the field_attributes property # forced_attributes = {} try: forced_attributes = self.field_attributes[field_name] except KeyError: pass def resolve_target(target): """A class or name of the class representing the other side of a relation. Use the name of the class to avoid circular dependencies""" if isinstance(target, basestring): for mapped_class in _mapper_registry.keys(): if mapped_class.class_.__name__ == target: return mapped_class.class_ raise Exception('No mapped class found for target %s'%target) return target def get_entity_admin(target): """Helper function that instantiated an Admin object for a target entity class. :param target: an entity class for which an Admin object is needed """ try: admin_class = forced_attributes['admin'] return admin_class(self.app_admin, target) except KeyError: return self.get_related_admin(target) # # Get the default field_attributes trough introspection if the # field is a mapped field # from sqlalchemy import orm, schema from sqlalchemy.exc import InvalidRequestError from camelot.view.field_attributes import _sqlalchemy_to_python_type_ try: property = self.mapper.get_property( field_name ) if isinstance(property, orm.properties.ColumnProperty): column_type = property.columns[0].type python_type = _sqlalchemy_to_python_type_.get( column_type.__class__, None ) if python_type: attributes.update(python_type(column_type)) if isinstance( property.columns[0], (schema.Column) ): attributes['nullable'] = property.columns[0].nullable attributes['default'] = property.columns[0].default elif isinstance(property, orm.properties.PropertyLoader): target = forced_attributes.get( 'target', property.mapper.class_ ) # # _foreign_keys is for sqla pre 0.6.4 # if hasattr(property, '_foreign_keys'): foreign_keys = list(property._foreign_keys) else: foreign_keys = list( property._user_defined_foreign_keys ) foreign_keys.extend( list(property._calculated_foreign_keys) ) if property.direction == orm.interfaces.ONETOMANY: attributes.update( python_type = list, editable = True, nullable = True, delegate = delegates.One2ManyDelegate, target = target, create_inline = False, direction = 'onetomany', admin = get_entity_admin(target) ) elif property.direction == orm.interfaces.MANYTOONE: attributes.update( python_type = str, editable = True, delegate = delegates.Many2OneDelegate, target = target, # # @todo: take into account all foreign keys instead # of only the first one # nullable = foreign_keys[0].nullable, direction = 'manytoone', admin = get_entity_admin(target) ) elif property.direction == orm.interfaces.MANYTOMANY: attributes.update( python_type = list, editable = True, target = target, nullable = True, create_inline = False, direction = 'manytomany', delegate = delegates.One2ManyDelegate, admin = get_entity_admin(target) ) else: raise Exception('PropertyLoader has unknown direction') except InvalidRequestError: # # If the field name is not a property of the mapper, then use # the default stuff # pass if 'choices' in forced_attributes: attributes['delegate'] = delegates.ComboBoxDelegate attributes['editable'] = True if isinstance(forced_attributes['choices'], list): choices_dict = dict(forced_attributes['choices']) attributes['to_string'] = lambda x : choices_dict[x] # # Overrule introspected field_attributes with those defined # attributes.update(forced_attributes) # # In case of a 'target' field attribute, instantiate an appropriate # 'admin' attribute # if 'target' in attributes: attributes['target'] = resolve_target(attributes['target']) attributes['admin'] = get_entity_admin(attributes['target']) self._field_attributes[field_name] = attributes return attributes
def get_field_attributes(self, field_name): """Get the attributes needed to visualize the field field_name :param field_name: the name of the field :return: a dictionary of attributes needed to visualize the field, those attributes can be: * python_type : the corresponding python type of the object * editable : bool specifying wether the user can edit this field * widget : which widget to be used to render the field * ... """ try: return self._field_attributes[field_name] except KeyError: def create_default_getter(field_name): return lambda o: getattr(o, field_name) from camelot.view.controls import delegates # # Default attributes for all fields # attributes = dict(python_type=str, field_name=field_name, getter=create_default_getter(field_name), length=None, tooltip=None, background_color=None, minimal_column_width=12, editable=False, nullable=True, widget='str', blank=True, delegate=delegates.PlainTextDelegate, validator_list=[], name=ugettext_lazy( field_name.replace('_', ' ').capitalize())) # # Field attributes forced by the field_attributes property # forced_attributes = {} try: forced_attributes = self.field_attributes[field_name] except KeyError: pass def get_entity_admin(target): """Helper function that instantiated an Admin object for a target entity class. :param target: an entity class for which an Admin object is needed. """ try: fa = self.field_attributes[field_name] target = fa.get('target', target) admin_class = fa['admin'] return admin_class(self.app_admin, target) except KeyError: return self.get_related_entity_admin(target) # # Get the default field_attributes trough introspection if the # field is a mapped field # from sqlalchemy import orm from sqlalchemy.exceptions import InvalidRequestError from camelot.view.field_attributes import _sqlalchemy_to_python_type_ try: property = self.mapper.get_property(field_name, resolve_synonyms=True) if isinstance(property, orm.properties.ColumnProperty): column_type = property.columns[0].type python_type = _sqlalchemy_to_python_type_.get( column_type.__class__, None) if python_type: attributes.update(python_type(column_type)) if not isinstance( property.columns[0], (sqlalchemy.sql.expression._Label, sqlalchemy.sql.expression.ColumnClause)): attributes['nullable'] = property.columns[0].nullable attributes['default'] = property.columns[0].default elif isinstance(property, orm.properties.PropertyLoader): target = property._get_target().class_ # # _foreign_keys is for sqla pre 0.6.4 # if hasattr(property, '_foreign_keys'): foreign_keys = list(property._foreign_keys) else: foreign_keys = list( property._user_defined_foreign_keys) foreign_keys.extend( list(property._calculated_foreign_keys)) if property.direction == orm.interfaces.ONETOMANY: attributes.update(python_type=list, editable=True, nullable=True, delegate=delegates.One2ManyDelegate, target=target, create_inline=False, direction=property.direction, admin=get_entity_admin(target)) elif property.direction == orm.interfaces.MANYTOONE: attributes.update( python_type=str, editable=True, delegate=delegates.Many2OneDelegate, target=target, # # @todo: take into account all foreign keys instead # of only the first one # nullable=foreign_keys[0].nullable, direction=property.direction, admin=get_entity_admin(target)) elif property.direction == orm.interfaces.MANYTOMANY: attributes.update( python_type=list, editable=True, target=target, nullable=True, create_inline=False, direction=property.direction, delegate=delegates.ManyToManyDelegate, admin=get_entity_admin(target)) else: raise Exception('PropertyLoader has unknown direction') except InvalidRequestError: # # If the field name is not a property of the mapper, then use # the default stuff # pass if 'choices' in forced_attributes: attributes['delegate'] = delegates.ComboBoxDelegate attributes['editable'] = True # # Overrule introspected field_attributes with those defined # attributes.update(forced_attributes) # # In case of a 'target' field attribute, instantiate an appropriate # 'admin' attribute # if 'target' in attributes: attributes['admin'] = get_entity_admin(attributes['target']) self._field_attributes[field_name] = attributes return attributes
def get_field_attributes(self, field_name): """Get the attributes needed to visualize the field field_name :param field_name: the name of the field :return: a dictionary of attributes needed to visualize the field, those attributes can be: * python_type : the corresponding python type of the object * editable : bool specifying wether the user can edit this field * widget : which widget to be used to render the field * ... """ try: return self._field_attributes[field_name] except KeyError: def create_default_getter(field_name): return lambda o: getattr(o, field_name) from camelot.view.controls import delegates # # Default attributes for all fields # attributes = dict( python_type=str, field_name=field_name, getter=create_default_getter(field_name), length=None, tooltip=None, background_color=None, minimal_column_width=12, editable=False, nullable=True, widget="str", blank=True, delegate=delegates.PlainTextDelegate, validator_list=[], name=ugettext_lazy(field_name.replace("_", " ").capitalize()), ) # # Field attributes forced by the field_attributes property # forced_attributes = {} try: forced_attributes = self.field_attributes[field_name] except KeyError: pass def get_entity_admin(target): """Helper function that instantiated an Admin object for a target entity class. :param target: an entity class for which an Admin object is needed. """ try: fa = self.field_attributes[field_name] target = fa.get("target", target) admin_class = fa["admin"] return admin_class(self.app_admin, target) except KeyError: return self.get_related_entity_admin(target) # # Get the default field_attributes trough introspection if the # field is a mapped field # from sqlalchemy import orm from sqlalchemy.exceptions import InvalidRequestError from camelot.view.field_attributes import _sqlalchemy_to_python_type_ try: property = self.mapper.get_property(field_name, resolve_synonyms=True) if isinstance(property, orm.properties.ColumnProperty): column_type = property.columns[0].type python_type = _sqlalchemy_to_python_type_.get(column_type.__class__, None) if python_type: attributes.update(python_type(column_type)) if not isinstance( property.columns[0], (sqlalchemy.sql.expression._Label, sqlalchemy.sql.expression.ColumnClause) ): attributes["nullable"] = property.columns[0].nullable attributes["default"] = property.columns[0].default elif isinstance(property, orm.properties.PropertyLoader): target = property._get_target().class_ # # _foreign_keys is for sqla pre 0.6.4 # if hasattr(property, "_foreign_keys"): foreign_keys = list(property._foreign_keys) else: foreign_keys = list(property._user_defined_foreign_keys) foreign_keys.extend(list(property._calculated_foreign_keys)) if property.direction == orm.interfaces.ONETOMANY: attributes.update( python_type=list, editable=True, nullable=True, delegate=delegates.One2ManyDelegate, target=target, create_inline=False, direction=property.direction, admin=get_entity_admin(target), ) elif property.direction == orm.interfaces.MANYTOONE: attributes.update( python_type=str, editable=True, delegate=delegates.Many2OneDelegate, target=target, # # @todo: take into account all foreign keys instead # of only the first one # nullable=foreign_keys[0].nullable, direction=property.direction, admin=get_entity_admin(target), ) elif property.direction == orm.interfaces.MANYTOMANY: attributes.update( python_type=list, editable=True, target=target, nullable=True, create_inline=False, direction=property.direction, delegate=delegates.ManyToManyDelegate, admin=get_entity_admin(target), ) else: raise Exception("PropertyLoader has unknown direction") except InvalidRequestError: # # If the field name is not a property of the mapper, then use # the default stuff # pass if "choices" in forced_attributes: attributes["delegate"] = delegates.ComboBoxDelegate attributes["editable"] = True # # Overrule introspected field_attributes with those defined # attributes.update(forced_attributes) # # In case of a 'target' field attribute, instantiate an appropriate # 'admin' attribute # if "target" in attributes: attributes["admin"] = get_entity_admin(attributes["target"]) self._field_attributes[field_name] = attributes return attributes