Python 在 Flask 中连接数据库,哪种方法更好?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16311974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 22:15:18  来源:igfitidea点击:

Connect to a Database in Flask, Which Approach is better?

pythonsqliteflask

提问by Gaby Solis

Method One: Using special g object from http://flask.pocoo.org/docs/tutorial/dbcon/and http://flask.pocoo.org/docs/patterns/sqlite3/

方法一:使用来自http://flask.pocoo.org/docs/tutorial/dbcon/http://flask.pocoo.org/docs/patterns/sqlite3/ 的特殊 g 对象

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

Method Two: Using Mysterious _app_ctx_stack from https://github.com/mitsuhiko/flask/blob/master/examples/flaskr/flaskr.py

方法二:使用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()

Which method is better? What is the difference?

哪种方法更好?有什么不同?

回答by Robert Lujo

I'd go with method one - more readable and less "hackish".

我会使用方法一 - 更具可读性,更少“hackish”。

The method 2 is probably designed for flask extensions integration (exampleand explanation of app-ctx-stack). Although they probably have very similar effect, method one should be used for normal cases.

方法 2 可能是为烧瓶扩展集成而设计的(app-ctx-stack 的示例解释)。虽然它们可能具有非常相似的效果,但方法一应该用于正常情况。

回答by Sean Vieira

The difference between the two is that method one creates a connection on g.dbwhether you need it or not while method two only creates the connection when you call get_dbfor the first time in that application context.

两者之间的区别在于,方法一根据g.db您是否需要创建连接,而方法二仅在您get_db在该应用程序上下文中第一次调用时创建连接。

If you compare the two, using this setup:

如果您比较两者,请使用此设置:

yourapp = Flask(__name__)

# setup g.db or app_context here
# Add a logging statement (print will do)
# to the get_db or before_request functions
# that simply says "Getting the db connection ..."
# Then access / and /1

@yourapp.route("/")
def index():
    return "No database calls here!"

@yourapp.route("/<int:post_id>")
def show_post(post_id):
    # get a post using g.db or get_db
    return "Went to the DB and got {!r}".format(post)

You'll see that when you hit /using the @app.before_requestsetup (g.db) you get a connection whether you use it or not, while using the _app_contextroute you only get a connection when you call get_db.

您将看到,当您/使用@app.before_requestsetup ( g.db) 时,无论您是否使用它,您都会获得一个连接,而使用该_app_context路由时,您只会在您调用 时get_db获得一个连接。

To be fair, you can also add a descriptor to gthat will do the same lazy connecting (or in real life, acquiring a connection from a connection pool). And in bothcases you can use a bit more magic (werkzeug.local.LocalProxyto be precise) to create your own custom thread localthat acts like g, current_appand request(among others).

公平地说,您还可以添加一个描述符来g执行相同的延迟连接(或在现实生活中,从连接池获取连接)。在这两种情况下,您都可以使用更多的魔法(werkzeug.local.LocalProxy准确地说)来创建您自己的自定义线程本地,其作用类似于g,current_apprequest等等)。

回答by arboc7

I recommend Flask-SQLAlchemy, which extends SQLAlchemy for use in Flask, so it supports many different databases. (Example from Flask-SQLAlchemy documentation)

我推荐Flask-SQLAlchemy,它扩展了 SQLAlchemy 以在 Flask 中使用,因此它支持许多不同的数据库。(来自 Flask-SQLAlchemy 文档的示例)

Setup:

设置:

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

Now, you can just import/use the Userclass to access the User table in your database.

现在,您只需导入/使用User该类即可访问数据库中的 User 表。

Create new users:

创建新用户:

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

Add the users to the database:

将用户添加到数据库:

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

Query for users already in database:

查询数据库中已有的用户:

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

回答by jpmc26

The first has the issue of acquiring connections even when they aren't needed. The second has the downside of playing with internals of a third party framework, plus it's pretty unreadable.

第一个存在获取连接的问题,即使它们不需要。第二个有使用第三方框架内部结构的缺点,而且它非常不可读。

Of the two alone, the second is probably the better choice. Not only does it not acquire a connection for routes that don't need one, it doesn't acquire a connection if you go down any code path that doesn't need one, even if other code paths in the route require one. (For example, if you have some form validation, you only need the connection if the validation passes; this won't open one when the validation fails.) You only acquire connections right before you use them with this set up.

仅在这两者中,第二个可能是更好的选择。它不仅不会为不需要的路由获取连接,而且如果您沿着任何不需要连接的代码路径,它也不会获取连接,即使路由中的其他代码路径需要一个连接。(例如,如果您有一些表单验证,则只有在验证通过时才需要连接;验证失败时不会打开连接。)您只在使用此设置之前获取连接。

However, you can avoid messing with the internals and still get all these benefits. Personally, I created my own little global methods:

但是,您可以避免弄乱内部结构并仍然获得所有这些好处。就个人而言,我创建了自己的小全局方法:

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

Then, throughout the app, always get your connection via get_request_connection, just as you would your get_dbfunction. Straightforward and high efficiency. Basically, the best of both worlds.

然后,在整个应用程序中,始终通过 获得连接get_request_connection,就像您的get_db功能一样。简单直接,效率高。基本上,两全其美。

Edit:

编辑:

In retrospect, I really dislike the fact these are global methods, but I think the reason for it is because that's how Flask works: it gives you "globals" that actually point to thread-locals.

回想起来,我真的不喜欢这些是全局方法的事实,但我认为这是因为 Flask 就是这样工作的:它为您提供实际上指向线程局部变量的“全局变量”。

回答by tanveer

To preserve the database connection within the same flask session you may use the application context and assign database connection. If the connection breaks,the context will try to establish the connection back as it polls the connection object continuously.

要在同一个 Flask 会话中保留数据库连接,您可以使用应用程序上下文并分配数据库连接。如果连接中断,上下文将尝试重新建立连接,因为它会不断轮询连接对象。

from flask import Flask
application = Flask(__name__)


def connect_to_database():
  db_handler = SqliteDBConnect("uid={0};""pwd={1}".format(UID, PWD),
                                table_prefix="{}".format(TBL_PRFX))
  return db_handler

fd = {'_database': None}
def get_db():
  db = fd['_database']
  if not isinstance(db, SqliteDBConnect):
    fd['_database'] = connect_to_database()
    db = fd['_database']
return db

with application.app_context():
  #Get DB connection from application's context
  db = LocalProxy(lambda: get_db())