2015-06-11 73 views
1

這裏是我的工作:瓶的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 

這裏沒有什麼特別。大部分內容可以在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>') 

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 

這不是一個問題,只要我實例化瓶應用對象之前導入我的資源(我做)。 here討論了類似的模式(參見頁面底部的循環導入部分)。

我的問題...

這是一個很好的方式來構建一個瓶的RESTful項目?

This是我可以找到的關於此主題最接近的SO問題。我對所提供的答案並不滿意,因爲我不想將我的數據庫功能保留在頂層__init__.py文件中(或者在api.py--路由所屬的地方)。

這裏有幾個其他類似的SO問題,但它們與進口處理錯誤(這我不是):

Structure Flask-Restful API to use SQLAlchemy

Error importing models when trying to run app

回答

2

由於您的問題在很大程度上是輿論基礎,我我會建議我認爲會更好的解決方案:)

而不是導入myproject.api.appdb.py,我會創建我自己的模塊級gl在db.py 10:28變量存儲數據庫配置:

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

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

+1

感謝您的答覆的依賴。我喜歡你的解決方案,但是,'db.py'仍然會依賴'api.py'。請參閱'@ app.teardown_appcontext'裝飾器的'close_connection'函數。 – jamesdarabi

+1

如果你不介意手動應用裝飾器,那麼可以很容易地解決這個問題:)。看到我上面的編輯。 – junnytony

+1

首先,我認爲你需要在'init'函數中將'close_connection'聲明爲全局的,否則Python會將它視爲一個局部變量。其次,當我嘗試這種方法時,出現以下錯誤:'ProgrammingError:無法在封閉數據庫上運行。「 – jamesdarabi