【问题标题】:Flask-RESTful Project StructureFlask-RESTful 项目结构
【发布时间】:2015-08-26 14:14:42
【问题描述】:

这是我的工作:

/myproject
    README.md
    runserver.py
    /myproject
        __init__.py
        api.py
        /resources
            __init__.py
            foo.py
            bar.py
        /common
            __init__.py
            db.py
    /tests
        test_myproject.py

这里没什么特别的。大部分内容都可以在 Flask-RESTful 用户指南的 Intermediate Usage 页面上找到。

我担心循环导入...

api.py

from flask import Flask
from flask_restful import Api

app = Flask(__name__)

from myproject.resources.foo import Foo
from myproject.resources.bar import Bar

api = Api(app)

api.add_resource(Foo, '/Foo', '/Foo/<str:id>')
api.add_resource(Bar, '/Bar', '/Bar/<str:id>')

foo.py

from flask_restful import Resource
from myproject.common.db import query_db


class Foo(Resource):
    def get(self):
        pass
    def post(self):
        pass

db.py

from flask import g
import sqlite3
from myproject.api import app


def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(app.config['DATABASE'])
        db.row_factory = make_dicts
    return db


def query_db(query, args=(), one=False):
    cur = get_db().execute(query, args)
    rv = cur.fetchall()
    cur.close()
    return (rv[0] if rv else None) if one else rv


@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.commit()
        db.close()

显然,我在我的项目中引入了循环导入:

api.py -> foo.py -> db.py -> api.py

这不是一个大 问题,只要我在导入资源之前实例化 Flask 应用程序对象(我会这样做)。 here 讨论了类似的模式(请参阅页面底部的循环导入部分)。

我的问题...

这是构建 Flask-RESTful 项目的好方法吗?

This 是我能找到的关于这个主题的最接近的 SO 问题。我对提供的答案不满意,因为我不想将我的数据库函数保留在顶级 __init__.py 文件中(或 api.py - 路由所属的位置)。

这里还有其他几个类似的 SO 问题,但它们正在处理导入错误(我不是):

Structure Flask-Restful API to use SQLAlchemy

Error importing models when trying to run app

【问题讨论】:

    标签: python sqlite rest flask flask-restful


    【解决方案1】:

    由于您的问题主要基于意见,因此我将提出我认为更好的解决方案:)

    我不会在db.py 中导入myproject.api.app,而是在db.py 中创建自己的模块级全局变量来存储数据库配置:

    db.py

    from flask import g
    import sqlite3
    
    _db_config = None # Holds database config
    
    def init(app):
        """ Function must be called to initalize this module """
        global _db_config
        global close_connection
        _db_config = app.config['DATABASE']
        # Manually apply @app.teardown_appcontext decorator
        close_connection = app.teardown_appcontext(close_connection)
    
    
    def _db_connect():
        if _db_config is None:
            raise Exception('Call init first') # or whatever error you want
        return sqlite3.connect(_db_config)
    
    
    def get_db():
        db = getattr(g, '_database', None)
        if db is None:
            db = g._database = _db_connect()
            db.row_factory = make_dicts
        return db
    
    ....
    
    def close_connection(exception):
        db = getattr(g, '_database', None)
        if db is not None:
            db.commit()
            db.close()
    

    然后在api.py调用myproject.common.db.init()初始化db

    api.py

    from flask import Flask
    from flask_restful import Api
    from myproject.common import db
    
    app = Flask(__name__)
    db.init(app)
    
    ....
    

    这样db.py 不再依赖api.py

    【讨论】:

    • 感谢您的回复。我喜欢你的解决方案,但是,db.py 仍然依赖于api.py。使用 @app.teardown_appcontext 装饰器查看 close_connection 函数。
    • 如果您不介意手动应用装饰器,这很容易解决:)。请参阅上面的编辑。
    • 首先,我认为您需要在 init 函数中将 close_connection 声明为全局变量,否则 Python 会将其视为局部变量。其次,当我尝试这种方法时,出现以下错误:ProgrammingError: Cannot operate on a closed database.
    • 对。更正了。你能找到ProgrammingError的位置吗?
    • 嘿,runserver.py 怎么样?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多