【问题标题】:flask-migrate issue while refactoring code重构代码时出现烧瓶迁移问题
【发布时间】:2018-09-18 02:48:32
【问题描述】:

我得到了一个带有 flask-migrate 的 Python-Flask 应用程序的以下文件结构:

我的问题是

1-我无法在 manage.py 中使用 db 和 create_app

当我这样做时:

$ python manage.py db init

我收到以下错误:

File "/app/main/model/model.py", line 25, in <module>
    class User(db.Model):
NameError: name 'db' is not defined

(db 在 main.init.py 中定义)

我尝试了不同的选项,但没有成功。

我想将 manage.py 、 model.py 和 main.init.py 保存在单独的文件中。

2- 在 model .py 中,我需要 db 。如何使 db 可用于 model.py ?

下面是manage.py

# This file take care of the migrations
# in model.py we have our tables
import os
import unittest

from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager

from app.main import create_app
from app.main import db
# # We import the tables into the migrate tool
from app.main.model import model


app = create_app(os.getenv('BOILERPLATE_ENV') or 'dev')

app.app_context().push()

manager = Manager(app)

migrate = Migrate(app, db)

manager.add_command('db', MigrateCommand)

#### If I add  model.py here all should be easier , but still I have the 
#### issue with 
#### from app.main import create_app , db


@manager.command
def run():
    app.run()


@manager.command
def test():
    """Runs the unit tests."""
    tests = unittest.TestLoader().discover('app/test', pattern='test*.py')
    result = unittest.TextTestRunner(verbosity=2).run(tests)
    if result.wasSuccessful():
        return 0
    return 1

if __name__ == '__main__':
    manager.run()

这是 app.init.py,其中定义了 db 和 create_app

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_cors import CORS

from .config import config_by_name

from flask_restful import Resource, Api
# from flask_restplus import Resource
from app.main.controller.api_controller import gconnect, \
     showLogin, createNewTest, getTest, getTests, getIssue, createNewIssue

db = SQLAlchemy()
flask_bcrypt = Bcrypt()


def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config_by_name[config_name])
    cors = CORS(app,
                supports_credentials=True,
                resources={r"/api/*":
                           {"origins":
                            ["http://localhost:3000",
                             "http://127.0.0.1:3000"]}})
    api = Api(app)
    db.init_app(app)
    flask_bcrypt.init_app(app)

    api.add_resource(gconnect, '/api/gconnect')
    api.add_resource(showLogin, '/login')
    api.add_resource(createNewTest, '/api/test')
    api.add_resource(getTest, '/api/test/<int:test_id>')
    api.add_resource(getTests, '/api/tests')
    api.add_resource(getIssue, '/api/issue/<int:issue_id>')
    api.add_resource(createNewIssue, '/api/issue')

    return app

这是我的模型(为简单起见,只是表格之一)

from sqlalchemy import Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
from sqlalchemy import create_engine
from sqlalchemy.sql import func


# # # This will let sql alchemy know that these clasess
# # # are special Alchemy classes
# Base = declarative_base()



class User(db.Model):

    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(250), nullable=False)
    email = db.Column(db.String(250), nullable=False)
    pictures = db.Column(db.String(250))
    role = db.Column(db.String(25), nullable=True)

我的问题是:

1-我无法在 manage.py 中使用 db 和 create_app

当我这样做时:

$ python manage.py db init

我收到以下错误:

文件“/app/main/model/model.py”,第 25 行,在 类用户(db.Model): NameError: 名称 'db' 未定义

(db 在 main.init.py 中定义)

我尝试了不同的选项,但没有成功。

我想将 manage.py 、 model.py 和 main.init.py 保存在单独的文件中。

2- 在模型 .py 中,我需要 db。如何使 db 可用于 model.py?

【问题讨论】:

    标签: python python-3.x flask-sqlalchemy factory-pattern flask-migrate


    【解决方案1】:

    一个简单的解决方案是在您的__init__.py 之外创建一个单独的初始化文件。例如init.py 在其中初始化 sqlalchemy 以及其他扩展。这样它们就可以在所有模块中导入,而不会出现任何循环依赖问题。

    然而,更优雅的解决方案是使用 Flask 的 current_appg 代理。它们旨在帮助 Flask 用户规避任何与循环依赖相关的问题。

    通常你在__init__.py 模块中初始化烧瓶app,而__init__.py 模块有时必须从其子模块中导入一些变量。当子模块尝试导入初始化的扩展时,这会成为问题

    作为一般经验法则,外部模块应该从其子模块导入,而不是相反。

    所以这是解决问题的一种方法(引用自here):

    ** __init__.py

    from flask import g
    
    def get_db():
        if 'db' not in g:
            g.db = connect_to_database()
    
        return g.db
    
    @app.teardown_appcontext
    def teardown_db():
        db = g.pop('db', None)
    
        if db is not None:
            db.close()
    
    
    def init_db():
        db = get_db()
    

    现在您可以通过以下方式轻松地将您的数据库连接导入任何其他模块:

    from flask import g
    
    db = g.db
    db.do_something()
    

    【讨论】:

    • 这个问题的根本原因是我想改进代码,将一些大文件拆分成多个小文件。但是这会导致循环引用问题。我设法解决了一些问题,但是仍然无法解决所有问题。我认为这个案例是否表明了为您的需求选择正确框架的重要性以及我们作为开发人员的局限性
    • 嗯,Flask 是一个微框架,这意味着它可以让你用最少数量的文件编写应用程序,从而使这些问题显而易见。您是否尝试过使用g
    • 你说得对。 g 是解决这个问题的一种方法。我实际上做了一些更简单的事情。刚刚创建了模块,我在其中声明了导致问题的全局变量。现在我有一个更清晰的代码。下一步是使用 g 。但我必须一步一步来。即使我没有使用您的建议,您的回答也是正确的。感谢您的帮助 Charming Robot :-)
    猜你喜欢
    • 2019-01-26
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多