Flask-RESTful 项目结构

jam*_*abi 5 python sqlite rest flask flask-restful

这是我正在处理的内容:

/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
Run Code Online (Sandbox Code Playgroud)

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

我担心的是循环进口......

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>')
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

数据库.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()
Run Code Online (Sandbox Code Playgroud)

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

api.py -> foo.py -> db.py -> api.py
Run Code Online (Sandbox Code Playgroud)

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

我的问题...

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

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

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

构建 Flask-Restful API 以使用 SQLAlchemy

尝试运行应用程序时导入模型时出错

jun*_*ony 2

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

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

数据库.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()
Run Code Online (Sandbox Code Playgroud)

然后api.py通过调用初始化数据库myproject.common.db.init()

api.py

from flask import Flask
from flask_restful import Api
from myproject.common import db

app = Flask(__name__)
db.init(app)

....
Run Code Online (Sandbox Code Playgroud)

这种方式db.py不再依赖于api.py