Model API (smells like django)

Models and their fields map directly to database tables and columns. Consider the following:

from peewee import *

db = SqliteDatabase('test.db')

# create a base model class that our application's models will extend
class BaseModel(Model):
    class Meta:
        database = db


class Blog(BaseModel):
    name = CharField() # <-- VARCHAR


class Entry(BaseModel):
    headline = CharField()
    content = TextField() # <-- TEXT
    pub_date = DateTimeField() # <-- DATETIME
    blog = ForeignKeyField() # <-- INTEGER referencing the Blog table

This is a typical example of how to specify models with peewee. There are several things going on:

  1. Create an instance of a Database

    db = SqliteDatabase('test.db')
    

    This establishes an object, db, which is used by the models to connect to and query the database. There can be multiple database instances per application, but, as I hope is obvious, ForeignKeyField related models must be on the same database.

  2. Create a base model class which specifies our database

    class BaseModel(Model):
        class Meta:
            database = db
    

    Model configuration is kept namespaced in a special class called Meta – this convention is borrowed from Django, which does the same thing. Meta configuration is passed on to subclasses, so this code basically allows all our project’s models to connect to our database.

  3. Declare a model or two

    class Blog(BaseModel):
        name = CharField()
    

    Model definition is pretty similar to django or sqlalchemy – you basically define a class which represents a single table in the database, then its attributes (which are subclasses of Field) represent columns.

    Models provide methods for creating/reading/updating/deleting rows in the database.

Creating tables

In order to start using these models, its necessary to open a connection to the database and create the tables first:

# connect to our database
db.connect()

# create the tables
Blog.create_table()
Entry.create_table()

Note

Strictly speaking, the explicit call to connect() is not necessary, but it is good practice to be explicit about when you are opening and closing connections.

Model instances

Assuming you’ve created the tables and connected to the database, you are now free to create models and execute queries.

Creating models in the interactive interpreter is a snap.

  1. Use the Model.create() classmethod:

    >>> blog = Blog.create(name='Funny pictures of animals blog')
    >>> entry = Entry.create(
    ...     headline='maru the kitty',
    ...     content='http://www.youtube.com/watch?v=xdhLQCYQ-nQ',
    ...     pub_date=datetime.datetime.now(),
    ...     blog=blog
    ... )
    
    >>> entry.blog.name
    'Funny pictures of animals blog'
    
  2. Build up the instance programmatically:

    >>> blog = Blog()
    >>> blog.name = 'Another sweet blog'
    >>> blog.save()
    

Traversing foriegn keys

As you can see from above, the foreign key from Entry to Blog can be traversed automatically:

>>> entry.blog.name
'Funny pictures of animals blog'

The reverse is also true, we can iterate a Blog objects associated Entries:

>>> for entry in blog.entry_set:
...     print entry.headline
...
maru the kitty

Under the hood, the entry_set attribute is just a SelectQuery:

>>> blog.entry_set
<peewee.SelectQuery object at 0x151f510>

>>> blog.entry_set.sql()
('SELECT * FROM entry WHERE blog_id = ?', [1])

Model options

In order not to pollute the model namespace, model-specific configuration is placed in a special class called Meta, which is a convention borrowed from the django framework:

from peewee import *

custom_db = SqliteDatabase('custom.db')

class CustomModel(Model):
    class Meta:
        database = custom_db

This instructs peewee that whenever a query is executed on CustomModel to use the custom database.

Note

Take a look at the sample models - you will notice that we created a BaseModel that defined the database, and then extended. This is the preferred way to define a database and create models.

There are several options you can specify as Meta attributes:

  • database: specifies a Database instance to use with this model
  • db_table: the name of the database table this model maps to
  • ordering: a sequence of columns to use as the default ordering for this model
  • pk_sequence: name of sequence to create for the primary key (peewee will autogenerate one
    if not provided and the backend supports sequences).

Example of ordering:

class Entry(Model):
    title = CharField()
    body = TextField()
    created = DateTimeField()

    class Meta:
        # order by created date descending, then title ascending
        ordering = (('created', 'desc'), 'title')

Note

These options are “inheritable”, which means that you can define a database adapter on one model, then subclass that model and the child models will use that database.

