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