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 = peewee.CharField() # <-- VARCHAR
class Entry(BaseModel):
headline = peewee.CharField()
content = peewee.TextField() # <-- TEXT
pub_date = peewee.DateTimeField() # <-- DATETIME
blog = peewee.ForeignKeyField() # <-- INTEGER referencing the Blog table
This is a typical example of how to specify models with peewee. There are several things going on:
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.
Create a base model class which specifies our database
class BaseModel(Model): class Meta: database = dbModel 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.
Declare a model or two
class Blog(BaseModel): name = peewee.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.
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.
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.
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'
Build up the instance programmatically:
>>> blog = Blog() >>> blog.name = 'Another sweet blog' >>> blog.save()
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])
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
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
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
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 the given instance
example:
>>> some_obj.delete_instance() # <-- it is gone forever
Parameters: |
|
---|---|
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')
Parameters: |
|
---|---|
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
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)
Return type: | a SelectQuery for the given Model |
---|
example:
>>> User.select().where(active=True).order_by('username')
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
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.
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
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
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.
Return type: | Boolean whether the table for this model exists in the database |
---|