my_db = PostgresqlDatabase('my_db')

class BaseModel(Model):
    class Meta:
        database = my_db

class SomeModel(BaseModel):
    field1 = CharField()

    class Meta:
        ordering = ('field1',)
        # no need to define database again since it will be inherited from
        # the BaseModel

Model methods

class Model
save()

Save the given instance, creating or updating depending on whether it has a primary key.

example:

>>> some_obj.title = 'new title' # <-- does not touch the database
>>> some_obj.save() # <-- change is persisted to the db
classmethod create(**attributes)
Parameters:attributes – key/value pairs of model attributes

Create an instance of the Model with the given attributes set.

example:

>>> user = User.create(username='admin', password='test')
delete_instance([recursive=False])

Delete the given instance. Any foreign keys set to cascade on delete will be deleted automatically. For more programmatic control, you can call with recursive=True, which will delete any non-nullable related models (those that are nullable will be set to NULL).

example:

>>> some_obj.delete_instance() # <-- it is gone forever
classmethod filter(*args, **kwargs)
Parameters:
  • args – a list of Q or Node objects
  • kwargs – a mapping of column + lookup to value, e.g. “age__gt=55”
Return type:

SelectQuery with appropriate WHERE clauses

Provides a django-like syntax for building a query. The key difference between filter() and SelectQuery.where() is that filter() supports traversing joins using django’s “double-underscore” syntax:

>>> sq = Entry.filter(blog__title='Some Blog')

This method is chainable:

>>> base_q = User.filter(active=True)
>>> some_user = base_q.filter(username='charlie')
classmethod get(*args, **kwargs)
Parameters:
  • args – a list of Q or Node objects
  • kwargs – a mapping of column + lookup to value, e.g. “age__gt=55”
Return type:

Model instance or raises DoesNotExist exception

Get a single row from the database that matches the given query. Raises a <model-class>.DoesNotExist if no rows are returned:

>>> user = User.get(username=username, password=password)

This method is also expose via the SelectQuery:

>>> active = User.select().where(active=True)
>>> try:
...     user = active.get(username=username, password=password)
... except User.DoesNotExist:
...     user = None
classmethod get_or_create(**attributes)
Parameters:attributes – key/value pairs of model attributes
Return type:a Model instance

Get the instance with the given attributes set. If the instance does not exist it will be created.

example:

>>> CachedObj.get_or_create(key=key, val=some_val)
classmethod select(query=None)
Return type:a SelectQuery for the given Model

example:

>>> User.select().where(active=True).order_by('username')
classmethod update(**query)
Return type:an UpdateQuery for the given Model

example:

>>> q = User.update(active=False).where(registration_expired=True)
>>> q.sql()
('UPDATE user SET active=? WHERE registration_expired = ?', [0, 1])
>>> q.execute() # <-- execute it
classmethod delete(**query)
Return type:a DeleteQuery for the given Model

example:

>>> q = User.delete().where(active=False)
>>> q.sql()
('DELETE FROM user WHERE active = ?', [0])
>>> q.execute() # <-- execute it

Warning

Assume you have a model instance – calling model_instance.delete() does not delete it.

classmethod insert(**query)
Return type:an InsertQuery for the given Model

example:

>>> q = User.insert(username='admin', active=True, registration_expired=False)
>>> q.sql()
('INSERT INTO user (username,active,registration_expired) VALUES (?,?,?)', ['admin', 1, 0])
>>> q.execute()
1
classmethod raw(sql, *params)
Return type:a RawQuery for the given Model

example:

>>> q = User.raw('select id, username from users')
>>> for user in q:
...     print user.id, user.username
classmethod create_table([fail_silently=False])
Parameters:fail_silently – If set to True, the method will check for the existence of the table before attempting to create.

Create the table for the given model.

example:

>>> database.connect()
>>> SomeModel.create_table() # <-- creates the table for SomeModel
classmethod drop_table([fail_silently=False])
Parameters:fail_silently – If set to True, the query will check for the existence of the table before attempting to remove.

Drop the table for the given model.

Note

Cascading deletes are not handled by this method, nor is the removal of any constraints.

classmethod table_exists()
Return type:Boolean whether the table for this model exists in the database