Adding a new Database Driver

Peewee comes with built-in support for Postgres, MySQL and SQLite. Thesedatabases are very popular and run the gamut from fast, embeddable databases toheavyweight servers suitable for large-scale deployments. That being said,there are a ton of cool databases out there and adding support for yourdatabase-of-choice should be really easy, provided the driver supports theDB-API 2.0 spec.

The DB-API 2.0 spec should be familiar to you if you’ve used the standardlibrary sqlite3 driver, psycopg2 or the like. Peewee currently relies on ahandful of parts:

  • Connection.commit
  • Connection.execute
  • Connection.rollback
  • Cursor.description
  • Cursor.fetchone

These methods are generally wrapped up in higher-level abstractions and exposedby the Database, so even if your driver doesn’t do these exactlyyou can still get a lot of mileage out of peewee. An example is the apswsqlite driver in the “playhouse” module.

The first thing is to provide a subclass of Database that will opena connection.

  1. from peewee import Database
  2. import foodb # Our fictional DB-API 2.0 driver.
  3.  
  4.  
  5. class FooDatabase(Database):
  6. def _connect(self, database, **kwargs):
  7. return foodb.connect(database, **kwargs)

The Database provides a higher-level API and is responsible forexecuting queries, creating tables and indexes, and introspecting the databaseto get lists of tables. The above implementation is the absolute minimumneeded, though some features will not work – for best results you will want toadditionally add a method for extracting a list of tables and indexes for atable from the database. We’ll pretend that FooDB is a lot like MySQL andhas special “SHOW” statements:

  1. class FooDatabase(Database):
  2. def _connect(self, database, **kwargs):
  3. return foodb.connect(database, **kwargs)
  4.  
  5. def get_tables(self):
  6. res = self.execute('SHOW TABLES;')
  7. return [r[0] for r in res.fetchall()]

Other things the database handles that are not covered here include:

  • last_insert_id() and rows_affected()
  • param and quote, which tell theSQL-generating code how to add parameter placeholders and quote entity names.
  • field_types for mapping data-types like INT or TEXT totheir vendor-specific type names.
  • operations for mapping operations such as “LIKE/ILIKE” to their database equivalent

Refer to the Database API reference or the source code. for details.

Note

If your driver conforms to the DB-API 2.0 spec, there shouldn’t be muchwork needed to get up and running.

Our new database can be used just like any of the other database subclasses:

  1. from peewee import *
  2. from foodb_ext import FooDatabase
  3.  
  4. db = FooDatabase('my_database', user='foo', password='secret')
  5.  
  6. class BaseModel(Model):
  7. class Meta:
  8. database = db
  9.  
  10. class Blog(BaseModel):
  11. title = CharField()
  12. contents = TextField()
  13. pub_date = DateTimeField()