web-dev-qa-db-ja.com

Flaskのデータベースに接続します。どちらのアプローチが良いですか?

方法1: http://flask.pocoo.org/docs/tutorial/dbcon/ および http://flask.pocoo.org/docs/patterns/からの特別なgオブジェクトを使用するsqlite3 /

import sqlite3
from flask import g

DATABASE = '/path/to/database.db'

def connect_db():
    return sqlite3.connect(DATABASE)

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    if hasattr(g, 'db'):
        g.db.close()

方法2: https://github.com/mitsuhiko/flask/blob/master/examples/flaskr/flaskr.py からMysterious _app_ctx_stackを使用する

from sqlite3 import dbapi2 as sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, \
     render_template, flash, _app_ctx_stack
def get_db():
    """Opens a new database connection if there is none yet for the
    current application context.
    """
    top = _app_ctx_stack.top
    if not hasattr(top, 'sqlite_db'):
        top.sqlite_db = sqlite3.connect(app.config['DATABASE'])
    return top.sqlite_db


@app.teardown_appcontext
def close_db_connection(exception):
    """Closes the database again at the end of the request."""
    top = _app_ctx_stack.top
    if hasattr(top, 'sqlite_db'):
        top.sqlite_db.close()

どちらの方法が良いですか?違いはなんですか?

56
Gaby Solis

1つ目は、接続が不要な場合でも接続を取得するという問題があります。 2番目の方法には、サードパーティのフレームワークの内部で遊んでいるという欠点がありますが、かなり読みにくいです。

2つだけの場合、おそらく2つ目がより良い選択です。ルートを必要としないルートの接続を取得しないだけでなく、ルートの他のコードパスが必要な場合でも、必要のないコードパスを下る場合は接続を取得しません。 (たとえば、何らかのフォーム検証がある場合、検証に合格した場合にのみ接続が必要になります。検証が失敗しても接続は開かれません。)この設定で使用する前に接続を取得するだけです。

ただし、内部の混乱を避けることができ、それでもこれらすべての利点を得ることができます。個人的に、私は独自の小さなグローバルメソッドを作成しました。

import flask
import sqlite3

def request_has_connection():
    return hasattr(flask.g, 'dbconn')

def get_request_connection():
    if not request_has_connection():
        flask.g.dbconn = sqlite3.connect(DATABASE)
        # Do something to make this connection transactional.
        # I'm not familiar enough with SQLite to know what that is.
    return flask.g.dbconn

@app.teardown_request
def close_db_connection(ex):
    if request_has_connection():
        conn = get_request_connection()
        # Rollback
        # Alternatively, you could automatically commit if ex is None
        # and rollback otherwise, but I question the wisdom 
        # of automatically committing.
        conn.close()

次に、アプリ全体で、_get_request_connection、あなたのget_db 関数。簡単で高効率。基本的に、両方の長所です。

編集:

振り返ってみると、これらがグローバルメソッドであるという事実を本当に嫌いますが、その理由はFlaskがどのように機能するかです。実際にスレッドローカルを指す「グローバル」を提供します。

12
jpmc26

Flask-SQLAlchemy をお勧めします。これは、Flaskで使用するためにSQLAlchemyを拡張し、さまざまなデータベースをサポートします。 (Flask-SQLAlchemyドキュメントの例)

セットアップ:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

これで、Userクラスをインポート/使用して、データベースのUserテーブルにアクセスできます。

新しいユーザーを作成します。

>>> from yourapplication import User
>>> admin = User('admin', '[email protected]')
>>> guest = User('guest', '[email protected]')

データベースにユーザーを追加します。

>>> db.session.add(admin)
>>> db.session.add(guest)
>>> db.session.commit()

データベースに既に存在するユーザーのクエリ:

>>> users = User.query.all()
[<User u'admin'>, <User u'guest'>]
>>> admin = User.query.filter_by(username='admin').first()
<User u'admin'>
7
arboc7

方法1を使用します-より読みやすく、「ハック」が少なくなります。

方法2は、おそらくflask拡張機能の統合( および app-ctx-stackの説明 )向けに設計されています。同様の効果があり、通常の場合は方法1を使用する必要があります。

4
Robert Lujo