Peewee - lightweight, flexible and very fast ORM in Python

  • Tutorial

I invite all djangists / alchemists to answer a little and read a free interpretation of the introductory tutorial and partially the Peewee documentation - stand-alone ORM, which is obligatory for acquaintance to any nutritionist and, in particular, to the flasker. Little is written about her, but in vain. It is very easy to make friends with Peewee, especially if you are already familiar with some ORM on ActiveRecord. More importantly, it’s nice to be friends with her :) Well, let's begin.

With pip:
pip install peewee

From the repository:
git clone cd peewee python install

python test

There is a binding for flask:
pip install flask-peewee

Definition of patterns or “smacks of junga”

All of the following code can be repeated one to one in an interactive interpreter or a separate script.

from peewee import *
db = SqliteDatabase('people.db')
class Person(Model):
    name = CharField()
    birthday = DateField()
    is_relative = BooleanField()
    class Meta:
        database = db  # модель будет использовать базу данных 'people.db'

There are many types of fields, for all occasions . Peewee takes on the conversion of Python objects to values ​​suitable for the database, and vice versa.

Initializing arguments

Each field takes the following initialization arguments:
  • null=False - is it possible to store null values;
  • index=False - whether to create an index for a given column in the database;
  • unique=False- whether to create a unique index for this column in the database. See also the chapter on composite indices ;
  • verbose_name=None - a string for human-readable representation of the field;
  • help_text=None - a line with auxiliary text for the field;
  • db_column=None - a string that explicitly sets the name of the column in the database for this field is used, for example, when working with the legacy database;
  • default=None - the default value for class fields during instantiation;
  • choices=None - a list or tuple of two-element tuples, where the first element is the value for the base, the second is the displayed value (similar to jang);
  • primary_key=False - whether to use this field as a primary key;
  • sequence=None - the sequence for filling the field (make sure that the backend supports this functionality);


For each table, you can write uniform metadata in class Meta:

databasemodel databaseYes
db_tablename of the table in which data will be storednot
indexeslist of fields to indexYes
order_bylist of fields to sort by defaultYes
primary_keycomposite primary key, an instance of the CompositeKey class, exampleYes
table_aliasalias tables for use in queriesnot

Let's try to set the relationship between the models through a foreign key. With peewee it is simple:

class Pet(Model):
    owner = ForeignKeyField(Person, related_name='pets')
    name = CharField()
    animal_type = CharField()
    class Meta:
        database = db  # модель будет использовать базу данных 'people.db'

Models are described, it remains to create the appropriate tables for them in the database:

>>> Person.create_table()
>>> Pet.create_table()

Work with data

For example, create a few people and get them pets:

>>> from datetime import date
>>> uncle_bob = Person(name='Bob', birthday=date(1960, 1, 15), is_relative=True)
>>>  # cохраним Боба в базе данных

Records can also be created directly using the Model.create () method without explicit save ():

>>> grandma = Person.create(name='Grandma', birthday=date(1935, 3, 1), is_relative=True)
>>> herb = Person.create(name='Herb', birthday=date(1950, 5, 5), is_relative=False)

We will please the granny with the surname:

>>> = 'Grandma L.'
>>>  # обновим запись grandma

Now we’ll generate some living creatures. Granny is allergic to cats, but the coat of arms has some problems :

>>> bob_kitty = Pet.create(owner=uncle_bob, name='Kitty', animal_type='cat')
>>> herb_fido = Pet.create(owner=herb, name='Fido', animal_type='dog')
>>> herb_mittens = Pet.create(owner=herb, name='Mittens', animal_type='cat')
>>> herb_mittens_jr = Pet.create(owner=herb, name='Mittens Jr', animal_type='cat')

At some point, Varezhka was tired of living with the Coat of Arms and, using the open window, he proudly ran into the sunset. Respecting his right to personal freedom, we will nevertheless delete the corresponding entry from the database:

>>> herb_mittens.delete_instance()  # удачи, Варежка

As you can see, the delete operation returns the number of deleted records, in this case - 1.

Uncle Bob decided that Gerba had so many animals and squeezed Fido out of him:

>>> herb_fido.owner = uncle_bob
>>> bob_fido = herb_fido  # переименуем переменную для лучшего соответствия суровой реальности


The selections are made directly with the class object and return SelectQuery instances (an analogue of QuerySet in the jung).

Retrieve a single record

To retrieve a single record, use the method SelectQuery.get():

>>> grandma = == 'Grandma L.').get()

The query can be shortened by substituting the argument directly in get():

>>> grandma = Person.get( == 'Grandma L.')

Retrieving Multiple Records

Let's go through all the instances with a Personcycle:

>>> for person in
...     print, person.is_relative
Bob True
Grandma L. True
Herb False

Let's go through the instances Personand all the records associated with them:

>>> for person in
...     print, person.pets.count(), 'pets'
...     for pet in person.pets:
...         print '    ',, pet.animal_type
Bob 2 pets
    Kitty cat
    Fido dog
Grandma L. 0 pets
Herb 1 pets
    Mittens Jr cat

We catch all cats and their owners (or vice versa?):

>>> for pet in == 'cat'):
...     print,
Kitty Bob
Mittens Jr Herb

Not without join'ov:

# выберем всех животных Боба
>>> for pet in == 'Bob'):
...     print

The same selection can be extracted in a different way - explicitly passing the object with Bob to the request:

>>> for pet in == uncle_bob):
...     print

Sort the selection in alphabetical order. To do this, we use the method SelectQuery.order_by():

>>> for pet in == uncle_bob).order_by(
...     print

Sort people by age:

>>> for person in
...     print
Grandma L.

Let's try a more complex query. Choose all people born
  • until 1940
  • after 1959

>>> d1940 = date(1940, 1, 1)
>>> d1960 = date(1960, 1, 1)
>>> for person in < d1940) | (Person.birthday > d1960)):
...     print
Grandma L.

The request where((Person.birthday < d1940) | (Person.birthday > d1960))can be written and how where(Person.birthday < d1940 or Person.birthday > d1960), but it is better not to do this, because peewee does not always correctly handle such a record.

And now the toroboan. Choose those born between 1940 and 1960:

>>> for person in > d1940) & (Person.birthday < d1960)):
...     print

And one last thing. We will use the SQL function and select all the people whose name begins with "G" in any register:

>>> for person in, 1, 1)) == 'g'):
...     print
Grandma L.

For selections, also use methods:
  • SelectQuery.group_by()
  • SelectQuery.having()
  • SelectQuery.limit() and SelectQuery.offset()

If you liked this short tutorial, be sure to visit the official documentation - there are a lot of interesting things, including recipes with solutions to common problems and a set of plugins that extend the basic functionality.


The authors on his blog were asked about the speed of ORM, to which he replied:

On my machine peewee has been faster than Django and SQA at most tasks, and about the same when iterating and returning Model instances.

On my computer, peewee outperformed Django and SQLAlchemy on most tasks, and showed comparable results on iterations and sample instances.

Then he published the results of the benchmark on the github. We tested common models and related via ForeignKey in various scenarios. Very curious .

Who cares, the source:

A good alternative to Alchemy, what do you think?

Also popular now: