Framework Integration

For web applications, it is common to open a connection when a request is received, and to close the connection when the response is delivered. In this section I will describe how to add hooks to your web app to ensure the database connection is handled properly.

These steps will ensure that regardless of whether you’re using a simple SQLite database, or a pool of multiple Postgres connections, peewee will handle the connections correctly.

Note

Applications that receive lots of traffic may benefit from using a connection pool to mitigate the cost of setting up and tearing down connections on every request.

Flask

Flask and peewee are a great combo and my go-to for projects of any size. Flask provides two hooks which we will use to open and close our db connection. We’ll open the connection when a request is received, then close it when the response is returned.

  1. from flask import Flask
  2. from peewee import *
  3. database = SqliteDatabase('my_app.db')
  4. app = Flask(__name__)
  5. # This hook ensures that a connection is opened to handle any queries
  6. # generated by the request.
  7. @app.before_request
  8. def _db_connect():
  9. database.connect()
  10. # This hook ensures that the connection is closed when we've finished
  11. # processing the request.
  12. @app.teardown_request
  13. def _db_close(exc):
  14. if not database.is_closed():
  15. database.close()

Django

While it’s less common to see peewee used with Django, it is actually very easy to use the two. To manage your peewee database connections with Django, the easiest way in my opinion is to add a middleware to your app. The middleware should be the very first in the list of middlewares, to ensure it runs first when a request is handled, and last when the response is returned.

If you have a django project named my_blog and your peewee database is defined in the module my_blog.db, you might add the following middleware class:

  1. # middleware.py
  2. from my_blog.db import database # Import the peewee database instance.
  3. def PeeweeConnectionMiddleware(get_response):
  4. def middleware(request):
  5. database.connect()
  6. try:
  7. response = get_response(request)
  8. finally:
  9. if not database.is_closed():
  10. database.close()
  11. return response
  12. return middleware
  13. # Older Django < 1.10 middleware.
  14. class PeeweeConnectionMiddleware(object):
  15. def process_request(self, request):
  16. database.connect()
  17. def process_response(self, request, response):
  18. if not database.is_closed():
  19. database.close()
  20. return response

To ensure this middleware gets executed, add it to your settings module:

  1. # settings.py
  2. MIDDLEWARE_CLASSES = (
  3. # Our custom middleware appears first in the list.
  4. 'my_blog.middleware.PeeweeConnectionMiddleware',
  5. # These are the default Django 1.7 middlewares. Yours may differ,
  6. # but the important this is that our Peewee middleware comes first.
  7. 'django.middleware.common.CommonMiddleware',
  8. 'django.contrib.sessions.middleware.SessionMiddleware',
  9. 'django.middleware.csrf.CsrfViewMiddleware',
  10. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  11. 'django.contrib.messages.middleware.MessageMiddleware',
  12. )
  13. # ... other Django settings ...

Bottle

I haven’t used bottle myself, but looking at the documentation I believe the following code should ensure the database connections are properly managed:

  1. # app.py
  2. from bottle import hook #, route, etc, etc.
  3. from peewee import *
  4. db = SqliteDatabase('my-bottle-app.db')
  5. @hook('before_request')
  6. def _connect_db():
  7. db.connect()
  8. @hook('after_request')
  9. def _close_db():
  10. if not db.is_closed():
  11. db.close()
  12. # Rest of your bottle app goes here.

Web.py

See the documentation for application processors.

  1. db = SqliteDatabase('my_webpy_app.db')
  2. def connection_processor(handler):
  3. db.connect()
  4. try:
  5. return handler()
  6. finally:
  7. if not db.is_closed():
  8. db.close()
  9. app.add_processor(connection_processor)

Tornado

It looks like Tornado’s RequestHandler class implements two hooks which can be used to open and close connections when a request is handled.

  1. from tornado.web import RequestHandler
  2. db = SqliteDatabase('my_db.db')
  3. class PeeweeRequestHandler(RequestHandler):
  4. def prepare(self):
  5. db.connect()
  6. return super(PeeweeRequestHandler, self).prepare()
  7. def on_finish(self):
  8. if not db.is_closed():
  9. db.close()
  10. return super(PeeweeRequestHandler, self).on_finish()

In your app, instead of extending the default RequestHandler, now you can extend PeeweeRequestHandler.

Note that this does not address how to use peewee asynchronously with Tornado or another event loop.

Wheezy.web

The connection handling code can be placed in a middleware.

  1. def peewee_middleware(request, following):
  2. db.connect()
  3. try:
  4. response = following(request)
  5. finally:
  6. if not db.is_closed():
  7. db.close()
  8. return response
  9. app = WSGIApplication(middleware=[
  10. lambda x: peewee_middleware,
  11. # ... other middlewares ...
  12. ])

Thanks to GitHub user @tuukkamustonen for submitting this code.

Falcon

The connection handling code can be placed in a middleware component.

  1. import falcon
  2. from peewee import *
  3. database = SqliteDatabase('my_app.db')
  4. class PeeweeConnectionMiddleware(object):
  5. def process_request(self, req, resp):
  6. database.connect()
  7. def process_response(self, req, resp, resource, req_succeeded):
  8. if not database.is_closed():
  9. database.close()
  10. application = falcon.API(middleware=[
  11. PeeweeConnectionMiddleware(),
  12. # ... other middlewares ...
  13. ])

Pyramid

Set up a Request factory that handles database connection lifetime as follows:

  1. from pyramid.request import Request
  2. db = SqliteDatabase('pyramidapp.db')
  3. class MyRequest(Request):
  4. def __init__(self, *args, **kwargs):
  5. super().__init__(*args, **kwargs)
  6. db.connect()
  7. self.add_finished_callback(self.finish)
  8. def finish(self, request):
  9. if not db.is_closed():
  10. db.close()

In your application main() make sure MyRequest is used as request_factory:

  1. def main(global_settings, **settings):
  2. config = Configurator(settings=settings, ...)
  3. config.set_request_factory(MyRequest)

CherryPy

See Publish/Subscribe pattern.

  1. def _db_connect():
  2. db.connect()
  3. def _db_close():
  4. if not db.is_closed():
  5. db.close()
  6. cherrypy.engine.subscribe('before_request', _db_connect)
  7. cherrypy.engine.subscribe('after_request', _db_close)

Sanic

In Sanic, the connection handling code can be placed in the request and response middleware sanic middleware.

  1. # app.py
  2. @app.middleware('request')
  3. async def handle_request(request):
  4. db.connect()
  5. @app.middleware('response')
  6. async def handle_response(request, response):
  7. if not db.is_closed():
  8. db.close()

FastAPI

Similar to Flask, FastAPI provides two event based hooks which we will use to open and close our db connection. We’ll open the connection when a request is received, then close it when the response is returned.

  1. from fastapi import FastAPI
  2. from peewee import *
  3. db = SqliteDatabase('my_app.db')
  4. app = FastAPI()
  5. # This hook ensures that a connection is opened to handle any queries
  6. # generated by the request.
  7. @app.on_event("startup")
  8. def startup():
  9. db.connect()
  10. # This hook ensures that the connection is closed when we've finished
  11. # processing the request.
  12. @app.on_event("shutdown")
  13. def shutdown():
  14. if not db.is_closed():
  15. db.close()

Other frameworks

Don’t see your framework here? Please open a GitHub ticket and I’ll see about adding a section, or better yet, submit a documentation pull-request.