Exemplo n.º 1
0
 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
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
    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