class DataBaseService(Service): """Manage all services""" def __init__(self, env, host, port, user, passwd, db): super(DataBaseService, self).__init__(env) self._db_proxy = Proxy() self._conn_info = dict(host=host, port=port, \ user=user, passwd=passwd, \ db=db) def on_active(self): super(DataBaseService, self).on_active() conn_info = self._conn_info.copy() db_name = conn_info.pop('db') database = PooledMySQLDatabaseWithReconnection( db_name, max_connections=DB_CONNECTION_MAX_NUM, stale_timeout=300, threadlocals=True, **conn_info ) self._db_proxy.initialize( database ) self._db_proxy.connect() def get_db(self): return self._db_proxy
class FlaskDB(object): """ Convenience wrapper for configuring a Peewee database for use with a Flask application. Provides a base `Model` class and registers handlers to manage the database connection during the request/response cycle. Usage:: from flask import Flask from peewee import * from playhouse.flask_utils import FlaskDB # The database can be specified using a database URL, or you can pass a # Peewee database instance directly: DATABASE = 'postgresql:///my_app' DATABASE = PostgresqlDatabase('my_app') # If we do not want connection-management on any views, we can specify # the view names using FLASKDB_EXCLUDED_ROUTES. The db connection will # not be opened/closed automatically when these views are requested: FLASKDB_EXCLUDED_ROUTES = ('logout',) app = Flask(__name__) app.config.from_object(__name__) # Now we can configure our FlaskDB: flask_db = FlaskDB(app) # Or use the "deferred initialization" pattern: flask_db = FlaskDB() flask_db.init_app(app) # The `flask_db` provides a base Model-class for easily binding models # to the configured database: class User(flask_db.Model): email = CharField() """ def __init__(self, app=None, database=None, model_class=Model, excluded_routes=None): self.database = None # Reference to actual Peewee database instance. self.base_model_class = model_class self._app = app self._db = database # dict, url, Database, or None (default). self._excluded_routes = excluded_routes or () if app is not None: self.init_app(app) def init_app(self, app): self._app = app if self._db is None: if 'DATABASE' in app.config: initial_db = app.config['DATABASE'] elif 'DATABASE_URL' in app.config: initial_db = app.config['DATABASE_URL'] else: raise ValueError('Missing required configuration data for ' 'database: DATABASE or DATABASE_URL.') else: initial_db = self._db if 'FLASKDB_EXCLUDED_ROUTES' in app.config: self._excluded_routes = app.config['FLASKDB_EXCLUDED_ROUTES'] self._load_database(app, initial_db) self._register_handlers(app) def _load_database(self, app, config_value): if isinstance(config_value, Database): database = config_value elif isinstance(config_value, dict): database = self._load_from_config_dict(dict(config_value)) else: # Assume a database connection URL. database = db_url_connect(config_value) if isinstance(self.database, Proxy): self.database.initialize(database) else: self.database = database def _load_from_config_dict(self, config_dict): try: name = config_dict.pop('name') engine = config_dict.pop('engine') except KeyError: raise RuntimeError('DATABASE configuration must specify a ' '`name` and `engine`.') if '.' in engine: path, class_name = engine.rsplit('.', 1) else: path, class_name = 'peewee', engine try: __import__(path) module = sys.modules[path] database_class = getattr(module, class_name) assert issubclass(database_class, Database) except ImportError: raise RuntimeError('Unable to import %s' % engine) except AttributeError: raise RuntimeError('Database engine not found %s' % engine) except AssertionError: raise RuntimeError('Database engine not a subclass of ' 'peewee.Database: %s' % engine) return database_class(name, **config_dict) def _register_handlers(self, app): app.before_request(self.connect_db) app.teardown_request(self.close_db) def get_model_class(self): if self.database is None: raise RuntimeError('Database must be initialized.') class BaseModel(self.base_model_class): class Meta: database = self.database return BaseModel @property def Model(self): if self._app is None: database = getattr(self, 'database', None) if database is None: self.database = Proxy() if not hasattr(self, '_model_class'): self._model_class = self.get_model_class() return self._model_class def connect_db(self): if self._excluded_routes and request.endpoint in self._excluded_routes: return self.database.connect() def close_db(self, exc): if self._excluded_routes and request.endpoint in self._excluded_routes: return if not self.database.is_closed(): self.database.close()
class FlaskDB(object): def __init__(self, app=None, database=None): self.database = None # Reference to actual Peewee database instance. self._app = app self._db = database # dict, url, Database, or None (default). if app is not None: self.init_app(app) def init_app(self, app): self._app = app if self._db is None: if 'DATABASE' in app.config: initial_db = app.config['DATABASE'] elif 'DATABASE_URL' in app.config: initial_db = app.config['DATABASE_URL'] else: raise ValueError('Missing required configuration data for ' 'database: DATABASE or DATABASE_URL.') else: initial_db = self._db self._load_database(app, initial_db) self._register_handlers(app) def _load_database(self, app, config_value): if isinstance(config_value, Database): database = config_value elif isinstance(config_value, dict): database = self._load_from_config_dict(dict(config_value)) else: # Assume a database connection URL. database = db_url_connect(config_value) if isinstance(self.database, Proxy): self.database.initialize(database) else: self.database = database def _load_from_config_dict(self, config_dict): try: name = config_dict.pop('name') engine = config_dict.pop('engine') except KeyError: raise RuntimeError('DATABASE configuration must specify a ' '`name` and `engine`.') if '.' in engine: path, class_name = engine.rsplit('.', 1) else: path, class_name = 'peewee', engine try: __import__(path) module = sys.modules[path] database_class = getattr(module, class_name) assert issubclass(database_class, Database) except ImportError: raise RuntimeError('Unable to import %s' % engine) except AttributeError: raise RuntimeError('Database engine not found %s' % engine) except AssertionError: raise RuntimeError('Database engine not a subclass of ' 'peewee.Database: %s' % engine) return database_class(name, **config_dict) def _register_handlers(self, app): app.before_request(self.connect_db) app.teardown_request(self.close_db) def get_model_class(self): if self.database is None: raise RuntimeError('Database must be initialized.') class BaseModel(Model): class Meta: database = self.database return BaseModel @property def Model(self): if self._app is None: database = getattr(self, 'database', None) if database is None: self.database = Proxy() if not hasattr(self, '_model_class'): self._model_class = self.get_model_class() return self._model_class def connect_db(self): self.database.connect() def close_db(self, exc): if not self.database.is_closed(): self.database.close()
class FlaskDB(object): def __init__(self, app=None): self._app = app self.database = None if app is not None: self.init_app(app) def init_app(self, app): self._app = app self._load_database(app) self._register_handlers(app) def _load_database(self, app): config_value = app.config['DATABASE'] if isinstance(config_value, dict): database = self._load_from_config_dict(dict(config_value)) else: # Assume a database connection URL. database = db_url_connect(config_value) if isinstance(self.database, Proxy): self.database.initialize(database) else: self.database = database def _load_from_config_dict(self, config_dict): try: name = config_dict.pop('name') engine = config_dict.pop('engine') except KeyError: raise RuntimeError('DATABASE configuration must specify a ' '`name` and `engine`.') if '.' in engine: path, class_name = engine.rsplit('.', 1) else: path, class_name = 'peewee', engine try: __import__(path) module = sys.modules[path] database_class = getattr(module, class_name) assert issubclass(database_class, _Database) except ImportError: raise RuntimeError('Unable to import %s' % engine) except AttributeError: raise RuntimeError('Database engine not found %s' % engine) except AssertionError: raise RuntimeError('Database engine not a subclass of ' 'peewee.Database: %s' % engine) return database_class(name, **config_dict) def _register_handlers(self, app): app.before_request(self.connect_db) app.teardown_request(self.close_db) def get_model_class(self): if self.database is None: raise RuntimeError('Database must be initialized.') class BaseModel(Model): class Meta: database = self.database return BaseModel @property def Model(self): if self._app is None: database = getattr(self, 'database', None) if database is None: self.database = Proxy() if not hasattr(self, '_model_class'): self._model_class = self.get_model_class() return self._model_class def connect_db(self): self.database.connect() def close_db(self, exc): if not self.database.is_closed(): self.database.close()
class Peewee(object): def __init__(self, app=None): """ Initialize the plugin. """ self.app = app self.database = Proxy() if app is not None: self.init_app(app) def init_app(self, app, database=None): """ Initialize an application. """ if not app: raise RuntimeError('Invalid application.') self.app = app if not hasattr(app, 'extensions'): app.extensions = {} app.extensions['peewee'] = self app.config.setdefault('PEEWEE_CONNECTION_PARAMS', {}) app.config.setdefault('PEEWEE_DATABASE_URI', 'sqlite:///peewee.sqlite') app.config.setdefault('PEEWEE_MANUAL', False) app.config.setdefault('PEEWEE_MIGRATE_DIR', 'migrations') app.config.setdefault('PEEWEE_MIGRATE_TABLE', 'migratehistory') app.config.setdefault('PEEWEE_MODELS_CLASS', Model) app.config.setdefault('PEEWEE_MODELS_IGNORE', []) app.config.setdefault('PEEWEE_MODELS_MODULE', '') app.config.setdefault('PEEWEE_READ_SLAVES', '') app.config.setdefault('PEEWEE_USE_READ_SLAVES', True) # Initialize database params = app.config['PEEWEE_CONNECTION_PARAMS'] database = database or app.config.get('PEEWEE_DATABASE_URI') if not database: raise RuntimeError('Invalid database.') database = get_database(database, **params) # Configure read slaves slaves = app.config['PEEWEE_READ_SLAVES'] if isinstance(slaves, str): slaves = slaves.split(',') self.slaves = [ get_database(slave, **params) for slave in slaves if slave ] self.database.initialize(database) if self.database.database == ':memory:': app.config['PEEWEE_MANUAL'] = True # TODO: Replace this code, when a solution will be found #if not app.config['PEEWEE_MANUAL']: # app.before_request(self.connect) # app.teardown_request(self.close) def connect(self): """ Initialize connection to database. """ LOGGER.info('Connecting [%s]', os.getpid()) return self.database.connect() def close(self, response): """ Close connection to database. """ LOGGER.info('Closing [%s]', os.getpid()) if not self.database.is_closed(): self.database.close() return response @cached_property def Model(self): """ Bind model to self database. """ Model_ = self.app.config['PEEWEE_MODELS_CLASS'] meta_params = {'database': self.database} if self.slaves and self.app.config['PEEWEE_USE_READ_SLAVES']: meta_params['read_slaves'] = self.slaves Meta = type('Meta', (), meta_params) return type('Model', (Model_, ), {'Meta': Meta}) @property def models(self): """ Return self.application models.py. """ Model_ = self.app.config['PEEWEE_MODELS_CLASS'] ignore = self.app.config['PEEWEE_MODELS_IGNORE'] models = [] if Model_ is not Model: try: mod = import_module(self.app.config['PEEWEE_MODELS_MODULE']) for model in dir(mod): models = getattr(mod, model) if not isinstance(model, PeeweeModel): continue models.append(models) except ImportError: return models elif isinstance(Model_, BaseSignalModel): models = BaseSignalModel.models return [m for m in models if m._meta.name not in ignore] def cmd_create(self, name, auto=False): """ Create a new migration. """ LOGGER.setLevel('INFO') LOGGER.propagate = 0 router = Router(self.database, migrate_dir=self.app.config['PEEWEE_MIGRATE_DIR'], migrate_table=self.app.config['PEEWEE_MIGRATE_TABLE']) if auto: auto = self.models router.create(name, auto=auto) def cmd_migrate(self, name=None, fake=False): """ Run migrations. """ LOGGER.setLevel('INFO') LOGGER.propagate = 0 router = Router(self.database, migrate_dir=self.app.config['PEEWEE_MIGRATE_DIR'], migrate_table=self.app.config['PEEWEE_MIGRATE_TABLE']) migrations = router.run(name, fake=fake) if migrations: LOGGER.warn('Migrations are completed: %s' % ', '.join(migrations)) def cmd_rollback(self, name): """ Rollback migrations. """ LOGGER.setLevel('INFO') LOGGER.propagate = 0 router = Router(self.database, migrate_dir=self.app.config['PEEWEE_MIGRATE_DIR'], migrate_table=self.app.config['PEEWEE_MIGRATE_TABLE']) router.rollback(name) def cmd_list(self): """ List migrations. """ LOGGER.setLevel('DEBUG') LOGGER.propagate = 0 router = Router(self.database, migrate_dir=self.app.config['PEEWEE_MIGRATE_DIR'], migrate_table=self.app.config['PEEWEE_MIGRATE_TABLE']) LOGGER.info('Migrations are done:') LOGGER.info('\n'.join(router.done)) LOGGER.info('') LOGGER.info('Migrations are undone:') LOGGER.info('\n'.join(router.diff)) def cmd_merge(self): """ Merge migrations. """ LOGGER.setLevel('DEBUG') LOGGER.propagate = 0 router = Router(self.database, migrate_dir=self.app.config['PEEWEE_MIGRATE_DIR'], migrate_table=self.app.config['PEEWEE_MIGRATE_TABLE']) router.merge() @cached_property def manager(self): """ Integration with the Sanic-Script package. """ from sanic_script import Manager, Command manager = Manager(usage="Migrate database.") manager.add_command('create', Command(self.cmd_create)) manager.add_command('migrate', Command(self.cmd_migrate)) manager.add_command('rollback', Command(self.cmd_rollback)) manager.add_command('list', Command(self.cmd_list)) manager.add_command('merge', Command(self.cmd_merge)) return manager @cached_property def cli(self): import click @click.group() def cli(): pass @cli.command() @click.argument('name') @click.option('--auto', is_flag=True) def create(name, auto=False): """ Create a new migration. """ return self.cmd_create(name, auto) @cli.command() @click.argument('name', default=None, required=False) @click.option('--fake', is_flag=True) def migrate(name, fake=False): """ Run migrations. """ return self.cmd_migrate(name, fake) @cli.command() @click.argument('name') def rollback(name): """ Rollback migrations. """ return self.cmd_rollback(name) @cli.command() def list(): """ List migrations. """ return self.cmd_list() return cli