Esempio n. 1
0
def activate(admin=True, browser=True, name='admin', reflect_all=False):
    """Activate each pre-registered model or generate the model classes and
    (possibly) register them for the admin.

    :param bool admin: should we generate the admin interface?
    :param bool browser: should we open the browser for the user?
    :param name: name to use for blueprint created by the admin interface. Set
                 this to avoid naming conflicts with other blueprints (if
                 trying to use sandman to connect to multiple databases
                 simultaneously)

    """
    with app.app_context():
        generate_pks = app.config.get('SANDMAN_GENERATE_PKS', None) or False
        if getattr(app, 'class_references', None) is None or reflect_all:
            app.class_references = collections.OrderedDict()
            generate_endpoint_classes(db, generate_pks)
        else:
            Model.prepare(db.engine)
        prepare_relationships(db, current_app.class_references)
        if admin:
            try:
                show_pks = current_app.config['SANDMAN_SHOW_PKS']
            except KeyError:
                show_pks = False
            register_classes_for_admin(db.session, show_pks, name)
    if browser:
        port = app.config.get('SERVER_PORT', None) or 5000
        webbrowser.open('http://localhost:{}/admin'.format(port))
Esempio n. 2
0
def activate(admin=True, browser=True, name="admin", reflect_all=False):
    """Activate each pre-registered model or generate the model classes and
    (possibly) register them for the admin.

    :param bool admin: should we generate the admin interface?
    :param bool browser: should we open the browser for the user?
    :param name: name to use for blueprint created by the admin interface. Set
                 this to avoid naming conflicts with other blueprints (if trying
                 to use sandman to connect to multiple databases simultaneously)

    """
    with app.app_context():
        generate_pks = app.config.get("SANDMAN_GENERATE_PKS", None) or False
        if getattr(app, "class_references", None) is None or reflect_all:
            app.class_references = collections.OrderedDict()
            generate_endpoint_classes(db, generate_pks)
        else:
            Model.prepare(db.engine)
        prepare_relationships(db, current_app.class_references)
        if admin:
            try:
                show_pks = current_app.config["SANDMAN_SHOW_PKS"]
            except KeyError:
                show_pks = False
            register_classes_for_admin(db.session, show_pks, name)
    if browser:
        port = app.config.get("SERVER_PORT", None) or 5000
        webbrowser.open("http://localhost:{}/admin".format(port))
Esempio n. 3
0
def register_classes_for_admin(db_session, show_pks=True, name='admin'):
    """Registers classes for the Admin view that ultimately creates the admin
    interface.

    :param db_session: handle to database session
    :param list classes: list of classes to register with the admin
    :param bool show_pks: show primary key columns in the admin?

    """

    with app.app_context():
        admin_view = Admin(current_app, name=name)
        for cls in set(
            cls for cls in current_app.class_references.values() if
                cls.use_admin):
            column_list = [column.name for column in
                           cls.__table__.columns.values()]
            if hasattr(cls, '__view__'):
                # allow ability for model classes to specify model views
                admin_view_class = type(
                    'AdminView',
                    (cls.__view__,),
                    {'form_columns': column_list})
            elif show_pks:
                # the default of Flask-SQLAlchemy is to not show primary
                # classes, which obviously isn't acceptable in some cases
                admin_view_class = type(
                    'AdminView',
                    (AdminModelViewWithPK,),
                    {'form_columns': column_list})
            else:
                admin_view_class = ModelView
            admin_view.add_view(admin_view_class(cls, db_session))
Esempio n. 4
0
def register_classes_for_admin(db_session, show_pks=True, name='admin'):
    """Registers classes for the Admin view that ultimately creates the admin
    interface.

    :param db_session: handle to database session
    :param list classes: list of classes to register with the admin
    :param bool show_pks: show primary key columns in the admin?

    """

    with app.app_context():
        admin_view = Admin(current_app, name=name)
        for cls in set(cls for cls in current_app.class_references.values()
                       if cls.use_admin):
            column_list = [
                column.name for column in cls.__table__.columns.values()
            ]
            if hasattr(cls, '__view__'):
                # allow ability for model classes to specify model views
                admin_view_class = type('AdminView', (cls.__view__, ),
                                        {'form_columns': column_list})
            elif show_pks:
                # the default of Flask-SQLAlchemy is to not show primary
                # classes, which obviously isn't acceptable in some cases
                admin_view_class = type('AdminView', (AdminModelViewWithPK, ),
                                        {'form_columns': column_list})
            else:
                admin_view_class = ModelView
            admin_view.add_view(admin_view_class(cls, db_session))
