在烧瓶和其他应用程序之间共享sqlalchemy模型 [英] Share sqlalchemy models between flask and other apps

查看:132
本文介绍了在烧瓶和其他应用程序之间共享sqlalchemy模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个正在运行的Flask应用程序,这个应用程序是根据我们在网上找到的最佳实践和Miguel Grinberg的Flask Web Development一书的结合而建立的。 现在需要第二个Python应用程序,这不是一个Web应用程序,需要访问与Flask应用程序相同的模型。我们希望重复使用相同的课程模式,所以这两个应用程序都可以从共享代码中获益。



我们已经移除了对flask-sqlalchemy扩展的依赖关系之前,当我们只有Flask应用程序)。并用这里描述的SQLalchemy声明性扩展替换它,这有点简单(Flask-SQLalchemy为标准的SQLAlchemy添加了一些特定的功能

根据这个例子,我们在根中创建了一个database.py文件。在我们的例子中,有两点与Declarative扩展示例不同:我将引擎和会话放在一个类中,因为我们所有的模型都使用db.session而不是db_session,并将具有配置值的字典传递给 init(),这样我就可以使用不同的配置从Flask以及另一个应用程序中重新使用这个database.py。它看起来像这样:

  from sqlalchemy import create_engine $ b $ from sqlalchemy.orm import scoped_session,sessionmaker 
from sqlalchemy.ext.declarative import declarative_base

$ b $ class数据库(对象):
$ b $ def __init __(self,cfg):
self.engine = create_engine (cfg ['SQLALCHEMY_DATABASE_URI'],convert_unicode = True)
self.session = scoped_session(sessionmaker(autocommit = False,autoflush = False,bind = self.engine))
$ b $ class Model对象):
pass

Base = declarative_base()

所以现在我们来解决实际的问题。 Flask创建一个包含配置选项的类似字典的对象,并将它们作为一个属性添加到应用程序实例中。它从一个实例文件夹,一个 config.py 在网站的根和环境变量。我需要从Flask传入配置字典,因此我需要Flask加载并组装配置,然后初始化数据库,并在应用程序文件的根目录中有一个(配置的)数据库对象。但是,我们遵循应用程序工厂模式,所以我们可以针对不同的情况使用不同的配置(测试,生产,发展)。



这意味着我们的 app / __ init __。py 看起来像这样(简化):

 从瓶子导入Flask 
从数据库导入数据库
从flask.ext.mail导入邮件
从flask_bcrypt导入Bcrypt
from config导入配置

mail = Mail()
bcrypt = Bcrypt()

$ b $ create_app(config_name):
$ b $ app = Flask(__ name__,instance_relative_config = True)

如果不是config_name:
config_name ='default'
app.config.from_object(config [config_name ])
app.config.from_pyfile('config.py')
config [config_name] .init_app(app)
$ b $ db = Database(app.config)

mail.init_app(app)
bcrypt.init_app(app)
$ b $ app_teardown_appcontext
def shutdown_session(exception = None):
db .session.remove()

作为main_blueprint输入main main
app.register_blueprint(main_bluepr int)

return app

但是db ..),现在需要在create_app()函数内,因为这是Flask加载配置的地方。如果我将在create_app()函数之外实例化db对象,它将从模型中导入,但是它没有被配置!

示例模型看起来像这样,正如你所看到的,它预计在应用程序的根目录中的数据库:

  from。 base_models从sqlalchemy.orm导入区域
导入关系,backref $ b $ from from ..utils.helper_functions导入newid $ b $ from .. import db


class类型(db.Model,areas):
Area model class。

country = relationship(Countries,backref = backref('areas'))

def __init __(self,* args,** kwargs):
self.area_id = newid()
super(Areas,self).__ init __(* args,** kwargs)$格式(self.area_name).encode('utf8')

def __repr __(self)b
$ def __str __(self):
return u{} :
return u< Area:'{}'>。format(self.area_name).encode('utf8')

所以我的问题是,我怎样才能有一个数据库实例,可以配置外部(Flask或其他应用程序),仍然使用应用程序工厂模式?
$ b 编辑:代码示例不正确,它有一个由替换的Flask-SQLalchemy导入数据库导入数据库。对于任何混淆,抱歉。
解决方案

Flask-SQLAlchemy扩展,像大多数Flask扩展一样,应该在工厂外部创建,然后初始化在工厂中使用 init_app 。这是为了您可以在创建应用程序之前使用 db 对象。

 <$ c $ b $ db 
def create_app():
app = Flask(__ name__)
db.init_app(app)
return app

您的Flask应用程序与任何正确设计的Python项目一样,应该是可安装的包。这很简单:确保您的项目布局合理,然后添加一个基本的 setup.py 文件。



<$在最基本的,这包含了create_app和db
setup.py
$项目/
my_flask_package /
__init__.py# c $ c



