Beispiel #1
0
class FinalPage(ProgressPage):
    """FinalPage is the final page in the import process"""

    title = ugettext_lazy('Import Progress')
    sub_title = ugettext_lazy('Please wait while data is being imported.')

    def __init__(self, parent=None, model=None, admin=None):
        """
        :model: the source model from which to import data
        :admin: the admin class of the target data
        """
        super(FinalPage, self).__init__(parent)
        self.model = model
        self.admin = admin
        icon = 'tango/32x32/mimetypes/x-office-spreadsheet.png'
        self.setPixmap(QtGui.QWizard.LogoPixmap, Pixmap(icon).getQPixmap())
        self.setButtonText(QtGui.QWizard.FinishButton, _('Close'))
        self.progressbar = QtGui.QProgressBar()

    def run(self):
        collection = self.model.get_collection()
        self.update_maximum_signal.emit(len(collection))
        for i, row in enumerate(collection):
            new_entity_instance = self.admin.entity()
            for field_name, attributes in self.model.get_admin().get_columns():
                try:
                    from_string = attributes['from_string']
                except KeyError:
                    logger.warn(
                        'field %s has no from_string field attribute, dont know how to import it properly'
                        % attributes['original_field'])
                    from_string = lambda _a: None
                setattr(new_entity_instance, attributes['original_field'],
                        from_string(getattr(row, field_name)))
            self.admin.add(new_entity_instance)
            self.admin.flush(new_entity_instance)
            self.update_progress_signal.emit(
                i,
                _('Row %i of %i imported') % (i + 1, len(collection)))
Beispiel #2
0
    def get_field_attributes(self, field_name):
        """
        Get the attributes needed to visualize the field field_name.  This
        function is called by get_static_field_attributes and
        get_dynamic_field_attributes.

        This function first tries to fill the dictionary with field
        attributes for a field with those gathered through introspection,
        and then updates them with those found in the field_attributes
        class attribute.

        :param field_name: the name of the field
        :return: a dictionary of attributes needed to visualize the field

        The values of the returned dictionary either contain the value
        of the field attribute, or in the case of dynamic field attributes,
        a function that returns the value of the field attribute.
        """
        #
        # @todo : this function should return a frozen dictionary, so no
        #         other parts of the application can modify the cached field
        #         attributes
        #
        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(
                getter=create_default_getter(field_name),
                to_string = to_string,
                field_name=field_name,
                python_type=str,
                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

            #
            # TODO : move part of logic from entity admin class over here
            #

            #
            # Overrule introspected field_attributes with those defined
            #
            attributes.update(forced_attributes)

            #
            # In case of a 'target' field attribute, instantiate an appropriate
            # 'admin' attribute
            #

            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_admin(target)

            if 'target' in attributes:
                attributes['admin'] = get_entity_admin(attributes['target'])

            self._field_attributes[field_name] = attributes
            return attributes
Beispiel #3
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
            from sqlalchemy.exc import InvalidRequestError

            try:
                property = self.mapper.get_property(
                    field_name
                )
                if isinstance(property, orm.properties.ColumnProperty):
                    columns = property.columns
                    sql_attributes = self.get_sql_field_attributes( columns )
                    attributes.update( sql_attributes ) 
                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
Beispiel #4
0
    def get_field_attributes(self, field_name):
        """
        Get the attributes needed to visualize the field field_name.  This
        function is called by get_static_field_attributes and
        get_dynamic_field_attributes.

        This function first tries to fill the dictionary with field
        attributes for a field with those gathered through introspection,
        and then updates them with those found in the field_attributes
        class attribute.

        :param field_name: the name of the field
        :return: a dictionary of attributes needed to visualize the field

        The values of the returned dictionary either contain the value
        of the field attribute, or in the case of dynamic field attributes,
        a function that returns the value of the field attribute.
        """
        #
        # @todo : this function should return a frozen dictionary, so no
        #         other parts of the application can modify the cached field
        #         attributes
        #
        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(
                getter=create_default_getter(field_name),
                to_string = to_string,
                field_name=field_name,
                python_type=str,
                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

            #
            # TODO : move part of logic from entity admin class over here
            #

            #
            # Overrule introspected field_attributes with those defined
            #
            attributes.update(forced_attributes)

            #
            # In case of a 'target' field attribute, instantiate an appropriate
            # 'admin' attribute
            #

            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_admin(target)

            if 'target' in attributes:
                attributes['admin'] = get_entity_admin(attributes['target'])

            self._field_attributes[field_name] = attributes
            return attributes
Beispiel #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
         * ...
        """
        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
            from sqlalchemy.exc import InvalidRequestError

            try:
                property = self.mapper.get_property(field_name)
                if isinstance(property, orm.properties.ColumnProperty):
                    columns = property.columns
                    sql_attributes = self.get_sql_field_attributes(columns)
                    attributes.update(sql_attributes)
                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
Beispiel #6
0
    def get_field_attributes(self, field_name):
        """
        Get the attributes needed to visualize the field field_name.  This
        function is called by get_static_field_attributes and
        get_dynamic_field_attributes.

        This function first tries to fill the dictionary with field
        attributes for a field with those gathered through introspection,
        and then updates them with those found in the field_attributes
        class attribute.

        :param field_name: the name of the field
        :return: a dictionary of attributes needed to visualize the field

        The values of the returned dictionary either contain the value
        of the field attribute, or in the case of dynamic field attributes,
        a function that returns the value of the field attribute.
        """
        #
        # @todo : this function should return a frozen dictionary, so no
        #         other parts of the application can modify the cached field
        #         attributes
        #
        try:
            return self._field_attributes[field_name]
        except KeyError:
            from camelot.view.controls import delegates
            #
            # Default attributes for all fields
            #
            attributes = dict(to_string=to_string,
                              field_name=field_name,
                              python_type=str,
                              length=None,
                              tooltip=None,
                              background_color=None,
                              editable=False,
                              nullable=True,
                              widget='str',
                              blank=True,
                              delegate=delegates.PlainTextDelegate,
                              validator_list=[],
                              name=ugettext_lazy(
                                  field_name.replace('_', ' ').capitalize()))
            descriptor_attributes = self.get_descriptor_field_attributes(
                field_name)
            attributes.update(descriptor_attributes)
            #
            # first put the attributes in the cache, and only then start to expand
            # them, to be able to prevent recursion when expanding the attributes
            #
            self._field_attributes[field_name] = attributes
            forced_attributes = self.field_attributes.get(field_name, {})
            attributes.update(forced_attributes)
            if 'choices' in forced_attributes:
                from camelot.view.controls import delegates
                attributes['delegate'] = delegates.ComboBoxDelegate
                if isinstance(forced_attributes['choices'], list):
                    choices_dict = dict(forced_attributes['choices'])
                    attributes['to_string'] = lambda x: choices_dict.get(x, '')
            self._expand_field_attributes(attributes, field_name)
            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
Beispiel #8
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