当前位置: 首页 > 面试题库 >

在Flask和其他应用程序之间共享SQLAlchemy模型

松雅昶
2023-03-14
问题内容

我有一个正在运行的Flask应用程序,该应用程序是根据我们在网上和Miguel Grinberg的“ Flask Web开发”书中找到的最佳实践组合设置的。

现在,我们需要第二个Python应用程序,它不是Web应用程序,并且需要访问与Flask应用程序相同的模型。我们想重复使用相同的课程模型,因此两个应用程序都可以从共享代码中受益。

我们删除了关于flask-
sqlalchemy扩展的依赖关系(之前只有Flask应用程序时使用过)。并将其替换为此处描述的SQLalchemy声明性扩展,这有点简单(Flask-
SQLalchemy向标准SQLAlchemy添加了一些特定的东西

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

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

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

这意味着我们app/__init__.py看起来像这样(简化):

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

但是,数据库(模型从..导入)的数据库现在需要位于create_app()函数内部,因为这是Flask加载配置的地方。如果我要在create_app()函数外部实例化db对象,则可以从模型中导入该对象,但未配置该对象!

一个示例模型如下所示,如您所见,它期望在应用程序的根目录中有一个“ db”:

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

所以我的问题是,如何拥有可以在外部(通过Flask或其他应用程序)配置的数据库实例,并且仍然使用Application Factory Pattern?

编辑: 该代码示例不正确,它具有Flask-SQLalchemy的导入,已由代替from database import Database。抱歉给您带来任何混乱。


问题答案:

与大多数Flask扩展一样,Flask-
SQLAlchemy扩展应在工厂外部创建,然后在工厂中使用进行初始化init_app。这样,您就可以db在创建应用之前使用该对象。

db = SQLAlchemy()

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

与任何适当设计的Python项目一样,您的Flask应用应为可安装的程序包。这很容易做到:确保您的项目布局合理,然后添加一个基本setup.py文件。

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

现在,您可以安装Flask应用程序及其数据库,以供其他项目使用。将其安装并导入到第二个项目的virtualenv中,然后创建并推送应用以对其进行初始化。

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

如果您担心创建应用程序涉及的开销,则可以在create_app函数中添加参数以控制初始化的内容。在大多数情况下,这应该不是问题。



 类似资料:
  • 问题内容: 我的公司接管了一些旧的php应用程序。由于我们偏爱ASP.net且由于以前的开发人员缺少任何文档,因此我们不想在PHP开发上花费大量资源。为了实现新功能,我们将创建一个Asp.net应用程序,其外观与用户相同。我们要开发一种“共存”的Web应用程序。因此,我们必须在PHP和Asp.net Web应用程序项目之间共享会话,因为现有的MySQL数据库涉及用户管理。 (例如,链接“ A”指向

  • 首先请不要把这个问题当作重复的问题。所有其他问题都是旧的,我已经尝试了其中大多数的解决方案,但没有一个奏效。 我正在开发一个Android应用程序,我已经将我的应用程序添加到共享Android菜单中。我想添加功能,这样如果用户在共享列表上单击我的应用,例如在Chrome浏览器或Google Drive应用中,我的应用将从该应用接收数据,例如从Chrome it wold URL。 我尝试过使用不同

  • 我有一个Flask应用程序在Gunicorn下运行,使用同步工作进程类型和20个工作进程。该应用程序在启动时读取大量数据,这需要时间和内存。更糟糕的是,每个进程都加载自己的副本,这会导致它花费更长的时间,占用20倍的内存。数据是静态的,不会更改。我想加载一次,让所有20名员工共享。 如果我使用设置,它只加载在一个线程中,并且最初只需要1X内存,但是一旦请求开始进来,它似乎会变成20X。我需要快速随

  • 问题内容: 我一次运行2个单独的Java应用程序。(两个单独的javaw.exe)在它们运行时,我需要在它们之间共享一个对象。 没有永久存储的最简单方法是什么? 问题答案: 对象及其实例变量可以在Java程序的线程之间共享,这是非常简单的任务。 如果您需要在两个程序之间共享对象(例如它的对象)而没有数据存储,那么下一个选择将是使用RMI套接字通信或Java消息传递服务。

  • 问题内容: 假设我有一个要注入到config中的模块: 有两个子模块: 这是第一个: 第二个是相同的,以简化示例: 您会注意到,您可以将它们作为提供者来访问以配置选项: 如果我们在控制器中,则可以覆盖每个范围,例如: 但是,如果他们总是共享相同的财产怎么办?如何在提供商之间共享某些东西? 我可以同时为和注入和配置共享属性吗? 如何同时访问和作为单个模块的扩展? 问题答案: 将模块插入两个共享这些属

  • 我们目前支持英语、德语、西班牙语、意大利语和法语作为语言。我们有一个iOS、Android和Windows Phone应用程序,以及一个HTML/JS Web应用程序。这三款移动应用程序非常相似。它们的屏幕和文本基本相同。每个应用程序都由一个小团队完成,并为所有应用程序并行开发功能。webapp中也使用了相当多的文本。 我们现在面临着如何管理我们的(英语)文本字符串及其翻译的问题。现在,我们有Go