Esempio n. 5
0
    def as_dict(self, depth=0):
        """Return a dictionary containing only the attributes which map to
        an instance's database columns.

        :param int depth: Maximum depth to recurse subobjects
        :rtype: dict

        """
        result_dict = {}
        for column in self.__table__.columns.keys():
            result_dict[column] = getattr(self, column, None)
            if isinstance(result_dict[column], Decimal):
                result_dict[column] = str(result_dict[column])
        result_dict["links"] = self.links()
        for foreign_key in self.__table__.foreign_keys:
            column_name = foreign_key.column.name
            column_value = getattr(self, column_name, None)
            if column_value:
                table = foreign_key.column.table.name
                with app.app_context():
                    endpoint = current_app.class_references[table]
                    session = db.session()
                    resource = session.query(endpoint).get(column_value)
                if depth > 0:
                    result_dict.update(
                        {"rel": endpoint.__name__, endpoint.__name__.lower(): resource.as_dict(depth - 1)}
                    )
                else:
                    result_dict[endpoint.__name__.lower() + "_url"] = "/{}/{}".format(endpoint.__name__, column_value)

        result_dict["self"] = self.resource_uri()
        return result_dict
Esempio n. 6
0
    def as_dict(self, depth=0):
        """Return a dictionary containing only the attributes which map to
        an instance's database columns.

        :rtype: dict

        """
        result_dict = {}
        for column in self.__table__.columns.keys():
            result_dict[column] = getattr(self, column, None)
            if isinstance(result_dict[column], Decimal):
                result_dict[column] = str(result_dict[column])
        result_dict['links'] = self.links()
        for foreign_key in self.__table__.foreign_keys:
            column_name = foreign_key.column.name
            column_value = getattr(self, column_name, None)
            if column_value:
                table = foreign_key.column.table.name
                with app.app_context():
                    endpoint = current_app.class_references[table]
                    session = db.session()
                    resource = session.query(endpoint).get(column_value)
                if depth > 0:
                    result_dict.update({
                        'rel': endpoint.__name__, 
                        endpoint.__name__.lower() : resource.as_dict(depth - 1)
                        })
                else:
                    result_dict[endpoint.__name__.lower() + '_url'] = '/{}/{}'.format(endpoint.__name__, column_value)

        result_dict['self'] = self.resource_uri()
        return result_dict
Esempio n. 7
0
    def as_dict(self, depth=0, cols_to_remove=None):
        """Return a dictionary containing only the attributes which map to
        an instance's database columns.

        :rtype: dict

        """
        result_dict = {}
        if cols_to_remove is not None:
            self.__table__.columns = {k:v for k,v in dict(self.__table__.columns).iteritems() if k not in cols_to_remove}
        for column in self.__table__.columns.keys():
            result_dict[column] = getattr(self, column, None)
            if isinstance(result_dict[column], Decimal):
                result_dict[column] = str(result_dict[column])
        result_dict['links'] = self.links()
        for foreign_key in self.__table__.foreign_keys:
            column_name = foreign_key.column.name
            column_value = getattr(self, column_name, None)
            if column_value:
                table = foreign_key.column.table.name
                with app.app_context():
                    endpoint = current_app.class_references[table]
                    session = db.session()
                    resource = session.query(endpoint).get(column_value)
                if depth > 0:
                    result_dict.update({
                        'rel': endpoint.__name__, 
                        endpoint.__name__.lower() : resource.as_dict(depth - 1)
                        })
                else:
                    result_dict[endpoint.__name__.lower() + '_url'] = '/{}/{}'.format(endpoint.__name__, column_value)

        result_dict['self'] = self.resource_uri()
        return result_dict
Esempio n. 8
0
 def links(self):
     """Return a list of links for endpoints related to the resource."""
     links = []
     for foreign_key in self.__table__.foreign_keys:
         column = foreign_key.column.name
         table = foreign_key.column.table.name
         with app.app_context():
             endpoint = current_app.table_to_endpoint[table]
         links.append({'rel': endpoint, 'uri': '/{}/{}'.format(endpoint, getattr(self, column))})
     links.append({'rel': 'self', 'uri': self.resource_uri()})
     return links
Esempio n. 9
0
def register_internal_data(cls):
    """Register a new class, *cls*, with various internal data structures.

    :params `sandman.model.Model` cls: class to register

    """
    with app.app_context():
        current_app.class_references[cls.__tablename__] = cls
        current_app.class_references[cls.__name__] = cls
        current_app.class_references[cls.endpoint()] = cls
        if not getattr(cls, '__related_tables__', None):
            cls.__related_tables__ = set()
Esempio n. 10
0
def register_internal_data(cls):
    """Register a new class, *cls*, with various internal data structures.

    :params `sandman.model.Model` cls: class to register

    """
    with app.app_context():
        current_app.class_references[cls.__tablename__] = cls
        current_app.class_references[cls.__name__] = cls
        current_app.class_references[cls.endpoint()] = cls
        if not getattr(cls, "__related_tables__", None):
            cls.__related_tables__ = set()