pre $ from setuptools import setup,find_packages

setup(
name ='my_flask_package',
version ='1.0',
packages = find_packages(),
install_requires = ['flask','flask-sqlalchemy '],





  $ python setup.py sdist 

现在您可以安装Flask应用程序,数据库,用于其他项目。安装并导入到第二个项目的virtualenv中,然后创建并推送一个应用程序来初始化它。

  $ pip install my_flask_package-1.0 .tar.gz 





  from my_flask_package import db,create_app $ b $ create_app()。app_context()。push()
db.session.query(...)


I have a running Flask application that is set up according to a combination of best practices we found online and in Miguel Grinberg's "Flask Web Development" book.

We now need a second Python application, that is NOT a web app, and that needs access to the same models as the Flask application. We wanted to re-use the same models ofcourse, so both apps can benefit from the shared code.

We have removed dependencies on the flask-sqlalchemy extention (which we used before, when we had just the Flask application). And replaced it with the SQLalchemy Declarative extension described here, which is a bit simpler (Flask-SQLalchemy adds a few specific things to standard SQLAlchemy)

In line with the example we have created a database.py file in the root. In our case there are two things different from the Declarative extension example: I put the engine and session in a class, because all of our models use db.session, instead of db_session, and I pass a dictionary with configuration values to the init(), so that I can re-use this database.py from both Flask as well as another application, using a different configuration. it looks like this:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base


class Database(object):

    def __init__(self, cfg):
        self.engine = create_engine(cfg['SQLALCHEMY_DATABASE_URI'], convert_unicode=True)
        self.session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=self.engine))

    class Model(object):
        pass

Base = declarative_base()

So now we come to the actual problem. Flask creates a dictionary-like object containing configuration options, and adds them as a property to the app-instance. It loads them from an instance folder, a config.py in the root of the site and from environment variables. I need to pass in the configuration dictionary from Flask, so I need Flask to FIRST load and assemble the configuration, and after that initialise the database, and have a (configured) db object in the root of the app file. However, we follow the Application factory pattern, so we can use different configurations for different situations (test, production, development).

This means our app/__init__.py looks something like this (simplified):

from flask import Flask
from database import Database
from flask.ext.mail import Mail
from flask_bcrypt import Bcrypt
from config import config

mail = Mail()
bcrypt = Bcrypt()


def create_app(config_name):

    app = Flask(__name__, instance_relative_config=True)

    if not config_name:
        config_name = 'default'
    app.config.from_object(config[config_name])
    app.config.from_pyfile('config.py')
    config[config_name].init_app(app)

    db = Database(app.config)

    mail.init_app(app)
    bcrypt.init_app(app)

    @app.teardown_appcontext
    def shutdown_session(exception=None):
        db.session.remove()

    from main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

But the db (that the models import from ..), now needs to be inside the create_app() function, because that's where Flask loads the configuration. If I would instantiate the db object outside of the create_app() function, it will be importable from the models, but it is not configured!

an example model looks like this, and as you can see, it expects a "db" in the root of the app:

from . base_models import areas
from sqlalchemy.orm import relationship, backref
from ..utils.helper_functions import newid
from .. import db


class Areas(db.Model, areas):
    """Area model class.
    """
    country = relationship("Countries", backref=backref('areas'))

    def __init__(self, *args, **kwargs):
        self.area_id = newid()
        super(Areas, self).__init__(*args, **kwargs)

    def __str__(self):
        return u"{}".format(self.area_name).encode('utf8')

    def __repr__(self):
        return u"<Area: '{}'>".format(self.area_name).encode('utf8')

So my question is, how can I have a db instance that can be configured externally (by either Flask or another app), and still use the Application Factory Pattern?

edit: The code-example was incorrect, it had an import for Flask-SQLalchemy which was replaced by from database import Database. Sorry for any confusion.

解决方案

The Flask-SQLAlchemy extension, like most Flask extensions, should be created outside the factory, then initialized in the factory using init_app. This is so that you can use the db object before an app is created.

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    return app

Your Flask app, like any properly designed Python project, should be an installable package. This is simple to do: make sure your project layout makes sense, then add a basic setup.py file.

project/
    my_flask_package/
        __init__.py  # at the most basic, this contains create_app and db
    setup.py

from setuptools import setup, find_packages

setup(
    name='my_flask_package',
    version='1.0',
    packages=find_packages(),
    install_requires=['flask', 'flask-sqlalchemy'],
)

$ python setup.py sdist

Now you can install your Flask app, along with it's database, for use in other projects. Install and import it in your second project's virtualenv, then create and push an app to initialize it.

$ pip install my_flask_package-1.0.tar.gz

from my_flask_package import db, create_app
create_app().app_context().push()
db.session.query(...)

这篇关于在烧瓶和其他应用程序之间共享sqlalchemy模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