对于 Web 应用程序,通常在收到请求时打开连接,并在传递响应时关闭连接。在本节中,我将描述如何向您的 Web 应用程序添加挂钩,以确保正确处理数据库连接。
这些步骤将确保无论您使用的是简单的 SQLite 数据库,还是多个 Postgres 连接池,peewee 都能正确处理连接。
笔记
接收大量流量的应用程序可能会受益于使用 连接池来降低在每个请求上建立和拆除连接的成本。
Flask 和 peewee 是一个很棒的组合,是任何规模项目的首选。Flask 提供了两个钩子,我们将使用它们来打开和关闭我们的数据库连接。我们将在收到请求时打开连接,然后在返回响应时关闭它。
from flask import Flask
from peewee import *
database = SqliteDatabase('my_app.db')
app = Flask(__name__)
# This hook ensures that a connection is opened to handle any queries
# generated by the request.
@app.before_request
def _db_connect():
database.connect()
# This hook ensures that the connection is closed when we've finished
# processing the request.
@app.teardown_request
def _db_close(exc):
if not database.is_closed():
database.close()
虽然 peewee 与 Django 一起使用的情况不太常见,但实际上两者都很容易使用。要使用 Django 管理您的 peewee 数据库连接,我认为最简单的方法是在您的应用程序中添加一个中间件。中间件应该是中间件列表中的第一个,以确保它在处理请求时首先运行,并在返回响应时最后运行。
如果您有一个名为my_blog的 django 项目,并且您的 peewee 数据库在模块中定义my_blog.db,您可以添加以下中间件类:
# middleware.py
from my_blog.db import database # Import the peewee database instance.
def PeeweeConnectionMiddleware(get_response):
def middleware(request):
database.connect()
try:
response = get_response(request)
finally:
if not database.is_closed():
database.close()
return response
return middleware
# Older Django < 1.10 middleware.
class PeeweeConnectionMiddleware(object):
def process_request(self, request):
database.connect()
def process_response(self, request, response):
if not database.is_closed():
database.close()
return response
为确保执行此中间件,请将其添加到您的settings模块中:
# settings.py
MIDDLEWARE_CLASSES = (
# Our custom middleware appears first in the list.
'my_blog.middleware.PeeweeConnectionMiddleware',
# These are the default Django 1.7 middlewares. Yours may differ,
# but the important this is that our Peewee middleware comes first.
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
# ... other Django settings ...
我自己没有使用过Bottle,但是查看文档我相信以下代码应该确保数据库连接得到正确管理:
# app.py
from bottle import hook #, route, etc, etc.
from peewee import *
db = SqliteDatabase('my-bottle-app.db')
@hook('before_request')
def _connect_db():
db.connect()
@hook('after_request')
def _close_db():
if not db.is_closed():
db.close()
# Rest of your bottle app goes here.
请参阅 应用程序处理器的文档。
db = SqliteDatabase('my_webpy_app.db')
def connection_processor(handler):
db.connect()
try:
return handler()
finally:
if not db.is_closed():
db.close()
app.add_processor(connection_processor)
看起来 Tornado 的RequestHandler类实现了两个钩子,可用于在处理请求时打开和关闭连接。
from tornado.web import RequestHandler
db = SqliteDatabase('my_db.db')
class PeeweeRequestHandler(RequestHandler):
def prepare(self):
db.connect()
return super(PeeweeRequestHandler, self).prepare()
def on_finish(self):
if not db.is_closed():
db.close()
return super(PeeweeRequestHandler, self).on_finish()
RequestHandler在您的应用程序中,现在您可以扩展默认值,而不是扩展PeeweeRequestHandler.
请注意,这并未解决如何将 peewee 与 Tornado 或其他事件循环异步使用。
连接处理代码可以放在中间件中。
def peewee_middleware(request, following):
db.connect()
try:
response = following(request)
finally:
if not db.is_closed():
db.close()
return response
app = WSGIApplication(middleware=[
lambda x: peewee_middleware,
# ... other middlewares ...
])
感谢 GitHub 用户@tuukkamustonen提交此代码。
连接处理代码可以放在中间件组件中。
import falcon
from peewee import *
database = SqliteDatabase('my_app.db')
class PeeweeConnectionMiddleware(object):
def process_request(self, req, resp):
database.connect()
def process_response(self, req, resp, resource, req_succeeded):
if not database.is_closed():
database.close()
application = falcon.API(middleware=[
PeeweeConnectionMiddleware(),
# ... other middlewares ...
])
设置一个处理数据库连接生命周期的请求工厂,如下所示:
from pyramid.request import Request
db = SqliteDatabase('pyramidapp.db')
class MyRequest(Request):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
db.connect()
self.add_finished_callback(self.finish)
def finish(self, request):
if not db.is_closed():
db.close()
在您的应用程序main()中,确保将MyRequest用作 request_factory:
def main(global_settings, **settings):
config = Configurator(settings=settings, ...)
config.set_request_factory(MyRequest)
请参阅发布/订阅模式。
def _db_connect():
db.connect()
def _db_close():
if not db.is_closed():
db.close()
cherrypy.engine.subscribe('before_request', _db_connect)
cherrypy.engine.subscribe('after_request', _db_close)
在 Sanic 中,连接处理代码可以放在请求和响应中间件sanic middleware中。
# app.py
@app.middleware('request')
async def handle_request(request):
db.connect()
@app.middleware('response')
async def handle_response(request, response):
if not db.is_closed():
db.close()
与 Flask 类似,FastAPI 提供了两个基于事件的钩子,我们将使用它们来打开和关闭我们的数据库连接。我们将在收到请求时打开连接,然后在返回响应时关闭它。
from fastapi import FastAPI
from peewee import *
db = SqliteDatabase('my_app.db')
app = FastAPI()
# This hook ensures that a connection is opened to handle any queries
# generated by the request.
@app.on_event("startup")
def startup():
db.connect()
# This hook ensures that the connection is closed when we've finished
# processing the request.
@app.on_event("shutdown")
def shutdown():
if not db.is_closed():
db.close()
在这里看不到您的框架?请打开 GitHub 票证,我会看到有关添加部分的信息,或者更好的是,提交文档拉取请求。
SQL 查询通常通过调用execute()使用查询构建器 API 构建的查询来执行(或者在查询的情况下通过简单地迭代查询对象Select)。对于希望直接执行 SQL 的情况,可以使用该Database.execute_sql()方法。
db = SqliteDatabase('my_app.db')
db.connect()
# Example of executing a simple query and ignoring the results.
db.execute_sql("ATTACH DATABASE ':memory:' AS cache;")
# Example of iterating over the results of a query using the cursor.
cursor = db.execute_sql('SELECT * FROM users WHERE status = ?', (ACTIVE,))
for row in cursor.fetchall():
# Do something with row, which is a tuple containing column data.
pass