Esempio n. 11
0
 def links(self):
     """Return a list of links for endpoints related to the resource."""
     links = []
     for foreign_key in self.__table__.foreign_keys:
         column = foreign_key.column.name
         column_value = getattr(self, column, None)
         if column_value:
             table = foreign_key.column.table.name
             with app.app_context():
                 endpoint = current_app.table_to_endpoint[table]
             links.append({'rel': endpoint, 'uri': '/{}/{}'.format(endpoint, column_value)})
     links.append({'rel': 'self', 'uri': self.resource_uri()})
     return links
Esempio n. 12
0
 def links(self):
     """Return a list of links for endpoints related to the resource."""
     links = []
     for foreign_key in self.__table__.foreign_keys:
         column = foreign_key.column.name
         column_value = getattr(self, column, None)
         if column_value:
             table = foreign_key.column.table.name
             with app.app_context():
                 endpoint = current_app.class_references[table]
             links.append({'rel': 'related', 'uri': '/{}/{}'.format(
                 endpoint.__name__, column_value)})
     links.append({'rel': 'self', 'uri': self.resource_uri()})
     return links
Esempio n. 13
0
def register_internal_data(cls):
    """Register a new class, *cls*, with various internal data structures.

    :params `sandman.model.Model` cls: class to register

    """
    with app.app_context():
        if getattr(cls, 'endpoint', None) is None:
            orig_class = cls
            cls = type('Sandman' + cls.__name__, (cls, Model), {})
            cls.__from_class__ = orig_class
        current_app.class_references[cls.__tablename__] = cls
        current_app.class_references[cls.__name__] = cls
        current_app.class_references[cls.endpoint()] = cls
        if not getattr(cls, '__related_tables__', None):
            cls.__related_tables__ = set()
Esempio n. 14
0
def register_internal_data(cls):
    """Register a new class, *cls*, with various internal data structures.

    :params `sandman.model.Model` cls: class to register

    """
    with app.app_context():
        if getattr(cls, 'endpoint', None) is None:
            orig_class = cls
            cls = type('Sandman' + cls.__name__, (cls, Model), {})
            cls.__from_class__ = orig_class
        current_app.class_references[cls.__tablename__] = cls
        current_app.class_references[cls.__name__] = cls
        current_app.class_references[cls.endpoint()] = cls
        if not getattr(cls, '__related_tables__', None):
            cls.__related_tables__ = set()
Esempio n. 15
0
def generate_endpoint_classes(db, generate_pks=False):
    """Return a list of model classes generated for each reflected database
    table."""
    seen_classes = set()
    for cls in current_app.class_references.values():
        seen_classes.add(cls.__tablename__)
    with app.app_context():
        db.metadata.reflect(bind=db.engine)
        for name, table in db.metadata.tables.items():
            if not name in seen_classes:
                seen_classes.add(name)
                if not table.primary_key and generate_pks:
                    cls = add_pk_if_required(db, table, name)
                else:
                    cls = type(str(name), (sandman_model, db.Model), {"__tablename__": name})
                register(cls)
Esempio n. 16
0
def generate_endpoint_classes(db, generate_pks=False):
    """Return a list of model classes generated for each reflected database
    table."""
    seen_classes = set()
    for cls in current_app.class_references.values():
        seen_classes.add(cls.__tablename__)
    with app.app_context():
        db.metadata.reflect(bind=db.engine)
        for name, table in db.metadata.tables.items():
            if not name in seen_classes:
                seen_classes.add(name)
                if not table.primary_key and generate_pks:
                    cls = add_pk_if_required(db, table, name)
                else:
                    cls = type(str(name), (sandman_model, db.Model),
                               {'__tablename__': name})
                register(cls)
Esempio n. 17
0
def register(cls, use_admin=True):
    """Register with the API a :class:`sandman.model.Model` class and associated
    endpoint.

    :param cls: User-defined class derived from :class:`sandman.model.Model` to
                be registered with the endpoint returned by :func:`endpoint()`
    :type cls: :class:`sandman.model.Model` or tuple

    """
    with app.app_context():
        if getattr(current_app, "class_references", None) is None:
            current_app.class_references = {}
        if isinstance(cls, (list, tuple)):
            for entry in cls:
                register_internal_data(entry)
                entry.use_admin = use_admin
        else:
            register_internal_data(cls)
            cls.use_admin = use_admin
Esempio n. 18
0
def register(cls, use_admin=True):
    """Register with the API a :class:`sandman.model.Model` class and
    associated endpoint.

    :param cls: User-defined class derived from :class:`sandman.model.Model` to
                be registered with the endpoint returned by :func:`endpoint()`
    :type cls: :class:`sandman.model.Model` or tuple

    """
    with app.app_context():
        if getattr(current_app, 'class_references', None) is None:
            current_app.class_references = {}
        if isinstance(cls, (list, tuple)):
            for entry in cls:
                register_internal_data(entry)
                entry.use_admin = use_admin
        else:
            register_internal_data(cls)
            cls.use_admin = use_admin