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 User(BaseModel):
    username = CharField()

class Tweet(BaseModel):
    user = ForeignKeyField(User, related_name='tweets')
    message = TextField()
    created_date = DateTimeField(default=datetime.datetime.now)
    is_published = BooleanField(default=True)

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 User(BaseModel):
        username = 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
User.create_table()
Tweet.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:

    >>> user = User.create(username='charlie')
    >>> tweet = Tweet.create(
    ...     message='http://www.youtube.com/watch?v=xdhLQCYQ-nQ',
    ...     user=user
    ... )
    
    >>> tweet.user.username
    'charlie'
    
  2. Build up the instance programmatically:

    >>> user = User()
    >>> user.username = 'charlie'
    >>> user.save()
    

Traversing foriegn keys

As you can see from above, the foreign key from Tweet to User can be traversed automatically:

>>> tweet.user.username
'charlie'

The reverse is also true, we can iterate a User objects associated Tweets:

>>> for tweet in user.tweets:
...     print tweet.message
...
http://www.youtube.com/watch?v=xdhLQCYQ-nQ

Under the hood, the tweets attribute is just a SelectQuery with the where clause prepopulated to point at the right User instance:

>>> user.tweets
<peewee.SelectQuery object at 0x151f510>

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
  • indexes: a list of fields to index
  • order_by: a sequence of columns to use as the default ordering for this model

Specifying indexes:

class Transaction(Model):
    from_acct = CharField()
    to_acct = CharField()
    amount = DecimalField()
    date = DateTimeField()

    class Meta:
        indexes = (
            # create a unique on from/to/date
            (('from_acct', 'to_acct', 'date'), True),

            # create a non-unique on from/to
            (('from_acct', 'to_acct'), False),
        )

Example of ordering:

class Tweet(Model):
    message = TextField()
    created = DateTimeField()

    class Meta:
        # order by created date descending
        ordering = ('-created',)

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([force_insert=False])

Save the given instance, creating or updating depending on whether it has a primary key. If force_insert=True an INSERT will be issued regardless of whether or not the primary key exists.

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_nullable=False]])
Parameters:
  • recursive – Delete this instance and anything that depends on it, optionally updating those that have nullable dependencies
  • delete_nullable – If doing a recursive delete, delete all dependent objects regardless of whether it could be updated to NULL

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). If you wish to delete all dependencies regardless of whether they are nullable, set delete_nullable=True.

example:

>>> some_obj.delete_instance() # <-- it is gone forever
classmethod get(*args, **kwargs)
Parameters:
  • args – a list of query expressions, e.g. Usre.username == 'foo'
  • 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(User.username == username, User.password == password)

This method is also expose via the SelectQuery, though it takes no parameters:

>>> active = User.select().where(User.active == True)
>>> try:
...     users = active.where(User.username == username, User.password == password)
...     user = users.get()
... except User.DoesNotExist:
...     user = None

Note

the “kwargs” style syntax is provided for compatibility with version 1.0. The expression-style syntax is preferable.

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(*selection)
Parameters:selection – a list of model classes, field instances, functions or expressions
Return type:a SelectQuery for the given Model

example:

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

example:

>>> q = User.update(active=False).where(User.registration_expired == True)
>>> q.execute() # <-- execute it
classmethod delete()
Return type:a DeleteQuery for the given Model

example:

>>> q = User.delete().where(User.active == False)
>>> 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.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 filter(*args, **kwargs)
Parameters:
  • args – a list of DQ 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')

Note

this method is provided for compatibility with peewee 1.0

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