0% found this document useful (0 votes)
1K views

Using Pony in Flask

This document describes Pony ORM, an object-relational mapper (ORM) for Python. An ORM allows developers to work with database contents as objects rather than rows and tables. Pony ORM aims to provide a convenient syntax for writing queries using Python generator expressions that get translated to optimized SQL. The document covers getting started with Pony, defining entities and relationships, querying, transactions, and other features. It serves as a user guide for the Pony ORM library.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views

Using Pony in Flask

This document describes Pony ORM, an object-relational mapper (ORM) for Python. An ORM allows developers to work with database contents as objects rather than rows and tables. Pony ORM aims to provide a convenient syntax for writing queries using Python generator expressions that get translated to optimized SQL. The document covers getting started with Pony, defining entities and relationships, querying, transactions, and other features. It serves as a user guide for the Pony ORM library.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 90

Pony ORM

Release 0.6

March 23, 2015

Contents

What is Pony ORM?

Getting Started with Pony


2.1 Creating a database . . . . . . . . . . . . . . . . . .
2.2 Defining entities . . . . . . . . . . . . . . . . . . .
2.3 Mapping entities to database tables . . . . . . . . .
2.4 Late database binding . . . . . . . . . . . . . . . .
2.5 Using debug mode . . . . . . . . . . . . . . . . . .
2.6 Creating entity instances and populating the database
2.7 Writing queries . . . . . . . . . . . . . . . . . . . .
2.8 Getting objects . . . . . . . . . . . . . . . . . . . .
2.9 Updating an object . . . . . . . . . . . . . . . . . .
2.10 db_session . . . . . . . . . . . . . . . . . . . . . .
2.11 Writing SQL manually . . . . . . . . . . . . . . . .
2.12 Pony examples . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

3
3
3
5
5
5
6
6
8
9
9
10
10

Database
3.1 Creating a database object . . . . . . . . . . . . . . . .
3.2 Defining entities which are related to the database object
3.3 Binding the database object to a specific database . . . .
3.4 Database providers . . . . . . . . . . . . . . . . . . . .
3.5 Mapping entities to the database tables . . . . . . . . .
3.6 Early database binding . . . . . . . . . . . . . . . . . .
3.7 Methods and attributes of the Database object . . . . . .
3.8 Using Database object for raw SQL queries . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

11
11
11
12
12
13
14
14
18

Entities
4.1 Defining an entity . . .
4.2 Entity attributes . . . . .
4.3 Attribute data types . . .
4.4 Attribute options . . . .
4.5 Entity inheritance . . . .
4.6 Mapping customization

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

21
21
21
24
25
28
30

Relationships
5.1 One-to-many relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 Many-to-many relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3 One-to-one relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33
33
34
34

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

5.4
5.5
6

Self-references . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Multiple relationships between two entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34
35

Transactions
6.1 Working with database session . . . . . . . . . . . .
6.2 Functions for working with transactions . . . . . . .
6.3 Parameters of db_session . . . . . . . . . . . . . .
6.4 Optimistic concurrency control . . . . . . . . . . .
6.5 Pessimistic locking . . . . . . . . . . . . . . . . . .
6.6 Transaction isolation levels and database differences
6.7 How Pony avoids lost updates . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

37
37
39
40
40
41
42
43

Working with entity instances


7.1 Creating an entity instance . . . .
7.2 Loading objects from the database
7.3 Updating an object . . . . . . . .
7.4 Deleting an object . . . . . . . .
7.5 Entity class methods . . . . . . .
7.6 Entity instance methods . . . . .
7.7 Entity hooks . . . . . . . . . . .
7.8 Serializing entity instances . . . .
7.9 Using raw SQL . . . . . . . . . .
7.10 Saving objects in the database . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

45
45
45
48
49
50
52
54
55
57
57

Working with relationships


8.1 Establishing a relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.2 Operations with collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61
61
62

Queries
9.1 Pony ORM functions used to query the database
9.2 Query object methods . . . . . . . . . . . . . .
9.3 Automatic DISTINCT . . . . . . . . . . . . . .
9.4 Functions which can be used inside Query . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

10 Aggregation
10.1 Several aggregate functions in one query
10.2 Grouping . . . . . . . . . . . . . . . . .
10.3 Function count . . . . . . . . . . . . .
10.4 Conditional COUNT . . . . . . . . . . .
10.5 More complex grouping options . . . . .
10.6 Queries with HAVING . . . . . . . . . .
10.7 Query optimization . . . . . . . . . . . .
10.8 Aggregation queries with sorting . . . .

ii

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

69
69
72
77
78

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

79
80
80
80
81
81
82
82
83

CHAPTER 1

What is Pony ORM?

The acronym ORM stands for object-relational mapper. An ORM allows developers to work with the contents of a
database in the form of objects. A relational database contains rows that are stored in tables. However, when writing
a program in a high level object-oriented language, it is considerably more convenient when the data retrieved from
the database can be accessed in the form of objects. Pony ORM is a library for Python language that allows you to
conveniently work with objects which are stored as rows in a relational database.
There are other popular mappers implemented in Python such as Django and SQLAlchemy, but we propose that Pony
has certain distinct advantages:
An exceptionally convenient syntax for writing queries
Automatic query optimization
An elegant solution for the N+1 problem
A graphical database schema editor
In comparison to Django, Pony supports:
The IdentityMap pattern
Automatic transaction management
Automatic caching of queries and objects
Full support of composite keys
The ability to easily write queries using LEFT JOIN, HAVING and other features of SQL
One interesting feature of Pony is that it allows you to interact with databases in pure Python in the form of generator
expressions, which are then translated into SQL. Such queries may easily be written by a programmer familiar with
Python, even without being a database expert. The following is an example of such a query:
select(c for c in Customer if sum(c.orders.total_price) > 1000)

In this query, we would like to retrieve all customers with total purchases greater than 1000. select is a function
provided by Pony ORM. The function receives a generator expression that helps describe the query to the database.
Usually generators are executed in Python, but if such a generator is indicated inside the function select, then it will
be automatically translated to SQL and then executed inside the database. Customer is a entity class that is initially
described when the application is created, and corresponds to a table in the database.
Not every object-relational mapper offers such a convenient query syntax. In addition to ease of use, Pony ensures
efficient work with data. Queries are translated into SQL that is executed quickly and efficiently. Depending on the
DBMS, the syntax of the generating SQL may differ in order to take full advantage of the chosen database. The query
code written in Python will look the same regardless of the DBMS, which ensures the applications portability.

Pony ORM, Release 0.6

Pony allows any programmer to write complex and effective queries against a database, even without being an expert
in SQL. At the same time, Pony does not fight with SQL if a programmer needs to write a query in pure SQL,
for example to call up a stored procedure, they can easily do this from within Pony. The basic objective of Pony is to
simplify the development of web applications. A typical scenario in which Pony is used is generation of a dynamic
web page.
Pony ORM team can be reached by the email: team (at) ponyorm.com.

Chapter 1. What is Pony ORM?

CHAPTER 2

Getting Started with Pony

To install Pony, type the following command into the command prompt:
pip install pony

Pony may be installed on Python 2 beginning with version 2.6, and has no external dependencies.
To make sure Pony has been successfully installed, launch a Python interpreter in interactive mode and type:
>>> from pony.orm import *

This imports the entire (and not very large) set of classes and functions necessary for working with Pony. Eventually
you can choose what to import, but we recommend using import * at first.
The best way to become familiar with Pony is to play around with it in interactive mode. Lets create a sample database
containing the entity class Person, add three objects to it, and write a query.

2.1 Creating a database


Entities in Pony are connected to the database; this is why we first need to create the database object. In the Python
interpreter, type:
>>> db = Database(sqlite, :memory:)

This command creates the connection object for the database. Its first parameter specifies the DBMS we want to work
with. Currently Pony supports 4 types of databases: sqlite, mysql, postgresql and oracle. The
subsequent parameters are specific to each DBMS; they are the same ones you would use if you were connecting to
the database through the DB-API module. For sqlite, either the filename of the database or the string :memory: must
be indicated as a parameter, depending on where the database is being created. If the database is created in-memory,
it will be deleted once the interactive session in Python is closed. In order to work with a database stored in a file, you
can replace the previous line with the following:
>>> db = Database(sqlite, test_db.sqlite, create_db=True)

In this case, if the database file does not exist, it will be created. In our example, we can use a database created
in-memory.

2.2 Defining entities


Now, lets create two entities Person and Car. The entity Person has two attributes name and age, and Car has
attributes make and model. The two entities have a one-to-many relationship. In the Python interpreter, type the
3

Pony ORM, Release 0.6

following code:
>>> class Person(db.Entity):
...
name = Required(str)
...
age = Required(int)
...
cars = Set("Car")
...
>>> class Car(db.Entity):
...
make = Required(str)
...
model = Required(str)
...
owner = Required(Person)
...
>>>

The classes that we have created are derived from db.Entity. It means that they are not ordinary classes, but
entities whose instances are stored in the database that the db variable points to. Pony allows you to work with several
databases at the same time, but each entity belongs to one specific database.
Inside the entity Person we have created three attributes name, age and cars. name and age are mandatory
attributes; in other words, they cant have the value None. name is an alphanumeric attribute, while age is numeric.
The cars attribute has the type Car which means that this is a relationship. It can store a collection of instances of
Car entity. "Car" is specified as a string here because we didnt declare the entity Car by that moment yet.
The entity Car has three mandatory attributes. make and model are strings and owner is the other side of the
one-to-many relationship. Relationships in Pony are always defined by two attributes which represent both sides of a
relationship.
If we need to create a many-to-many relationship between two entities, then we should declare two Set attributes at
both ends. Pony creates the intermediate table automatically.
The str type is used for representing an unicode string in Python 3. Python 2 has two types for representing strings
- str and unicode. Starting with the Pony Release 0.6, you can use either str or unicode for string attributes,
both of them mean an unicode string. We recommend to use str for string attributes, because it looks more natural
in Python 3.
If you need to see an entity definition in the interactive mode, you can use the show() function. Pass an entity class
to this function in order to see the entity description:
>>> show(Person)
class Person(Entity):
id = PrimaryKey(int, auto=True)
name = Required(str)
age = Required(int)
cars = Set(Car)

You may notice that the entity got one extra attribute named id. Why did that happen?
Each entity must contain a primary key, which allows you to distinguish one entity from another. Since we have not
set the primary key manually, it was created automatically. If the primary key is created automatically, it is named id
and has a numeric format. If the key is created manually, it can be named in any way and can be either numeric or
text. Pony also supports compound primary keys.
When the primary key is created automatically, it always has the option auto set to True. It means that the value for
this attribute will be assigned automatically using the databases incremental counter or sequence.

Chapter 2. Getting Started with Pony

Pony ORM, Release 0.6

2.3 Mapping entities to database tables


Now we need to create tables to store the objects data. For this purpose, we need to call the following method on the
Database object:
>>> db.generate_mapping(create_tables=True)

The parameter create_tables=True indicates that, if the tables do not already exist, then they will be created
using the CREATE TABLE command.
All entities connected to the database must be specified before calling generate_mapping() method.

2.4 Late database binding


Starting with Pony release 0.5 there is an alternative way of specifying the database parameters. Now you can create
a database object first and then, after you declare entities, bind it to a specific database:
### module my_project.my_entities.py
from pony.orm import *
db = Database()
class Person(db.Entity):
name = Required(str)
age = Required(int)
cars = Set("Car")
class Car(db.Entity):
make = Required(str)
model = Required(str)
owner = Required(Person)
### module my_project.my_settings.py
from my_project.my_entities import db
db.bind(sqlite, test_db.sqlite, create_db=True)
db.generate_mapping(create_tables=True)

This way you can separate entity definition from mapping it to a particular database. It can be useful for testing.

2.5 Using debug mode


Pony allows you to see on the screen (or in a log file, if configured) the SQL commands that it sends to the database.
In order to turn on this mode, type:
>>> sql_debug(True)

If this command is executed before calling generate_mapping(), then during the creation of the tables, you will
see the SQL code used to generate the tables.
Be default Pony sends debug information to stdout. If you have the standard Python logging configured, Pony will use
it instead of stdout. Using Python logging you can store debug information in a file:
import logging
logging.basicConfig(filename=pony.log, level=logging.INFO)

2.3. Mapping entities to database tables

Pony ORM, Release 0.6

Note, that we had to specify the level=logging.INFO because the default standard logging level is WARNING and Pony uses the INFO level for its messages by default. Pony uses two loggers: pony.orm.sql for SQL
statements that it sends to the database and pony.orm for all other messages.

2.6 Creating entity instances and populating the database


Now, lets create five objects that describe three persons and two cars, and save this information in the database. To do
this, we execute the following commands:
>>>
>>>
>>>
>>>
>>>
>>>

p1 = Person(name=John, age=20)
p2 = Person(name=Mary, age=22)
p3 = Person(name=Bob, age=30)
c1 = Car(make=Toyota, model=Prius, owner=p2)
c2 = Car(make=Ford, model=Explorer, owner=p3)
commit()

Pony does not save objects in the database as soon as they are created, instead they are saved only after the commit()
command is executed. If the debug mode is turned on before executing commit(), then you will see the five INSERT
commands used to store the objects in the database.

2.7 Writing queries


Now that we have a database with five objects saved in it, we can try some queries. For example, this is the query
which returns a list of persons who are older than twenty years old:
>>> select(p for p in Person if p.age > 20)
<pony.orm.core.Query at 0x105e74d10>

The select function translates the Python generator into a SQL query and returns an instance of the Query class.
This SQL query will be sent to the database once we start iterating over the query. One of the ways to get the list of
objects is to apply the slice operator [:] to it:
>>> select(p for p in Person if p.age > 20)[:]
SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
WHERE "p"."age" > 20
[Person[2], Person[3]]

As the result you will see the text of the SQL query which was sent to the database and the list of extracted objects.
When we print out the query result, an entity instance is represented by the entity name and its primary key written in
square brackets: Person[2].
To order the resulting list we can use the order_by method of the query. And if we need only a portion of the result
set, we can achieve this by using the slice operator as we would on a Python list. For example, if we want to sort all
people by name and extract the first two objects, we can write:
>>> select(p for p in Person).order_by(Person.name)[:2]
SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
ORDER BY "p"."name"
LIMIT 2

Chapter 2. Getting Started with Pony

Pony ORM, Release 0.6

[Person[3], Person[1]]

Sometimes, when working in interactive mode, we want to see the values of all object attributes represented as a table.
In order to do this, we can use the .show() method of the query result list:
>>> select(p for p in Person).order_by(Person.name)[:2].show()
SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
ORDER BY "p"."name"
LIMIT 2
id|name|age
--+----+--3 |Bob |30
1 |John|20

The .show() method doesnt display to-many attributes because it would require additional query to the database
and could be bulky. That is why you can see no information about the related cars above. But if an instance has a
to-one relationship, then it will be displayed:
>>> Car.select().show()
id|make |model
|owner
--+------+--------+--------1 |Toyota|Prius
|Person[2]
2 |Ford |Explorer|Person[3]

If we dont want to get a list of objects, but need to iterate over the resulting sequence, we can use the for loop
without using the slice operator:
>>> persons = select(p for p in Person if o in p.name)
>>> for p in persons:
...
print p.name, p.age
...
SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
WHERE "p"."name" LIKE %o%
John 20
Bob 30

In the example above we get all Person objects where the name attribute contains the letter o and display their name
and age.
A query does not necessarily have to return entity objects only. For example, we can get a list of object attributes:
>>> select(p.name for p in Person if p.age != 30)[:]
SELECT DISTINCT "p"."name"
FROM "Person" "p"
WHERE "p"."age" <> 30
[uJohn, uMary]

Or a tuple:
>>> select((p, count(p.cars)) for p in Person)[:]
SELECT "p"."id", COUNT(DISTINCT "car-1"."id")

2.7. Writing queries

Pony ORM, Release 0.6

FROM "Person" "p"


LEFT JOIN "Car" "car-1"
ON "p"."id" = "car-1"."owner"
GROUP BY "p"."id"
[(Person[1], 0), (Person[2], 1), (Person[3], 1)]

In the example above we get a list of tuples consisting of a person and the number of cars they own.
You can also run aggregate queries. Here is an example of a query which returns the maximum persons age:
>>> print max(p.age for p in Person)
SELECT MAX("p"."age")
FROM "Person" "p"
30

Pony allows you to write queries that are much more complex than the ones we have examined so far. You can read
more on this in later sections of this manual.

2.8 Getting objects


To get an object by its primary key you specify the primary key value in square brackets:
>>> p1 = Person[1]
>>> print p1.name
John

You may notice that no query was sent to the database. That happened because this object is already present in the
database session cache. Caching reduces the number of requests that need to be sent to the database.
Getting objects by other attributes:
>>> mary = Person.get(name=Mary)
SELECT "id", "name", "age"
FROM "Person"
WHERE "name" = ?
[uMary]
>>> print mary.age
22

In this case, even though the object had already been loaded to the cache, the query still had to be sent to the database
because name is not a unique key. The database session cache will only be used if we lookup an object by its primary
or unique key.
You can pass an entity instance to the function show() in order to display the entity class and attribute values:
>>> show(mary)
instance of Person
id|name|age
--+----+--2 |Mary|22

Chapter 2. Getting Started with Pony

Pony ORM, Release 0.6

2.9 Updating an object


>>> mary.age += 1
>>> commit()

Pony keeps track of changed attributes. When the operation commit() is executed, all objects that were updated
during the current transaction will be saved in the database. Pony saves only changed attributes.

2.10 db_session
When you work with Pythons interactive shell you dont need to worry about the database session because it is
maintained by Pony automatically. But when you use Pony in your application, all database interactions should be
done within a database session. In order to do that you need to wrap the functions that work with the database with
the @db_session decorator:
@db_session
def print_person_name(person_id):
p = Person[person_id]
print p.name
# database session cache will be cleared automatically
# database connection will be returned to the pool
@db_session
def add_car(person_id, make, model):
Car(make=make, model=model, owner=Person[person_id])
# commit() will be done automatically
# database session cache will be cleared automatically
# database connection will be returned to the pool

The @db_session decorator performs several very important actions upon function exit:
Performs rollback of transaction if the function raises an exception
Commits transaction if data was changed and no exceptions occurred
Returns the database connection to the connection pool
Clears the database session cache
Even if a function just reads data and does not make any changes, it should use the db_session in order to return
the connection to the connection pool.
The entity instances are valid only within the db_session. If you need to render an HTML template using those
objects, you should do this within the db_session.
Another option for working with the database is using db_session as the context manager instead of the decorator:
with db_session:
p = Person(name=Kate, age=33)
Car(make=Audi, model=R8, owner=p)
# commit() will be done automatically
# database session cache will be cleared automatically
# database connection will be returned to the pool

2.9. Updating an object

Pony ORM, Release 0.6

2.11 Writing SQL manually


If you need to write an SQL query manually, you can do it this way:
>>> x = 25
>>> Person.select_by_sql(SELECT * FROM Person p WHERE p.age < $x)
SELECT * FROM Person p WHERE p.age < ?
[25]
[Person[1], Person[2]]

If you want to work with the database directly, avoiding entities altogether, you can use the select() method on the
Database object:
>>> x = 20
>>> db.select(name FROM Person WHERE age > $x)
SELECT name FROM Person WHERE age > ?
[20]
[uMary, uBob]

2.12 Pony examples


Instead of creating models manually, it may be easier to get familiar with Pony by importing some ready-made examples for instance, a simplified model of an online store. You can view the diagram for this example on the Pony
website at this address: https://editor.ponyorm.com/user/pony/eStore
To import the example:
>>> from pony.orm.examples.estore import *

At the initial launch, an SQLite database will be created with all the necessary tables. In order to populate it with the
sample data, you can execute the following function, as indicated in the example file:
>>> populate_database()

This function will create objects and place them in the database.
After the objects have been created, you can write a query. For example, you can find the country with the most
customers:
>>> select((customer.country, count(customer))
...
for customer in Customer).order_by(-2).first()
SELECT "customer"."country", COUNT(DISTINCT "customer"."id")
FROM "Customer" "customer"
GROUP BY "customer"."country"
ORDER BY 2 DESC
LIMIT 1

In this case, we are grouping objects by country, sorting them by the second column (quantity of customers) in reverse
order, and then extracting the country with the highest number of customers.
You can find more query examples in the test_queries() function from the pony.orm.examples.estore
module.

10

Chapter 2. Getting Started with Pony

CHAPTER 3

Database

Before you can start working with entities you have to create a Database object. This object manages database
connections using a connection pool. The Database object is thread safe and can be shared between all threads in
your application. The Database object allows you to work with the database directly using SQL, but most of the
time you will work with entities and let Pony generate SQL statements in order to make the corresponding changes in
the database. Pony allows you to work with several databases at the same time, but each entity belongs to one specific
database.
Mapping entities to the database can be divided into four steps:
Creating a database object
Defining entities which are related to the database object
Binding the database object to a specific database
Mapping entities to the database tables

3.1 Creating a database object


At this step we simply create an instance of the Database class:
db = Database()

Although you can pass the database connection parameters right here, often it is more convenient to do it at a later
stage using the db.bind() method. This way you can use different databases for testing and production.
The Database instance has an attribute Entity which represents a base class to be used for entities declaration.

3.2 Defining entities which are related to the database object


Entities should inherit from the base class of the Database object:
class MyEntity(db.Entity):
attr1 = Required(str)

Well talk about entities definition in detail in the next chapter. Now, lets see the next step in mapping entities to a
database.

11

Pony ORM, Release 0.6

3.3 Binding the database object to a specific database


Before we can map entities to a database, we need to connect to the database. At this step we should use the bind()
method:
db.bind(postgres, user=, password=, host=, database=)

The first parameter of this method is the name of the database provider. The database provider is a module which
resides in the pony.orm.dbproviders package and which knows how to work with a particular database. After
the database provider name you should specify parameters which will be passed to the connect() method of the
corresponding DBAPI driver.

3.4 Database providers


Currently Pony can work with four database systems: SQLite, PostgreSQL, MySQL and Oracle, with the corresponding Pony provider names: sqlite, postgres, mysql and oracle. Pony can easily be extended to
incorporate additional database providers.
During the bind() call, Pony tries to establish a test connection to the database. If the specified parameters are
not correct or the database is not available, an exception will be raised. After the connection to the database was
established, Pony retrieves the version of the database and returns the connection to the connection pool.

3.4.1 SQLite
Using SQLite database is the easiest way to work with Pony because there is no need to install a database system
separately - the SQLite database system is included in the Python distribution. It is a perfect choice for beginners who
want to experiment with Pony in the interactive shell. In order to bind the Database object a SQLite database you
can do the following:
db.bind(sqlite, filename, create_db=True)

Here filename is the name of the file where SQLite will store the data. The filename can be absolute or relative.
Note: If you specify a relative path, that path is appended to the directory path of the Python file where this database
was created (and not to the current working directory). We did it this way because sometimes a programmer doesnt
have the control over the current working directory (e.g. in mod_wsgi application). This approach allows the programmer to create applications which consist of independent modules, where each module can work with a separate
database.
When working in the interactive shell, Pony requires that you to always specify the absolute path of the storage file.
If the parameter create_db is set to True then Pony will try to create the database if such filename doesnt exists.
Default value for create_db is False.
Note: Normally SQLite database is stored in a file on disk, but it also can be stored entirely in memory. This is a
convenient way to create a SQLite database when playing with Pony in the interactive shell, but you should remember,
that the entire in-memory database will be lost on program exit. Also you should not work with the same in-memory
SQLite database simultaneously from several threads because in this case all threads share the same connection due to
SQLite limitation.
In order to bind with an in-memory database you should specify :memory: instead of the filename:
db.bind(sqlite, :memory:)

12

Chapter 3. Database

Pony ORM, Release 0.6

There is no need in the parameter create_db when creating an in-memory database.


Note: By default SQLite doesnt check foreign key constraints. Pony always enables the foreign key support by
sending the command PRAGMA foreign_keys = ON; starting with the release 0.4.9.

3.4.2 PostgreSQL
Pony uses psycopg2 driver in order to work with PostgreSQL. In order to bind the Database object to PostgreSQL
use the following line:
db.bind(postgres, user=, password=, host=, database=)

All the parameters that follow the Pony database provider name will be passed to the psycopg2.connect()
method. Check the psycopg2.connect documentation in order to learn what other parameters you can pass to this
method.

3.4.3 MySQL
db.bind(mysql, host=, user=, passwd=, db=)

Pony tries to use the MySQLdb driver for working with MySQL. If this module cannot be imported, Pony tries to use
pymysql. See the MySQLdb and pymysql documentation for more information regarding these drivers.

3.4.4 Oracle
db.bind(oracle, user/password@dsn)

Pony uses cx_Oracle driver for connecting to Oracle databases. More information about the parameters which you can
use for creating a connection to Oracle database can be found here.

3.5 Mapping entities to the database tables


After the Database object is created, entities are defined, and a database is bound, the next step is to map entities to
the database tables:
db.generate_mapping(check_tables=True, create_tables=False)

If the parameter create_tables is set to True then Pony will try to create tables if they dont exist. The default
value for create_tables is False because in most cases tables already exist. Pony generates the names of the
database tables and columns automatically, but you can override this behavior if you want. See more details in the
Mapping customization chapter. Also this parameter makes Pony to check if foreign keys and indexes exist and create
them if they are missing.
After the create_tables option is processed, Pony does a simple check: it sends SQL queries to the database
which check that all entity tables and column names exist. At the same time this check doesnt catch situations when
the table has extra columns or when the type of a particular column doesnt match. You can switch this check off
by passing the parameter check_tables=False. It can be useful when you want to generate mapping and create
tables for your entities later, using the method db.create_tables().
The method db.create_tables() checks the existing mapping and creates tables for entities if they dont exist.
Also, Pony checks if foreign keys and indexes exist and create them if they are missing.
3.5. Mapping entities to the database tables

13

Pony ORM, Release 0.6

3.6 Early database binding


You can combine the steps Creating a database object and Binding the database object to a specific database into
one step by passing the database parameters during the database object creation:
db = Database(sqlite, filename, create_db=True)
db = Database(postgres, user=, password=, host=, database=)
db = Database(mysql, host=, user=, passwd=, db=)
db = Database(oracle, user/password@dsn)

It is the same set of parameters which you can pass to the bind() method. If you pass the parameters during the
creation of the Database object, then there is no need in calling the bind() method later - the database will be
already bound to the instance.

3.7 Methods and attributes of the Database object


class Database
generate_mapping(check_tables=True, create_tables=False)
Map declared entities to the corresponding tables in the database. create_tables=True - create
tables, foreign key references and indexes if they dont exist. check_tables=False - switch the table
checks off. This check only verifies if the table name and attribute names match. It doesnt catch situations
when the table has extra columns or when the type of a particular column doesnt match.
create_tables()
Check the existing mapping and create tables for entities if they dont exist. Also, Pony checks if foreign
keys and indexes exist and create them if they are missing.
drop_all_tables(with_all_data=False)
Drop all tables which are related to the current mapping. When this method is called without parameters,
Pony will drop tables only if none of them contain any data. In case at least one of them is not empty the
method will raise the TableIsNotEmpty exception without dropping any table. In order to drop tables
with the data you should pass the parameter with_all_data=True.
drop_table(table_name, if_exists=False, with_all_data=False)
Drops the table_name table.
If such table doesnt exist the method raises the exception
TableDoesNotExist. Note, that the table_name is case sensitive.
You can pass the entity class as the table_name parameter. In this case Pony will try to delete the table
associated with the entity.
If the parameter if_exists is set to True, then it will not raise the TableDoesNotExist exception if there is no such table in the database. If the table is not empty the method will raise the
TableIsNotEmpty exception.
In order to drop tables with the data you should pass the parameter with_all_data=True.
If you need to delete the table which is mapped to an entity, you should use the method drop_table()
of an entity: it will use the right letter case for the entity table name.

14

Chapter 3. Database

Pony ORM, Release 0.6

3.7.1 Methods for working with transactions


class Database
commit()
Saves all changes which were made within the current db_session using the flush() method and
commits the transaction to the database.
A programmer can call commit() more than once within the same db_session. In this case the
db_session cache keeps the cached objects after commits. This allows Pony to use the same objects in
the transaction chain. The cache will be cleaned up when db_session is finished or the transaction is
rolled back.
rollback()
Rolls back the current transaction and clears the db_session cache.
flush()
Saves the changes accumulated in the db_session cache to the database. You may never have a need to
call this method manually. Pony always saves the changes accumulated in the cache automatically before
executing the following methods: select(), get(), exists(), execute() and commit().

3.7.2 Database object attributes


class Database
Entity
This attribute represents a base class which should be inherited by all entities which are mapped to the
particular database:
db = Database()
class Person(db.Entity):
name = Required(str)
age = Required(int)

last_sql
Read-only attribute which keeps the text of the last SQL statement. It can be used for debugging.

3.7.3 Methods for raw SQL access


class Database
select(sql)
Executes the SQL statement in the database and returns a list of tuples. Pony gets a database connection
from the connection pool and returns it after the query is completed. The word select can be omitted in
the SQL statement - Pony will add the select keyword automatically when it is necessary:
select("* from Person")

We did it because the method name speaks for itself and this way the query looks more concise. If the
query returns just one column, then, for the convenience, the result will be a list of values, not tuples:
db.select("name from Person")

3.7. Methods and attributes of the Database object

15

Pony ORM, Release 0.6

The method above returns: [John, Mary, Bob]


If a query returns more than one column and the names of table columns are valid Python identifiers, then
you can access them as attributes:
for row in db.select("name, age from Person"):
print row.name, row.age

Pony has a limit for the number of rows which can be returned by the select method. This limit
is specified by the pony.options.MAX_FETCH_COUNT parameter (1000 by default). If select
returns more than MAX_FETCH_COUNT rows Pony raises the TooManyRowsFound exception. You can
change this value, although we dont recommend doing this because if a query returns more than 1000
rows then it is likely that there is a problem with the application design. The results of select are stored
in memory and if the number of rows is very large, applications can face scalability problems.
Before executing select, Pony flushes all the changes from the cache using the flush() method.
get(sql)
Use the get method when you need to select one row or just one value from the database:
name = db.get("age from Person where id = $id")

The word select can be omitted in the SQL statement - Pony will add the select keyword automatically
if it is necessary. If the table Person has a row with the specified id, then the variable age will be assigned
with the corresponding value of int type. The get method assumes that the query returns exactly one
row. If the query returns nothing then Pony raises RowNotFound exception. If the query returns more
than one row, the exception MultipleRowsFound will be raised.
If you need to select more than one column you can do it this way:
name, age = db.get("name, age from Person where id = $id")

If your request returns a lot of columns then you can assign the resulting tuple of the get method to a
variable and work with it the same way as it is described in select method.
Before executing get, Pony flushes all the changes from the cache using the flush() method.
exists(sql)
The exists method is used in order to check if the database has at least one row with the specified
parameters. The result will be True or False:
if db.exists("* from Person where name = $name"):
print "Person exists in the database"

The word select can be omitted in the beginning of the SQL statement.
Before executing this method, Pony flushes all the changes from the cache using the flush() method.
insert(table_name, returning=None, **kwargs)
insert(entity, returning=None, **kwargs)
Insert new rows into a table. This command bypasses the identity map cache and can be used in order to
increase the performance when we need to create a lot of objects and not going to read them in the same
transaction. Also you can use the db.execute() method for this purpose. If you need to work with
those objects in the same transaction it is better to create instances of entities and have Pony to save them
in the database on commit().
table_name - is the name of the table into which the data will be inserted, the name is case sensitive.
Instead of the table_name you can use the entity class. In this case Pony will insert into the table
associated with the entity.

16

Chapter 3. Database

Pony ORM, Release 0.6

The returning parameter allows you to specify the name of the column that holds the automatically
generated primary key. If you want the insert method to return the value which is generated by the
database, you should specify the name of the primary key column:
new_id = db.insert("Person", name="Ben", age=33, returning=id)

execute(sql)
This method allows you to execute arbitrary (raw) SQL statements:
cursor = db.execute("""create table Person (
id integer primary key autoincrement,
name text,
age integer
)""")
name, age = "Ben", 33
cursor = db.execute("insert into Person (name, age) values ($name, $age)")

All the parameters can be passed into the query using the Pony unified way, independently of the DBAPI
provider, using the $ sign. In the example above we pass name and age parameters into the query.
It is possible to have a Python expressions inside the query text, for example:
x = 10
a = 20
b = 30
db.execute("SELECT * FROM Table1 WHERE column1 = $x and column2 = $(a + b)")

If you need to use the $ sign as a string literal inside the query, you need to escape it using another $ (put
two $ signs in succession: $$).
The method returns the DBAPI cursor. Before executing the provided SQL, Pony flushes all the changes
from the cache using the flush() method.
get_connection()
Get an active database connection. It can be useful if you want to work with the DBAPI interface directly.
This is the same connection which is used by the ORM itself. The connection will be reset and returned
to the connection pool on leaving the db_session context or when the database transaction rolls back.
This connection can be used only within the db_session scope where the connection was obtained.
disconnect()
Close the database connection for the current thread if it was opened.

3.7.4 Database statistics


class Database
The Database object keeps statistics on executed queries. You can check which queries were executed more
often and how long it took to execute them as well as many other parameters. Pony keeps all statistics separately for each thread. If you want to see the aggregated statistics for all threads then you need to call the
merge_local_stats() method.
local_stats
This is a dictionary which keeps the SQL query statistics for the current thread. The key of this dictionary
is the SQL statement and the value is an object of the QueryStat class.
class QueryStat
The class has a set of attributes which accumulate the corresponding values: avg_time, cache_count,
db_count, max_time, merge, min_time, query_executed, sql, sum_time

3.7. Methods and attributes of the Database object

17

Pony ORM, Release 0.6

merge_local_stats()
This method merges the statistics from the current thread into the global statistics. You can call this method
at the end of the HTTP request processing.
global_stats
This is a dictionary where the statistics for executed SQL queries is aggregated from all threads. The key
of this dictionary is the SQL statement and the value is an object of the QueryStat class.

3.8 Using Database object for raw SQL queries


Typically you will work with entities and let Pony interact with the database, but Pony also allows you to work with
the database using SQL, or even combine both ways. Of course you can work with the database directly using the
DBAPI interface, but using the Database object gives you the following advantages:
Automatic transaction management using the db_session decorator or context manager. All data will be stored
to the database after the transaction is finished, or rolled back if an exception happened.
Connection pool. There is no need to keep track of database connections. You have the connection when you
need it and when you have finished your transaction the connection will be returned to the pool.
Unified database exceptions. Each DBAPI module defines its own exceptions. Pony allows you to work with
the same set of exceptions when working with any database. This helps you to create applications which can be
ported from one database to another.
Unified way of passing parameters to SQL queries with the protection from injection attacks. Different database
drivers use different paramstyles - the DBAPI specification offers 5 different ways of passing parameters to SQL
queries. Using the Database object you can use one way of passing parameters for all databases and eliminate
the risk of SQL injection.
Automatic unpacking of single column results when using get or select methods of the Database object.
If the select method returns just one column, Pony returns a list of values, not a list of tuples each of which
has just one item, as it does DBAPI. If the get method returns a single column it returns just value, not a tuple
consisting of one item. Its just convenient.
When the methods select or get return more than one column, Pony uses smart tuples which allow accessing
items as tuple attributes using column names, not just tuple indices.
In other words the Database object helps you save time completing routine tasks and provides convenience and
uniformity.

3.8.1 Using parameters in raw SQL queries


With Pony you can easily pass parameters into SQL queries. In order to specify a parameter you need to put the $ sign
before the variable name:
x = "John"
data = db.select("* from Person where name = $x")

When Pony encounters such a parameter within the SQL query it gets the variable value from the current frame (from
globals and locals) or from the dictionary which is passed as the second parameter. In the example above Pony will try
to get the value for $x from the variable x and will pass this value as a parameter to the SQL query which eliminates
the risk of SQL injection. Below you can see how to pass a dictionary with the parameters:
data = db.select("* from Person where name = $x", {"x" : "Susan"})

This method of passing parameters to the SQL queries is very flexible and allows using not only single variables, but
any Python expression. In order to specify an expression you need to put it in parentheses after the $ sign:
18

Chapter 3. Database

Pony ORM, Release 0.6

data = db.select("* from Person where name = $(x.lower()) and age > $(y + 2)")

3.8. Using Database object for raw SQL queries

19

Pony ORM, Release 0.6

20

Chapter 3. Database

CHAPTER 4

Entities

Entities are Python classes which store an objects state in the database. Each instance of an entity corresponds to a
row in the database table. Often entities represent objects from the real world (e.g. Customer, Product).
Pony also has an entity-relationship diagram editor which can be used for creating Python entity definitions.
Before creating entity instances you need to map entities to database tables. Pony can map entities to existing tables
or create new tables. After the mapping is generated you can query the database and create new instances of entities.

4.1 Defining an entity


Each entity belongs to a database. That is why before defining entities you need to create an object of the Database
class:
from pony.orm import *
db = Database("sqlite", "database.sqlite", create_db=True)
class MyEntity(db.Entity):
attr1 = Required(str)

The Ponys Database object has the Entity attribute which is used as a base class for all the entities stored in this
database. Each new entity that is defined must inherit from this Entity class.

4.2 Entity attributes


Entity attributes are specified as class attributes inside the entity class using the syntax attr_name =
kind(type):
class Customer(db.Entity):
name = Required(str)
picture = Optional(buffer)

You can also specify additional attribute options after the attribute type in the parentheses. We will discuss this in
more detail later in this chapter.
Pony has the following kinds of attributes:
Required
Optional

21

Pony ORM, Release 0.6

PrimaryKey
Set

4.2.1 Required and Optional


Usually most entity attributes are of Required or Optional kind. If an attribute is defined as Required then it
must have a value at all times, while Optional attributes may be empty.
If you need the value of an attribute to be unique then you can set the attribute option unique=True.

4.2.2 Optional string attributes


For most data types None is used when no value is assigned to the attribute. But when a string attribute is not assigned
a value, Pony uses an empty string instead of None. This is more practical than storing empty string as NULL in the
database. Most frameworks behave this way. Also, empty strings can be indexed for faster search, unlike NULLs. If
you will try to assign None to such an optional string attribute, youll get the ConstraintError exception. You
can change this behavior using the nullable=True option. In this case it will be possible to store both empty
strings and NULL values in the same column, but this is rarely needed.
Oracle database treats empty strings as NULL values. Because of this all Optional attributes in Oracle have
nullable set to True automatically.
If an optional string attribute is used as a unique key or as a part of a unique composite key, it will always have
nullable set to True automatically.

4.2.3 PrimaryKey
PrimaryKey defines an attribute which is used as a primary key in the database table. Each entity should always
have a primary key. If the primary key is not specified explicitly, Pony will create it implicitly. Lets consider the
following example:
class Product(db.Entity):
name = Required(str, unique=True)
price = Required(Decimal)
description = Optional(str)

The entity definition above will be equal to the following:


class Product(db.Entity):
id = PrimaryKey(int, auto=True)
name = Required(str, unique=True)
price = Required(Decimal)
description = Optional(str)

The primary key attribute which Pony adds automatically always will have the name id and int type. The option
auto=True means that the value for this attribute will be assigned automatically using the databases incremental
counter or a sequence.
If you specify the primary key attribute yourself, it can have any name and type. For example, we can define the entity
Customer and have customers email as the primary key:
class Customer(db.Entity):
email = PrimaryKey(str)
name = Required(str)

22

Chapter 4. Entities

Pony ORM, Release 0.6

4.2.4 Set
A Set attribute represents a collection. You can specify another entity as the type for the Set attribute. This is the
way to define one side for the to-many relationships, which can be many-to-many or one-to-many. As of now, Pony
doesnt allow the use of Set with primitive types. We plan to add this feature later. We will talk in more detail about
this attribute type in Working with relationships chapter.

4.2.5 Composite keys


Pony fully supports composite keys. In order to declare a composite primary key you need to specify all the parts of
the key as Required and then combine them into a composite primary key:
class Example(db.Entity):
a = Required(int)
b = Required(str)
PrimaryKey(a, b)

Here PrimaryKey(a, b) doesnt create an attribute, but combines the attributes specified in the parenthesis into a
composite primary key. Each entity can have only one primary key.
In order to declare a secondary composite key you need to declare attributes as usual and then combine them using the
composite_key directive:
class Example(db.Entity):
a = Required(str)
b = Optional(int)
composite_key(a, b)

In the database composite_key(a, b) will be represented as the UNIQUE ("a", "b") constraint.
If have just one attribute, which represents a unique key, you can create such a key by specifying unique=True by
an attribute:
class Product(db.Entity):
name = Required(str, unique=True)

4.2.6 Composite indexes


Using the composite_index() directive you can create a composite index for speeding up data retrieval. It can
combine two or more attributes:
class Example(db.Entity):
a = Required(str)
b = Optional(int)
composite_index(a, b)

You can use the attribute or the attribute name:


class Example(db.Entity):
a = Required(str)
b = Optional(int)
composite_index(a, b)

If you want to create a non-unique index for just one column, you can specify the index option of an attribute. This
option is described later in this chapter.
The composite index can include a discriminator attribute used for inheritance.

4.2. Entity attributes

23

Pony ORM, Release 0.6

4.3 Attribute data types


Entity attributes are specified as class attributes inside the entity class using the syntax attr_name =
kind(type). You can use the following data types when define attributes:
str
unicode
int
float
Decimal
datetime
date
time
timedelta
bool
buffer - used for binary data in Python 2 and 3
bytes - used for binary data in Python 3
LongStr - used for large strings
LongUnicode - used for large strings
UUID
buffer and bytes types are stored as binary (BLOB) types in the database. LongStr and LongUnicode are
stored as CLOB in the database.
Starting with the Pony Release 0.6, where the support for Python 3 was added, instead of unicode and
LongUnicode we recommend to use str and LongStr types respectively.
As you know, Python 3 has some differences from Python 2 when it comes to strings. Python 2 provides two string
types str (byte string) and unicode (unicode string), whereas in Python 3 the str type represents unicode strings
and the unicode was just removed.
Before the release 0.6, Pony stored str and unicode attributes as unicode in the database, but for str attributes it
had to convert unicode to byte string on reading from the database. Starting with the Pony Release 0.6 the attributes
of str type in Python 2 behave as if they were declared as unicode attributes. There is no difference now if you
specify str or unicode as the attribute type you will have unicode string in Python and in the database. The
same thing is with the LongUnicode and LongStr. LongStr now is an alias to LongUnicode. This type uses
unicode in Python and in the database.
attr1 = Required(str)
# is the same as
attr2 = Required(unicode)
attr3 = Required(LongStr)
# is the same as
attr4 = Required(LongUnicode)

If you need to represent byte sequence in Python 2, you can use the buffer type. In Python 3 you should use the
bytes type for this purpose.

24

Chapter 4. Entities

Pony ORM, Release 0.6

If you need to represent a byte sequence in Python 2, you can use the buffer type. In Python 3 the buffer type
has gone, and Pony uses the bytes type which was added in Python 3 to represent binary data. But for the sake of
backward compatibility we still keep buffer as an alias to the bytes type in Python 3. If youre importing * from
pony.orm you will get this alias too.
If you want to write code which can run both on Python 2 and Python 3, you should use the buffer type for binary
attributes. If your code is for Python 3 only, you can use bytes instead:
attr1 = Required(buffer) # Python 2 and 3
attr2 = Required(bytes) # Python 3 only

It would be cool if we could use the bytes type as an alias to buffer in Python 2, but unfortunately it is impossible,
because Python 2.6 adds bytes as a synonym for the str type.
Also you can specify another entity as the attribute type for defining a relationship between two entities.

4.4 Attribute options


You can specify additional options during attribute definitions using positional and keyword arguments. Positional
arguments depend on the attribute type.

4.4.1 Max string length


String types accept a positional argument which specifies the max length of this column in the database:
name = Required(str, 40)

VARCHAR(40)

4.4.2 Max integer number size


For the int type you can specify the size of integer type that should be used in the database using the size keyword.
This parameter receives the number of bits that should be used for representing an integer in the database. Allowed
values are 8, 16, 24, 32 and 64:
attr1
attr2
attr3
attr4
attr5

=
=
=
=
=

Required(int,
Required(int,
Required(int,
Required(int,
Required(int,

size=8)
size=16)
size=24)
size=32)
size=64)

#
#
#
#
#

8 bit - TINYINT in MySQL


16 bit - SMALLINT in MySQL
24 bit - MEDIUMINT in MySQL
32 bit - INTEGER in MySQL
64 bit - BIGINT in MySQL

You can use the unsigned parameter to specify that the attribute is unsigned:
attr1 = Required(int, size=8, unsigned=True) # TINYINT UNSIGNED in MySQL

The default value of the unsigned parameter is False. If unsigned is set to True, but size is not provided,
size assumed to be 32 bits.
If current database does not support specified attribute size, the next bigger size is used. For example, PostgreSQL
does not have MEDIUMINT numeric type, so INTEGER type will be used for an attribute with size 24.
Only MySQL actually supports unsigned types. For other databases the column will use signed numeric type which
can hold all valid values for the specified unsigned type. For example, in PostgreSQL an unsigned attribute with size
16 will use INTEGER type. An unsigned attribute with size 64 can be represented only in MySQL and Oracle.
When the size is specified, Pony automatically assigns min and max values for this attribute. For example, a signed
attribute with size 8 will receive min value -128 and max value 127, while unsigned attribute with the same size will
4.4. Attribute options

25

Pony ORM, Release 0.6

receive min value 0 and max value 255. You can override min and max with your own values if necessary, but these
values should not exceed the range implied by the size.
Note: Starting with the Pony release 0.6 the long type is deprecated and if you want to store 64 bit integers in the
database, you need to use int instead with size=64. If you dont specify the size parameter, Pony will use the
default integer type for the specific database.

4.4.3 Decimal scale and precision


For the Decimal type you can specify precision and scale:
price = Required(Decimal, 10, 2)

DECIMAL(10, 2)

4.4.4 Datetime and time precision


The datetime and time types accept a positional argument which specifies the columns precision. By default it is
equal to 6 for most databases.
For MySQL database the default value is 0. Before the MySQL version 5.6.4, the DATETIME and TIME columns
were unable to store fractional seconds at all. Starting with the version 5.6.4, you can store fractional seconds if you
set the precision equal to 6 during the attribute definition:
dt = Required(datetime, 6)

4.4.5 Other attribute options


Additional attribute options which can be set as keyword arguments:
unique
Boolean value to determine if the value of the attribute should be unique.
auto
Boolean value, can be used for a PrimaryKey attribute only. If auto=True then the value for this attribute will
be assigned automatically using the databases incremental counter or sequence.
default
Allows you to specify a default value for the attribute.
sql_default
This option allows you to specify default SQL text which will be included to the CREATE TABLE SQL command. For example:
created_at = Required(datetime, sql_default=CURRENT_TIMESTAMP)

Specifying sql_default=True can be convenient when you have a Required attribute and the value for
it is going to be calculated in the database during the INSERT command (e.g. by a trigger). None by default.
index
Allows you to control index creation for this column. index=True - the index will be created with the default
name. index=index_name - create index with the specified name. index=False skip index creation.
If no index option is specified then Pony still creates index for foreign keys using the default name.
sql_type
Use this option if you want to set a specific SQL type for the column.

26

Chapter 4. Entities

Pony ORM, Release 0.6

lazy
Boolean value, defers loading of the attribute while loading the object. True means this attribute will not
be loaded until you try to access this attribute directly. By default lazy is set to True for LongStr and
LongUnicode and to False for all other types.
cascade_delete
Boolean value which controls the cascade deletion of related objects. True means that Pony always
does cascade delete even if the other side is defined as Optional. False means that Pony never does
cascade delete for this relationship. If the relationship is defined as Required at the other end and
cascade_delete=False then Pony raises the ConstraintError exception on deletion attempt.
column
Specifies the name of the column in the database table which is used for mapping.
columns
Specifies a list of column names in the database table which are used for mapping a composite attribute.
reverse
Specifies the attribute at the other end which should be used for the relationship.
reverse_column
Used for a symmetric relationship in order to specify the name of the database column for the intermediate table.
reverse_columns
Used for a symmetric relationship if the entity has a composite primary key. Allows you to specify the name of
the database columns for the intermediate table.
table
Can be used for many-to-many relationship only in order to specify the name of the intermediate table.
nullable
Boolean value. True allows the column to be NULL in the database. Most likely you dont need to specify this
option because Pony sets it to the most appropriate value by default.
volatile
Usually you specify the value of the attribute in Python and Pony stores this value in the database. But sometimes
you might want to have some logic in the database which changes the value for a column. For example, you can
have a trigger in the database which updates the timestamp of the last objects modification. In this case you
want to have Pony to forget the value of the attribute on objects update sent to the database and read it from the
database at the next access attempt. Set volatile=True in order to let Pony know that this attribute can be
changed in the database.
The volatile=True option can be combined with the sql_default=True option if the value for this
attribute is going to be both created and updated by the database.
You can get the exception UnrepeatableReadError: Value ... was updated outside of
current transaction if another transaction changes the value of the attribute which is used in the current
transaction. Pony notifies about it because this situation can break the business logic of the application. If
you dont want Pony to protect you from such concurrent modifications you can set volatile=True for an
attribute.
sequence_name
Allows you to specify the sequence name used for PrimaryKey attributes for Oracle database.
py_check
This parameter allows you to specify a function which will be used for checking the value before it is assigned
to the attribute. The function should return True or False. Also it can raise the ValueError exception if
the check failed. Example:

4.4. Attribute options

27

Pony ORM, Release 0.6

class Student(db.Entity):
name = Required(str)
gpa = Required(float, py_check=lambda val: val >= 0 and val <= 5)

min
Allows you to specify the minimum allowed value for numeric attributes (int, float, Decimal). If you will try to
assign the value that is less than the specified min value, youll get the ValueError exception.
max
Allows you to specify the maximum allowed value for numeric attributes (int, float, Decimal). If you will try to
assign the value that is greater than the specified max value, youll get the ValueError exception.

4.5 Entity inheritance


Entity inheritance in Pony is similar to inheritance for regular Python classes. Lets consider an example of a data
diagram where entities Student and Professor inherit from the entity Person:
class Person(db.Entity):
name = Required(str)
class Student(Person):
gpa = Optional(Decimal)
mentor = Optional("Professor")
class Professor(Person):
degree = Required(str)
students = Set("Student")

All attributes and relationships of the base entity Person are inherited by all descendants. Some mappers (e.g.
Django) have a problem when a query on a base entity doesnt return the right classes: for instances of derived models
the query returns just a base part of each instance. Pony doesnt have such a problem, you always get the correct entity
instances:
for p in Person.select():
if isinstance(p, Professor):
print p.name, p.degree
elif isinstance(p, Student):
print p.name, p.gpa
else: # somebody else
print p.name

In order to create the correct entity instance Pony uses a discriminator column. By default this is a string column and
Pony uses it to store the entity class name:
classtype = Discriminator(str)

By default Pony implicitly creates the classtype attribute for each entity class which takes part in inheritance. You
can use your own discriminator column name and type. If you change the type of the discriminator column, then you
have to specify the _discrimintator_ value for each entity. Lets consider the example above and use cls_id
as the name for our discriminator column of int type:
class Person(db.Entity):
cls_id = Discriminator(int)
_discriminator_ = 1
...

28

Chapter 4. Entities

Pony ORM, Release 0.6

class Student(Person):
_discriminator_ = 2
...
class Professor(Person):
_discriminator_ = 3
...

4.5.1 Multiple inheritance


Pony also supports multiple inheritance. If you use multiple inheritance then all the parent classes of the newly defined
class should inherit from the same base class (a diamond-like hierarchy).
Lets consider a data diagram example where a student can be a teaching assistant. For this purpose well introduce the
entity Teacher and derive Professor and TeachingAssistant from it. The entity TeachingAssistant
inherits from both the Student class and the Teacher class:
class Person(db.Entity):
name = Required(str)
class Student(Person):
...
class Teacher(Person):
...
class Professor(Teacher):
...
class TeachingAssistant(Student, Teacher):
...

The TeachingAssistant objects are instances of both Teacher and Student entities and inherit all their
attributes. Multiple inheritance is possible here because both Teacher and Student have the same base class
Person.
Inheritance is a very powerful tool, but it should be used wisely. Often the data diagram is much simpler if it has
limited usage of inheritance.

4.5.2 Representing inheritance in the database


There are three ways to implement inheritance in the database:
1. Single Table Inheritance: all entities in the hierarchy are mapped to a single database table.
2. Class Table Inheritance: each entity in the hierarchy is mapped to a separate table, but each table stores only the
attributes which the entity doesnt inherit from its parents.
3. Concrete Table Inheritance: each entity in the hierarchy is mapped to a separate table and each table stores the
attributes of the entity and all its ancestors.
The main problem of the third approach is that there is no single table where we can store the primary key and that is
why this implementation is rarely used.
The second implementation is used often, this is how the inheritance is implemented in Django. The disadvantage
of this approach is that the mapper has to join several tables together in order to retrieve data which can lead to the
performance degradation.

4.5. Entity inheritance

29

Pony ORM, Release 0.6

Pony uses the first approach where all entities in the hierarchy are mapped to a single database table. This is the most
efficient implementation because there is no need to join tables. This approach has its disadvantages too:
Each table row has columns which are not used because they belong to other entities in the hierarchy. It is not a
big problem because the blank columns keep NULL values and it doesnt use much space.
The table can have large number of columns if there are a lot of entities in the hierarchy. Different databases
have different limits for maximum columns per table, but usually that limit is pretty high.
The second approach has the following advantage: when a new entity is added to the hierarchy, there is no need to
change the base class table. Pony is going to support this approach in the future.

4.6 Mapping customization


When Pony creates tables from entity definitions, it uses the name of entity as the table name and attribute names as
the column names, but you can override this behavior.
The name of the table is not always equal to the name of an entity: in MySQL and PostgreSQL the default table name
generated from the entity name will be converted to the lower case, in Oracle - to the upper case. You can always find
the name of the entity table by reading the _table_ attribute of an entity class.
If you need to set your own table name use the _table_ class attribute:
class Person(db.Entity):
_table_ = "person_table"
name = Required(str)

If you need to set your own column name, use the option column:
class Person(db.Entity):
_table_ = "person_table"
name = Required(str, column="person_name")

For composite attributes use the option columns with the list of the column names specified:
class Course(db.Entity):
name = Required(str)
semester = Required(int)
lectures = Set("Lecture")
PrimaryKey(name, semester)
class Lecture(db.Entity):
date = Required(datetime)
course = Required(Course, columns=["name_of_course", "semester"])

In this example we override the column names for the composite attribute Lecture.course. By default Pony will
generate the following column names: "course_name" and "course_semester". Pony combines the entity
name and the attribute name in order to make the column names easy to understand for the programmer.
If you need to set the column names for the intermediate table for many-to-many relationship, you should specify the
option column or columns for the Set attributes. Lets consider the following example:
from pony.orm import *
db = Database("sqlite", ":memory:")
class Student(db.Entity):
name = Required(str)
courses = Set("Course")

30

Chapter 4. Entities

Pony ORM, Release 0.6

class Course(db.Entity):
name = Required(str)
semester = Required(int)
students = Set(Student)
PrimaryKey(name, semester)
sql_debug(True)
db.generate_mapping(create_tables=True)

By default, for storing many-to-many relationships between Student and Course, Pony will create an intermediate
table "Course_Student" (it constructs the name of the intermediate table from the entity names in the alphabetical
order). This table will have three columns: "course_name", "course_semester" and "student" - two
columns for the Courses composite primary key and one column for the Student. Now lets say we want to
name the intermediate table as "Study_Plans" which have the following columns: "course", "semester"
and "student_id". Below is the code snippet which does this:
class Student(db.Entity):
name = Required(str)
courses = Set("Course", table="Study_Plans", columns=["course", "semester"]))
class Course(db.Entity):
name = Required(str)
semester = Required(int)
students = Set(Student, column="student_id")
PrimaryKey(name, semester)

You can find more examples of mapping customization in an example which comes with Pony ORM package

4.6. Mapping customization

31

Pony ORM, Release 0.6

32

Chapter 4. Entities

CHAPTER 5

Relationships

Entities can relate to each other. A relationship between two entities is defined by using two attributes which specify
both ends of a relationship:
class Customer(db.Entity):
orders = Set("Order")
class Order(db.Entity):
customer = Required(Customer)

In the example above we have two relationship attributes: orders and customer. When we define the entity
Customer, the entity Order is not defined yet. That is why we have to put quotes around Order. Another option
is to use lambda:
class Customer(db.Entity):
orders = Set(lambda: Order)

This can be useful if you want your IDE to check the names of declared entities and highlight typos.
Some mappers (e.g. Django) require defining relationships on one side only. Pony requires defining relationships on
both sides explicitly (as The Zen of Python reads: Explicit is better than implicit), which allows the user to see all
relationships from the perspective of each entity.
All relationships are bidirectional. If you update one side of a relationship, the other side will be updated automatically.
For example, if we create an instance of Order entity, the customers set of orders will be updated to include this new
order.
There are three types of relationships: one-to-one, one-to-many and many-to-many. A one-to-one relationship is rarely
used, most relations between entities are one-to-many and many-to-many. If two entities have one-to-one relationship
it often means that they can be combined into a single entity. If your data diagram has a lot of one-to-one relationships,
then it may signal that you need to reconsider entity definitions.

5.1 One-to-many relationship


Here is an example of one-to-many relationship:
class Order(db.Entity):
items = Set("OrderItem")
class OrderItem(db.Entity):
order = Required(Order)

33

Pony ORM, Release 0.6

In the example above the instance of OrderItem cannot exist without an order. If we want to allow an instance of
OrderItem to exist without being assigned to an order, we can define the order attribute as Optional:
class Order(db.Entity):
items = Set("OrderItem")
class OrderItem(db.Entity):
order = Optional(Order)

5.2 Many-to-many relationship


In order to create many-to-many relationship you need to define both ends of the relationship as Set attributes:
class Product(db.Entity):
tags = Set("Tag")
class Tag(db.Entity):
products = Set(Product)

In order to implement this relationship in the database, Pony will create an intermediate table. This is a well known
solution which allows you to have many-to-many relationships in relational databases.

5.3 One-to-one relationship


In order to create a one-to-one relationship, the relationship attributes should be defined as Optional-Required
or as Optional-Optional:
class Person(db.Entity):
passport = Optional("Passport")
class Passport(db.Entity):
person = Required("Person")

Defining both attributes as Required is not allowed because it doesnt make sense.

5.4 Self-references
An entity can relate to itself using a self-reference relationship. Such relationships can be of two types: symmetric
and non-symmetric. A non-symmetric relationship is defined by two attributes which belong to the same entity.
The specifics of the symmetrical relationship is that the entity has just one relationship attribute specified, and this
attribute defines both sides of the relationship. Such relationship can be either one-to-one or many-to-many. Here are
examples of self-reference relationships:
class Person(db.Entity):
name = Required(str)
spouse = Optional("Person", reverse="spouse") # symmetric one-to-one
friends = Set("Person", reverse="friends")
# symmetric many-to-many
manager = Optional("Person", reverse="employees") # one side of non-symmetric
employees = Set("Person", reverse="manager") # another side of non-symmetric

34

Chapter 5. Relationships

Pony ORM, Release 0.6

5.5 Multiple relationships between two entities


When two entities have more than one relationship between them, Pony requires the reverse attributes to be specified.
This is needed in order to let Pony know which pair of attributes are related to each other. Lets consider the data
diagram where a user can write tweets and also can favorite them:
class User(db.Entity):
tweets = Set("Tweet", reverse="author")
favorites = Set("Tweet", reverse="favorited")
class Tweet(db.Entity):
author = Required(User, reverse="tweets")
favorited = Set(User, reverse="favorites")

In the example above we have to specify the option reverse. If you will try to generate mapping for the entities definition without the reverse specified, you will get the exception pony.orm.core.ERDiagramError:
"Ambiguous reverse attribute for Tweet.author". That happens because in this case the attribute
author can technically relate either to the attribute tweets or to favorites and Pony has no information on
which one to use.

5.5. Multiple relationships between two entities

35

Pony ORM, Release 0.6

36

Chapter 5. Relationships

CHAPTER 6

Transactions

A database transaction is a logical unit of work, which can consist of one or several queries. Transactions are atomic,
which means that when a transaction makes changes to the database, either all the changes succeed when the transaction is committed, or all the changes are undone when the transaction is rolled back.
Pony provides automatic transaction management using the database session.

6.1 Working with database session


The code which interacts with the database has to work within a database session. The session sets the borders of a
conversation with the database. Each application thread which works with the database establishes a separate database
session and uses a separate instance of an Identity Map. This Identity Map works as a cache, helping to avoid a database
query when you access an object by its primary or unique key and it is already stored in the Identity Map. In order
to work with the database using the database session you can use the @db_session decorator or db_session
context manager. When the session ends it does the following actions:
Commits transaction if data was changed and no exceptions occurred otherwise it rolls back transaction.
Returns the database connection to the connection pool.
Clears the Identity Map cache.
If you forget to specify the db_session where necessary, Pony will raise the exception TransactionError:
db_session is required when working with the database.
Example of using the @db_session decorator:
@db_session
def check_user(username):
return User.exists(username=username)

Example of using the db_session context manager:


def process_request():
...
with db_session:
u = User.get(username=username)
...

Note: When you work with Pythons interactive shell you dont need to worry about the database session, because it
is maintained by Pony automatically.

37

Pony ORM, Release 0.6

If youll try to access instances attributes which were not loaded from the database outside of the db_session
scope, youll get the DatabaseSessionIsOver exception. For example:
DatabaseSessionIsOver: Cannot load attribute Customer[3].name: the database session is over

This happens because by this moment the connection to the database is already returned to the connection pool,
transaction is closed and we cannot send any queries to the database.
When Pony reads objects from the database it puts those objects to the Identity Map. Later, when you update an
objects attributes, create or delete an object, the changes will be accumulated in the Identity Map first. The changes
will be saved in the database on transaction commit or before calling the following methods: select(), get(),
exists(), execute().

6.1.1 Transaction scope


Usually you will have a single transaction within the db_session. There is no explicit command for starting a
transaction. A transaction begins with the first SQL query sent to the database. Before sending the first query, Pony
gets a database connection from the connection pool. Any following SQL queries will be executed in the context of
the same transaction.
Note: Python driver for SQLite doesnt start a transaction on a SELECT statement. It only begins a transaction on a
statement which can modify the database: INSERT, UPDATE, DELETE. Other drivers start a transaction on any SQL
statement, including SELECT.
A transaction ends when it is committed or rolled back using commit() or rollback() calls or implicitly by
leaving the db_session scope.
@db_session
def func():
# a new transaction is started
p = Product[123]
p.price += 10
# commit() will be done automatically
# database session cache will be cleared automatically
# database connection will be returned to the pool

6.1.2 Several transactions within the same db_session


If you need to have more than one transaction within the same database session you can call commit() or
rollback() at any time during the session, and then the next query will start a new transaction. The Identity
Map keeps data after the manual commit(), but if you call rollback() the cache will be cleared.
@db_session
def func1():
p1 = Product[123]
p1.price += 10
commit()
# the first transaction is committed
p2 = Product[456] # a new transaction is started
p2.price -= 10

6.1.3 Nested db_session


If you enter the db_session scope recursively, for example by calling a function which is decorated with the
@db_session decorator from another function which is decorated with @db_session, Pony will not create a new
38

Chapter 6. Transactions

Pony ORM, Release 0.6

session, but will share the same session for both functions. The database session ends on leaving the scope of the
outermost db_session decorator or context manager.

6.1.4 db_session cache


Pony caches data at several stages for increasing performance. It caches:
The results of a generator expression translation. If the same generator expression query is used several times
within the program, it will be translated to SQL only once. This cache is global for entire program, not only for
a single database session.
Objects which were created or loaded from the database. Pony keeps these objects in the Identity Map. This
cache is cleared on leaving the db_session scope or on transaction rollback.
Query results. Pony returns the query result from the cache if the same query is called with the same parameters
once again. This cache is cleared once any of entity instances is changed. This cache is cleared on leaving the
db_session scope or on transaction rollback.

6.1.5 Working with multiple databases


Pony can work with several databases simultaneously. In the example below we use PostgreSQL for storing user
information and MySQL for storing information about addresses:
db1 = Database("postgres", ...)
class User(db1.Entity):
...
db2 = Database("mysql", ...)
class Address(db2.Entity):
...
@db_session
def do_something(user_id, address_id):
u = User[user_id]
a = Address[address_id]
...

On exiting from the do_something() function Pony will perform commit() or rollback() to both databases
when necessary.

6.2 Functions for working with transactions


commit()
Saves all changes which were made within the current db_session using the flush() method and commits the
transaction to the database. This top level commit() function calls the commit() method of each database
object which was used in current transaction.
rollback()
Rolls back the current transaction. This top level rollback() function calls the rollback() method of
each database object which was used in current transaction.
flush()
Saves all changes from db_session cache to the databases, without committing them. Usually Pony saves
6.2. Functions for working with transactions

39

Pony ORM, Release 0.6

data from the database session cache automatically and you dont need to call this function yourself. One of the
use cases when it might be needed is when you want to get the primary keys values of newly created objects
which has autoincremented primary key before commit.
Pony always saves the changes accumulated in the db_session cache automatically before executing the
following methods: select(), get(), exists(), execute() and commit().
The flush() function makes the updates made in db_session cache visible to all database queries which
belong to current transaction. At the same time, after calling the flush() functions, the results are not committed to the database yet.
This top level flush() function calls the flush() method of each database object which was used in current
transaction.

6.3 Parameters of db_session


As it was mentioned above db_session can be used as a decorator or a context manager. db_session can receive
parameters which are described below.
retry
Accepts an integer value and specifies the number of attempts for committing the current transaction. This parameter can be used with the db_session decorator only. The decorated function cannot call commit() or
rollback() functions explicitly. When this parameter is specified, Pony catches the TransactionError
exception (and all its descendants) and restarts the current transaction. By default Pony catches the
TransactionError exception only, but this list can be modified using the retry_eceptions parameter.
retry_exceptions
Accepts list and allows you to specify the list of exceptions which will cause the transaction restart. By default
this parameter is equal to [TransactionError]. Another option is to specify a callable which returns a
boolean value. This callable receives the only parameter - the occurred exception. If this callable returns True
then the transaction will be restarted.
allowed_exceptions
This parameter receives a list of exceptions which when occurred do not cause the transaction rollback. For
example, some web frameworks trigger HTTP redirect with the help of an exception.
immediate
Accepts a boolean value, False by default. Some databases (e.g. SQLite, Postgres) start a transaction only
when a modifying query is sent to the database(UPDATE, INSERT, DELETE) and dont start it for SELECTs.
If you need to start a transaction on SELECT, then you should pass True for this parameter. Usually there is
no need to change this parameter.
serializable
Accepts a boolean value, False by default. Allows you to set the SERIALIZABLE isolation level for a
transaction.

6.4 Optimistic concurrency control


By default Pony uses the optimistic concurrency control concept for increasing performance. With this concept, Pony doesnt acquire locks on database rows. Instead it verifies that no other transaction has modified the data it has read or is trying to modify. If the check reveals conflicting modifications, the committing transaction gets the exception OptimisticCheckError, Object XYZ was updated outside
of current transaction and rolls back.

40

Chapter 6. Transactions

Pony ORM, Release 0.6

What should we do with this situation? First of all, this behavior is normal for databases which implement the MVCC
pattern (e.g. Postgres, Oracle). For example, in Postgres, you will get the following error when a concurrent transaction
changed the same data:
ERROR: could not serialize access due to concurrent update
The current transaction rolls back, but it can be restarted. In order to restart the transaction automatically, you can use
the retry parameter of the db_session decorator (see more details about it later in this chapter).
How Pony does the optimistic check? For this purpose Pony tracks access to attributes of each object. If the users code
reads or modifies an objects attribute, Pony then will check if this attribute value remains the same in the database on
commit. This approach guarantees that there will be no lost updates, the situation when during the current transaction
another transaction changed the same object and then our transaction overrides the data without knowing there were
changes.
During the optimistic check Pony verifies only those attributes which were read or written by the user. Also when
Pony updates an object, it updates only those attributes which were changed by the user. This way it is possible to
have two concurrent transactions which change different attributes of the same object and both of them succeed.
Generally the optimistic concurrency control increases the performance because transactions can complete without
the expense of managing locks or without having transactions wait for other transactions lock to clear. This approach
shows very good results when conflicts are rare and our application reads data more often then writes.
However, if contention for writing data is frequent, the cost of repeatedly restarting transactions hurts performance. In
this case the pessimistic locking can be more appropriate.

6.5 Pessimistic locking


Sometimes we need to lock an object in the database in order to prevent other transactions from modifying the same
record. Within the database such a lock should be done using the SELECT FOR UPDATE query. In order to generate
such a lock using Pony you should call the for_update method:
select(p for p in Product if p.price > 100).for_update()

The query above selects all instances of Product with the price greater than 100 and locks the corresponding rows in
the database. The lock will be released upon commit or rollback of current transaction.
If you need to lock a single object, you can use the get_for_update method of an entity:
Product.get_for_update(id=123)

When you trying to lock an object using for_update and it is already locked by another transaction, your request
will need to wait until the row-level lock is released. To prevent the operation from waiting for other transactions to
commit, use the nowait=True option:
select(p for p in Product if p.price > 100).for_update(nowait=True)
Product.get_for_update(id=123, nowait=True)

In this case, if a selected row(s) cannot be locked immediately, the request reports an error, rather than waiting.
The main disadvantage of pessimistic locking is performance degradation because of the expense of database locks
and limiting concurrency.

6.5. Pessimistic locking

41

Pony ORM, Release 0.6

6.6 Transaction isolation levels and database differences


Isolation is a property that defines when the changes made by one transaction become visible to other concurrent
transactions Isolation levels. The ANSI SQL standard defines four isolation levels:
READ UNCOMMITTED - the most unsafe level
READ COMMITTED
REPEATABLE READ
SERIALIZABLE - the most safe level
When using the SERIALIZABLE level, each transaction sees the database as a snapshot made at the beginning of a
transaction. This level provides the highest isolation, but it requires more resources than other levels.
This is the reason why most databases use a lower isolation level by default which allow greater concurrency. By
default Oracle and PostgreSQL use READ COMMITTED, MySQL - REPEATABLE READ. SQLite supports the
SERIALIZABLE level only, but Pony emulates the READ COMMITTED level for allowing greater concurrency.
If you want Pony to work with transactions using the SERIALIZABLE isolation level, you can do that by specifying
the serializable=True parameter to the @db_session decorator or db_session context manager:
@db_session(serializable=True)
def your_function():
...

6.6.1 READ COMMITTED vs. SERIALIZABLE mode


In SERIALIZABLE mode, you always have a chance to get a Cant serialize access due to concurrent update error,
and would have to retry the transaction until it succeeded. You always need to code a retry loop in your application
when you are using SERIALIZABLE mode for a writing transaction.
In READ COMMITTED mode, if you want to avoid changing the same data by a concurrent transaction, you should
use SELECT FOR UPDATE. But this way there is a chance to have a database deadlock - the situation where one
transaction is waiting for a resource which is locked by another transaction. If your transaction got a deadlock, your
application needs to restart the transaction. So you end up needing a retry loop either way. Pony can restart a transaction automatically if you specify the retry parameter to the @db_session decorator (but not the db_session
context manager):
@db_session(retry=3)
def your_function():
...

6.6.2 PostgreSQL
PostgreSQL uses the READ COMMITTED isolation level by default. PostgreSQL also supports the autocommit
mode. In this mode each SQL statement is executed in a separate transaction. When your application just selects
data from the database, the autocommit mode can be more effective because there is no need to send commands for
beginning and ending a transaction, the database does it automatically for you. From the isolation point of view, the
autocommit mode is nothing different from the READ COMMITTED isolation level. In both cases your application
sees the data which have been committed by this moment.
Pony automatically switches from the autocommit mode and begins an explicit transaction when your application
needs to modify data by several INSERT, UPDATE or DELETE SQL statements in order to provide atomicity of data
update.

42

Chapter 6. Transactions

Pony ORM, Release 0.6

6.6.3 SQLite
When using SQLite, Ponys behavior is similar as with PostgreSQL: when a transaction is started, selects will
be executed in the autocommit mode. The isolation level of this mode is equivalent of READ COMMITTED.
This way the concurrent transactions can be executed simultaneously with no risk of having a deadlock (the
sqlite3.OperationalError: database is locked is not arising with Pony ORM). When your code
issues non-select statement, Pony begins a transaction and all following SQL statements will be executed within this
transaction. The transaction will have the SERIALIZABLE isolation level.

6.6.4 MySQL
MySQL uses the REPEATABLE READ isolation level by default. Pony doesnt use the autocommit mode with
MySQL because there is no benefit of using it here. The transaction begins with the first SQL statement sent to the
database even if this is a SELECT statement.

6.6.5 Oracle
Oracle uses the READ COMMITTED isolation level by default. Oracle doesnt have the autocommit mode. The
transaction begins with the first SQL statement sent to the database even if this is a SELECT statement.

6.7 How Pony avoids lost updates


Lower isolation levels increase the ability of many users to access data at the same time, but it also can lead to database
anomalies such as lost updates.
Lets consider an example. Say we have two accounts. We need to provide a function which can transfer money from
one account to another. During the transfer we check if the account has enough funds.
Lets say we are using Django ORM for this task. Below if one of the possible ways of implementing such a function:
@transaction.atomic
def transfer_money(account_id1, account_id2, amount):
account1 = Account.objects.get(pk=account_id1)
account2 = Account.objects.get(pk=account_id2)
if amount > account1.amount:
# validation
raise ValueError("Not enough funds")
account1.amount -= amount
account1.save()
account2.amount += amount
account2.save()

By default in Django, each save() is performed in a separate transaction. If after the first save() there will be
a failure, the amount will just disappear. Even if there will be no failure, if another transaction will try to get the
account statement in between of two save() operations, the result will be wrong. In order to avoid such problems, both operations should be combined in one transaction. We can do that by decorating the function with the
@transaction.atomic decorator.
But even in this case we can encounter a problem. If two bank branches will try to transfer the full amount to different
accounts at the same time, both operations will be performed. Each function will pass the validation and finally one
transaction will override the results of another one. This anomaly is called lost update.
There are three ways to prevent such anomaly:
Use the SERIALIZABLE isolation level

6.7. How Pony avoids lost updates

43

Pony ORM, Release 0.6

Use SELECT FOR UPDATE instead SELECT


Use optimistic checks
If you use the SERIALIZABLE isolation level, the database will not allow to commit the second transaction by
throwing an exception during commit. The disadvantage of such approach is that this level requires more system
resources.
If you use SELECT FOR UPDATE then the transaction which hits the database first will lock the row and another
transaction will wait.
The optimistic check doesnt require more system resources and doesnt lock the database rows. It eliminates the lost
update anomaly by ensuring that the data wasnt changed between the moment when we read it from the database and
the commit operation.
The only way to avoid the lost update anomaly in Django is using the SELECT FOR UPDATE and you should use it
explicitly. If you forget to do that or if you dont realize that the problem of lost update exists with your business logic,
your data can be lost.
Pony allows using all three approaches, having the third one, optimistic checks, turned on by default. This way Pony
avoids the lost update anomaly completely. Also using the optimistic checks allows the highest concurrency because
it doesnt lock the database and doesnt require extra resources.
The similar function for transferring money would look this way in Pony:
The SERIALIZABLE approach:
@db_session(serializable=True)
def transfer_money(account_id1, account_id2, amount):
account1 = Account[account_id1]
account2 = Account[account_id2]
if amount > account1.amount:
raise ValueError("Not enough funds")
account1.amount -= amount
account2.amount += amount

The SELECT FOR UPDATE approach:


@db_session
def transfer_money(account_id1, account_id2, amount):
account1 = Account.get_for_update(id=account_id1)
account2 = Account.get_for_update(id=account_id2)
if amount > account1.amount:
raise ValueError("Not enough funds")
account1.amount -= amount
account2.amount += amount

The optimistic check approach:


@db_session
def transfer_money(account_id1, account_id2, amount):
account1 = Account[account_id1]
account2 = Account[account_id2]
if amount > account1.amount:
raise ValueError("Not enough funds")
account1.amount -= amount
account2.amount += amount

The last approach is used by default in Pony and you dont need to add anything else explicitly.

44

Chapter 6. Transactions

CHAPTER 7

Working with entity instances

7.1 Creating an entity instance


Creating an entity instance in Pony is similar to creating a regular object in Python:
customer1 = Customer(login="John", password="***",
name="John", email="[email protected]")

When creating an object in Pony, all the parameters should be specified as keyword arguments. If an attribute has a
default value, you can omit it.
All created instances belong to the current database session. In some object-relational mappers, you are required to
call an objects save() method in order to save it. This is inconvenient, as a programmer must track which objects
were created or updated, and must not forget to call the save() method on each object.
Pony tracks which objects were created or updated and saves them in the database automatically when current
db_session is over. If you need to save newly created objects before leaving the db_session scope, you can do
so by using flush() or commit() functions.

7.2 Loading objects from the database


7.2.1 Getting an object by primary key
The simplest case is when we want to retrieve an object by the primary key. To accomplish this in Pony, the user
simply needs to put the primary key in square brackets, after the class name. For example, to extract a customer with
the primary key value of 123, we can write:
customer1 = Customer[123]

The same syntax also works for objects with composite keys; we just need to list the elements of the composite primary
key, separated by commas, in the same order that the attributes were defined in the entity class description:
order_item = OrderItem[order1, product1]

Pony raises the ObjectNotFound exception if object with such primary key doesnt exist.

7.2.2 Getting one object by unique combination of attributes


If we want to retrieve one object not by its primary key, but by another combination of attributes, we can use the
get() method of an entity. In most cases, it is used when we want to get an object by the secondary unique key, but
45

Pony ORM, Release 0.6

it can also be used to search by any other combination of attributes. As a parameter of the get() method, we state
names of the attributes and their values. For example, if we want to receive a product under the name Product 1, and
we believe that database has only one product under this name, we can write:
product1 = Product.get(name="Product1")

If no object is found, get() returns None. If multiple objects are found, MultipleObjectsFoundError
exception is raised.
We may want to use the get() method with primary key when we want to get None instead of ObjectNotFound
exception if the object does not exists in database.
Method get() can also receive a lambda function as a single positioning argument, similar to the method select(),
which we will discuss later; but nevertheless, it will return an instance of an entity, and not an object of the Query
type.

7.2.3 Getting several objects


In order to retrieve several objects from a database, we use the select() method, which is present on every entity. Its
argument is a lambda function, which carries a single parameter, symbolizing an instance of an object in the database.
Inside this function, we can write conditions, by which we want to carry out the search. For example, if we want to
find all products with the price higher than 100, we can write:
products = Product.select(lambda p: p.price > 100)

This lambda function will not be executed in Python. Instead, it will be translated to a SQL query:
SELECT "p"."id", "p"."name", "p"."description",
"p"."picture", "p"."price", "p"."quantity"
FROM "Product" "p"
WHERE "p"."price" > 100

The select() method returns an instance of the Query class. If you start iterating over this object, the SQL query
will be sent to the database and you will get the sequence of entity instances. For example, this is how we can print
out all product names and prices for our products:
for p in Product.select(lambda p: p.price > 100):
print p.name, p.price

If we dont want to iterate over a query, but need just to get a list of objects, we can do it this way:
product_list = Product.select(lambda p: p.price > 100)[:]

Here we get a full slice [:] from the query. This is an equivalent of converting a query to a list:
product_list = list(Product.select(lambda p: p.price > 100))

7.2.4 Transfer parameters to the query


Inside the lambda function, it is possible to use variables declared previously. In such cases, the query will put the
values of those variables as a parameter. One important advantage of declarative query syntax in Pony is that it offers
full protection from SQL-injections, as all the data related to external parameters is properly escaped.
For example, if we want to find products with the price higher than x, then we can simply write:
x = 100
products = Product.select(lambda p: p.price > x)

46

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

The SQL query which will be generated will look this way:
SELECT "p"."id", "p"."name", "p"."description",
"p"."picture", "p"."price", "p"."quantity"
FROM "Product" "p"
WHERE "p"."price" > ?

This way the value ofx will be passed as the SQL query parameter, which completely eliminates the risk of SQLinjection.

7.2.5 Sorting query results


If we need to sort objects in a certain order, we can use the method order_by() of the Query object. For example,
if we want to display names and prices of all products with price higher than 100 in a descending order, we can do it
this way:
Product.select(lambda p: p.price > 100).order_by(desc(Product.price))

The methods of the Query object modify the SQL query which will be sent to the database. For the example above
the following SQL will be generated:
SELECT "p"."id", "p"."name", "p"."description",
"p"."picture", "p"."price", "p"."quantity"
FROM "Product" "p"
WHERE "p"."price" > 100
ORDER BY "p"."price" DESC

The order_by() method can also receive a lambda function as a parameter:


Product.select(lambda p: p.price > 100).order_by(lambda p: desc(p.price))

Using the lambda function inside the order_by method allows using advanced sorting expressions. For example,
this is how we can sort our customers by the total price of their orders in the descending order:
Customer.select().order_by(lambda c: desc(sum(c.orders.total_price)))

In order to sort the result by several attributes, we need to separate them by a comma. For example, if we want to sort
products by price in descending order, while displaying products with similar prices in alphabetical order, we can do
it this way:
Product.select(lambda p: p.price > 100).order_by(desc(Product.price), Product.name)

The same query, but using lambda function will look this way:
Product.select(lambda p: p.price > 100).order_by(lambda p: (desc(p.price), p.name))

Note that according to Python syntax, if we return more than one element from lambda, we need to wrap them into the
parenthesis.

7.2.6 Limiting the number of selected objects


It is possible to limit the number of objects returned by a query by using the limit() Query method, or by the more
compact Python slice notation. For example, this is how we can get the 10 most expensive products:
Product.select().order_by(lambda p: desc(p.price))[:10]

7.2. Loading objects from the database

47

Pony ORM, Release 0.6

The result of a slice is not a query object, but a final list of entity instances.
You can also use the Query.page() method as a convenient way of pagination the query results:
Product.select().order_by(lambda p: desc(p.price)).page(1)

7.2.7 Traversing relationships


In Pony you can traverse relationships easily:
order = Order[123]
customer = order.customer
print customer.name

Pony tries to minimize the number of queries sent to the database. In the example above, if a requested Customer
object was already loaded to the cache, Pony will return the object from the cache without sending a query to the
database. But, if an object was not loaded yet, Pony still will not send a query immediately. Instead, it will create a
seed object first. The seed is an object which has only the primary key initialized. Pony does not know how this
object will be used, and there is always the possibility that only the primary key is needed.
In the example above, Pony get the object from database in the third line in, when we access the name attribute. By
using the seed concept, Pony achieves high efficiency and solves the N+1 problem, which is a weakness of many
other mappers.
Traversing is possible in the to-many direction as well. For example, if we have a Customer object and we want
to loop through its orders, we can do it this way:
c = Customer[123]
for order in c.orders:
print order.state, order.price

7.3 Updating an object


When you assign new values to object attributes, you dont need to save each updated object manually. Changes will
be saved in the database automatically on leaving the db_session scope.
For example, in order to increase the number of products by 10 with a primary key of 123, we can execute the following
code:
Product[123].quantity += 10

If we need to change several attributes of the same object, we can do so separately:


order = Order[123]
order.state = "Shipped"
order.date_shipped = datetime.now()

or in a single line, using the set() method:


order = Order[123]
order.set(state="Shipped", date_shipped=datetime.now())

The set() method can be convenient when you need to update several object attributes at once from a dictionary:
order.set(**dict_with_new_values)

48

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

If you need to save the updates to the database before the current database session is finished, you can use the flush()
or commit() functions.
Pony always saves the changes accumulated in the db_session cache automatically before executing the following
methods: select(), get(), exists(), execute() and commit().
In future, Pony is going to support bulk update. It will allow updating multiple objects on the disk without loading
them to the cache:
update(p.set(price=price * 1.1) for p in Product
if p.category.name == "T-Shirt")

7.4 Deleting an object


When you call the delete() method of an entity instance, Pony marks the object as deleted. The object will be
removed from the database during the following commit.
For example, this is how we can delete an order with the primary key equal to 123:
Order[123].delete()

In future, Pony is going to support bulk deletes. It will allow the deletion of multiple objects without loading them to
the cache:
delete(p for p in Product if p.category.name == "Floppy disk")

7.4.1 Cascade delete


When Pony deletes an instance of an entity it also needs to delete its relationships with other objects. The relationships
between two objects are defined by two relationship attributes. If another side of the relationship is declared as a Set,
then we just need to remove the object from that collection. If another side is declared as Optional, then we need
to set it to None. If another side is declared as Required, we cannot just assign None to that relationship attribute.
In this case, Pony will try to do a cascade delete of the related object. This default behavior can be changed using
the cascade_delete option of an attribute. By default this option is set to True if another side of the relationship is
declared as Required and False for all other relationships.
True means that Pony always does cascade delete even if the other side is defined as Optional. False means that
Pony never does cascade delete for this relationship. If the relationship is defined as Required at the other end and
cascade_delete=False then Pony raises the ConstraintError exception on deletion attempt.
Cascade delete for one-to-many relationship example. Raises the ConstraintError exception on an attempt to
delete a group which has related students:
class Group(db.Entity):
major = Required(str)
items = Set("Student", cascade_delete=False)
class Student(db.Entity):
name = Required(str)
group = Required(Group)

Cascade delete for one-to-one relationship example. Deletes a related instance of Passport when deleting the
instance of Person:

7.4. Deleting an object

49

Pony ORM, Release 0.6

class Person(db.Entity):
name = Required(str)
passport = Optional("Passport", cascade_delete=True)
class Passport(db.Entity):
number = Required(str)
person = Required("Person")

7.5 Entity class methods


class Entity
[]
Returns an entity instance selected by its primary key. Raises the ObjectNotFound exception if there
is no such object. Example:
p = Product[123]

For entities with a compound primary key, use a comma between the primary key values:
order_id = 123
product_id = 456
item = OrderItem[123, 456]

If object with the specified primary key was already loaded into the db_session cache, Pony returns
the object from the cache without sending a query to the database.
describe()
Returns a string with the entity declaration. Example:
>>> from pony.orm.examples.estore import *
>>> print OrderItem.describe()
class OrderItem(Entity):
quantity = Required(int)
price = Required(Decimal)
order = Required(Order)
product = Required(Product)
PrimaryKey(order, product)

drop_table(with_all_data=False)
Drops the table which is associated with the entity in the database. If the table is not empty and
with_all_data=False, the method raises the TableIsNotEmpty exception and doesnt delete
anything. Setting the with_all_data=True allows you to delete the table even if it is not empty.
If you need to delete an intermediate table created for many-to-many relationship, you have to call the
method drop_table of the relationship attribute of the entity class(not instance):
class Product(db.Entity):
tags = Set(Tag)
class Tag(db.Entity):
products = Set(Product)
Product.tags.drop_table(with_all_data=True) # removes the intermediate table

50

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

exists(lambda[, globals[, locals])


exists(**kwargs)
Returns True if an instance with the specified condition or attribute values exists and False otherwise.
Examples:
Product.exists(price=1000)
Product.exists(lambda p: p.price > 1000)

get(lambda[, globals[, locals])


get(**kwargs)
Used for extracting one entity instance from the database. If the object with the specified parameters exists,
then returns the object. Returns None if there is no such object. If there are more than one objects with the
specified parameters, raises the MultipleObjectsFoundError: Multiple objects were
found. Use select(...) to retrieve them exception. Examples:
Product.get(price=1000)
Product.get(lambda p: p.name.startswith(A))

get_by_sql(sql, globals=None, locals=None)


select_by_sql(sql, globals=None, locals=None)
If you find that you cannot express a query using the standard Pony queries, you always can write your
own SQL query and Pony will build an entity instance(s) based on the query results. When Pony gets
the result of the SQL query, it analyzes the column names which it receives from the database cursor. If
your query uses SELECT * ... from the entity table, that would be enough for getting the necessary
attribute values for constructing entity instances. You can pass parameters into the query, see Using raw
SQL for more information.
get_for_update(lambda,[globals[, locals], nowait=False)
get_for_update(**kwargs, nowait=False)
Similar to get(), but locks the row in the database using the SELECT ... FOR UPDATE SQL
query. If nowait=True, then the method will throw an exception if this row is already blocked. If
nowait=False, then it will wait if the row is already blocked.
If you need to use SELECT ... FOR UPDATE for multiple rows then you should use the method
for_update() of Query object.
load()
load(args)
Loads all lazy and non-lazy attributes, but not collection attributes, which were not retrieved from the
database yet. If an attribute was already loaded, it wont be loaded again. You can specify the list of the
attributes which need to be loaded, or its names. In this case Pony will load only them:
obj.load(Person.biography, Person.some_other_field)
obj.load(biography, some_other_field)

select()
select(lambda[, globals[, locals])
Selects objects from the database in accordance with the condition specified in lambda, or all objects if
lambda function is not specified.
The select method returns an instance of the Query class. Entity instances will be retrieved from the
database once you start iterating over the Query object. Example:
Product.select(lambda p: p.price > 100 and count(p.order_items) > 1)[:]

The query above returns all products with a price greater than 100 and which were ordered more than once.

7.5. Entity class methods

51

Pony ORM, Release 0.6

select_random(limit)
Select limit random objects. This method uses the algorithm that can be much more effective than using
ORDER BY RANDOM() SQL construct. The method uses the following algorithm:
1.Determine max id from the table.
2.Generate random ids in the range (0, max_id]
3.Retrieve objects by those random ids. If an object with generated id does not exist (e.g. it was deleted),
then select another random id and retry.
Repeat the steps 2-3 as many times as necessary to retrieve the specified amount of objects.
This algorithm doesnt affect performance even when working with a large number of table rows. However
this method also has some limitations:
The primary key must be a sequential id of an integer type.
The number of gaps between existing ids (the count of deleted objects) should be relatively small.
The select_random() method can be used if your query does not have any criteria to select specific
objects. If such criteria is necessary, then you can use the random() method of the Query object.

7.6 Entity instance methods


class Entity
get_pk()
Returns the value of the primary key of the object.
>>> c = Customer[1]
>>> c.get_pk()
1

If the primary key is composite, then this method returns a tuple consisting of primary key column values.
>>> oi = OrderItem[1,4]
>>> oi.get_pk()
(1, 4)

delete()
Deletes an entity instance. The object will be marked as deleted and will be deleted from the database on
the operation flush() which is issued automatically on committing the current transaction, exiting from
the most outer db_session or before sending next query to the database.
set(**kwargs)
Assign new values to several object attributes at once:
Customer[123].set([email protected], address=New address)

This method also can be convenient when you want to assign new values from a dictionary:
d = {email: [email protected], address: New address}
Customer[123].set(**d)

to_dict(only=None,
exclude=None,
with_collections=False,
with_lazy=False,
related_objects=False)
Returns a dictionary with attribute names and its values. This method can be used when you need to
serialize an object to JSON or other format.

52

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

By default this method doesnt include collections (to-many relationships) and lazy attributes. If an attributes values is an entity instance then only the primary key of this object will be added to the dictionary.
only - use this parameter if you want to get only the specified attributes. This argument can be used
as a first positional argument. You can specify a list of attribute names obj.to_dict([id,
name]), a string separated by spaces: obj.to_dict(id name), or a string separated by spaces
with commas: obj.to_dict(id, name).
exclude - this parameter allows you to exclude specified attributes. Attribute names can be specified the
same way as for the only parameter.
related_objects - by default, all related objects represented as a primary key.
If
related_objects=True, then objects which have relationships with the current object will be added
to the resulting dict as objects, not their primary keys. It can be useful if you want to walk the related
objects and call the to_dict() method recursively.
with_collections - by default, the resulting dictionary will not contain collections (to-many relationships). If you set this parameter to True, then the relationships to-many will be represented as lists.
If related_objects=False (which is by default), then those lists will consist of primary keys of
related instances. If related_objects=True then to-many collections will be represented as lists of
objects.
with_lazy - if True, then lazy attributes (such as BLOBs or attributes which are declared with
lazy=True) will be included to the resulting dict.
For illustrating the usage of this method we will use the eStore example which comes with Pony distribution. Lets get a customer object with the id=1 and convert it to a dictionary:
>>> from pony.orm.examples.estore import *
>>> c1 = Customer[1]
>>> c1.to_dict()
{address: uaddress 1,
country: uUSA,
email: [email protected],
id: 1,
name: uJohn Smith,
password: u***}

If we dont want to serialize the password attribute, we can exclude it this way:
>>> c1.to_dict(exclude=password)
{address: uaddress 1,
country: uUSA,
email: [email protected],
id: 1,
name: uJohn Smith}

If you want to exclude more than one attribute, you can specify them as a list: exclude=[id,
password] or as a string: exclude=id, password which is the same as exclude=id
password.
Also you can specify only the attributes, which you want to serialize using the parameter only:
>>> c1.to_dict(only=[id, name])
{id: 1, name: uJohn Smith}
>>> c1.to_dict(name email) # only parameter as a positional argument

7.6. Entity instance methods

53

Pony ORM, Release 0.6

{email: [email protected], name: uJohn Smith}

By default the collections are not included to the resulting dict. If you want to include them, you can specify
with_collections=True. Also you can specify the collection attribute in the only parameter:
>>> c1.to_dict(with_collections=True)
{address: uaddress 1,
cart_items: [1, 2],
country: uUSA,
email: [email protected],
id: 1,
name: uJohn Smith,
orders: [1, 2],
password: u***}

By default all related objects (cart_items, orders) are represented as a list with their primary keys. If you
want to see the related objects instances, you can specify related_objects=True:
>>> c1.to_dict(with_collections=True, related_objects=True)
{address: uaddress 1,
cart_items: [CartItem[1], CartItem[2]],
country: uUSA,
email: [email protected],
id: 1,
name: uJohn Smith,
orders: [Order[1], Order[2]],
password: u***}

If you need to serialize more than one entity instance, or if you need to serialize an instance with its related
objects, you can use the :py:functo_dict function from the pony.orm.serialization module.
flush()
Saves the changes made to this object to the database. Usually Pony saves changes automatically and you
dont need to call this method yourself. One of the use cases when it might be needed is when you want
to get the primary key value of a newly created object which has autoincremented primary key before
commit.

7.7 Entity hooks


Sometimes you might need to perform an action before or after your entity instance is going to be created, updated or
deleted in the database. For this purpose you can use entity hooks. You can write your own implementation for the
following methods during the entity definition:
class Entity
before_insert()
Is called only for newly created objects before it is inserted into the database.
before_update()
Is called for entity instances before updating the instance in the database.
before_delete()
Is called before deletion the entity instance in the database.

54

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

after_insert()
Is called after the row is inserted into the database.
after_update()
Is called after the instance updated in the database.
after_delete()
Is called after the entity instance is deleted in the database.
>>> class Message(db.Entity):
...
title = Required(str)
...
content = Required(str)
...
def before_insert(self):
...
print "Before insert!"
>>> m = Message(title=First message, content=Hello, world!)
>>> commit()
Before insert!
INSERT INTO "Message" ("title", "content") VALUES (?, ?)
[uFirst message, uHello, world!]

7.8 Serializing entity instances


7.8.1 Serialization with pickle
Pony allows pickling entity instances, query results and collections. You might want to use it if you want to cache
entity instances in an external cache (e.g. memcache). When Pony pickles entity instances, it saves all attributes except
collections in order to avoid pickling a large set of data. If you need to pickle a collection attribute, you must pickle it
separately. Example:
>>> from pony.orm.examples.estore import *
>>> products = select(p for p in Product if p.price > 100)[:]
>>> products
[Product[1], Product[2], Product[6]]
>>> import cPickle
>>> pickled_data = cPickle.dumps(products)

Now we can put the pickled data to a cache. Later, when we need our instances again, we can unpickle it:
>>> products = cPickle.loads(pickled_data)
>>> products
[Product[1], Product[2], Product[6]]

You can use pickling for storing objects in an external cache for improving application performance. When you
unpickle objects, Pony adds them to the current db_session as if they were just loaded from the database. Pony
doesnt check if objects hold the same state in the database.

7.8.2 Serialization to a dictionary and to JSON


Another way to serialize entity instances is to use the to_dict() method of an entity instance or to_dict()
and to_json() functions from the pony.orm.serialization module. The instances to_dict() method
returns a key-value dictionary structure for a specific entity instance. Sometimes you might need to serialize not only
the instance itself, but also the instances related objects. In this case you can use the to_dict() function described
below.

7.8. Serializing entity instances

55

Pony ORM, Release 0.6

to_dict()
This function is used for serializing entity instances to a dictionary. It can receive an entity instance or any
iterator which returns entity instances. The function returns a multi-level dictionary which includes the objects
passed to the function, as well as the immediate related objects. Here is a structure of the resulting dict:
{
entity_name: {
primary_key_value: {
attr: value,
...
},
...
},
...
}

Lets use our online store model example (see the ER diagram) and print out the result of the to_dict()
function. Note that you need to import the to_dict function separately:
from pony.orm.examples.estore import *
from pony.orm.serialization import to_dict
print to_dict(Order[1])
{
Order: {
1: {
id: 1,
state: uDELIVERED,
date_created: datetime.datetime(2012, 10, 20, 15, 22)
date_shipped: datetime.datetime(2012, 10, 21, 11, 34),
date_delivered: datetime.datetime(2012, 10, 26, 17, 23),
total_price: Decimal(292.00),
customer: 1,
items: [1,1, 1,4],
}
}
},
Customer: {
1: {
id: 1
email: [email protected],
password: u***,
name: uJohn Smith,
country: uUSA,
address: uaddress 1,
}
},
OrderItem: {
1,1: {
quantity: 1
price: Decimal(274.00),
order: 1,
product: 1,
},
1,4: {
quantity: 2
price: Decimal(9.98),
order: 1,

56

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

product: 4,
}
}
}

In the example above the result contains the serialized Order[1] instance as well as the immediate related
objects: Customer[1], OrderItem[1, 1] and OrderItem[1, 4].
to_json()
This function uses the output of to_dict() and returns its JSON representation.

7.9 Using raw SQL


Although Pony can translate almost any condition written in Python to SQL, sometimes the need arises to use raw
SQL, for example - in order to call a stored procedure or to use a dialect feature of a specific database system. In this
case, Pony allows the user to write a query in a raw SQL, by placing it inside the function select_by_sql() or
get_by_sql() as a string:
products = Product.select_by_sql("SELECT * FROM Products")

Unlike the method select(), method select_by_sql does not return the Query object, but a list of entity
instances.
Parameters can be transferred to the string with SQL using the following syntax: $name_variable or $(expression
in Python). For example:
x = 1000
y = 500
Product.select_by_sql("SELECT * FROM Product WHERE price > $x OR price = $(y * 2)")

When Pony encounters a parameter within the SQL query it gets the variable value from the current frame (from
globals and locals) or from the dictionaries which can be passed as parameters:
Product.select_by_sql("SELECT * FROM Product WHERE price > $x OR price = $(y * 2)",
globals={x: 100}, locals={y: 200})

Variables and more complex expressions listed after the $ sign, will be automatically calculated and transferred into
the query as parameters, which makes SQL-injection impossible. Pony automatically replaces $x in the query string
with ?, %S or with other paramstyle, used in the current database system.
If the $ sign is used in the query itself (for example, in the name of a system table), it is necessary to write two $ signs
in succession: $$.

7.10 Saving objects in the database


7.10.1 Order of saving objects
Usually Pony saves objects in the database in the same order as they are created or modified. In some cases Pony can
reorder SQL INSERT statements if this is required for saving objects. Lets consider the following example:
from pony.orm import *
db = Database(sqlite, :memory:)

7.9. Using raw SQL

57

Pony ORM, Release 0.6

class TeamMember(db.Entity):
name = Required(str)
team = Optional(Team)
class Team(db.Entity):
name = Required(str)
team_members = Set(TeamMember)
db.generate_mapping(create_tables=True)
sql_debug(True)
with db_session:
john = TeamMember(name=John)
mary = TeamMember(name=Mary)
team = Team(name=Tenacity, team_members=[john, mary])

In the example above we create two team members and then a team object, assigning the team members to the team.
The relationship between TeamMember and Team objects is represented by a column in the TeamMember table:
CREATE TABLE "Team" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL
)
CREATE TABLE "TeamMember" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"team" INTEGER REFERENCES "Team" ("id")
)

When Pony creates john, mary and team objects, it understands that it should reorder SQL INSERT statements
and create an instance of the Team object in the database first, because it will allow using the team id for saving
TeamMember rows:
INSERT INTO "Team" ("name") VALUES (?)
[uTenacity]
INSERT INTO "TeamMember" ("name", "team") VALUES (?, ?)
[uJohn, 1]
INSERT INTO "TeamMember" ("name", "team") VALUES (?, ?)
[uMary, 1]

7.10.2 Cyclic chains during saving objects


Now lets say we want to have an ability to assign a captain to a team. For this purpose we need to add a couple of
attributes to our entities: Team.captain and reverse attribute TeamMember.captain_of
class TeamMember(db.Entity):
name = Required(str)
team = Optional(Team)
captain_of = Optional(Team)
class Team(db.Entity):
name = Required(str)
team_members = Set(TeamMember)
captain = Optional(TeamMember, reverse=captain_of)

58

Chapter 7. Working with entity instances

Pony ORM, Release 0.6

And here is the code for creating entity instances with a captain assigned to the team:
with db_session:
john = TeamMember(name=John)
mary = TeamMember(name=Mary)
team = Team(name=Tenacity, team_members=[john, mary], captain=mary)

When Pony tries to execute the code above it raises the following exception:
pony.orm.core.CommitException: Cannot save cyclic chain: TeamMember -> Team -> TeamMember

Why did it happen? Lets see. Pony sees that for saving the john and mary objects in the database it needs to
know the id of the team, and tries to reorder the insert statements. But for saving the team object with the captain
attribute assigned, it needs to know the id of mary object. In this case Pony cannot resolve this cyclic chain and raises
an exception.
In order to save such a cyclic chain, you have to help Pony by adding the flush() command:
with db_session:
john = TeamMember(name=John)
mary = TeamMember(name=Mary)
flush() # saves objects created by this moment in the database
team = Team(name=Tenacity, team_members=[john, mary], captain=mary)

In this case, Pony will save john and mary objects in the database first and then will issue SQL UPDATE statement
for building the relationship with the team object:
INSERT INTO "TeamMember" ("name") VALUES (?)
[uJohn]
INSERT INTO "TeamMember" ("name") VALUES (?)
[uMary]
INSERT INTO "Team" ("name", "captain") VALUES (?, ?)
[uTenacity, 2]
UPDATE "TeamMember"
SET "team" = ?
WHERE "id" = ?
[1, 2]
UPDATE "TeamMember"
SET "team" = ?
WHERE "id" = ?
[1, 1]

7.10. Saving objects in the database

59

Pony ORM, Release 0.6

60

Chapter 7. Working with entity instances

CHAPTER 8

Working with relationships

In Pony, an entity can relate to other entities through relationships. Each relationship always has two ends, and defined
by two entity attributes:
class Person(db.Entity):
cars = Set(Car)
class Car(db.Entity):
owner = Optional(Person)

In the example above weve defined one-to-many relationship between Person and Car entities using the cars and
owner attributes. Lets add a couple more data attributes to our entities and then try some examples:
from pony.orm import *
db = Database(sqlite, :memory:)
class Person(db.Entity):
name = Required(str)
cars = Set(Car)
class Car(db.Entity):
make = Required(str)
model = Required(str)
owner = Optional(Person)
db.generate_mapping(create_tables=True)

Now lets create instances of Person and Car entities:


>>> p1 = Person(name=John)
>>> c1 = Car(make=Toyota, model=Camry)
>>> commit()

Normally, in your program, you dont need to call the function commit manually, because it should be done automatically by db_session. But when you work in interactive mode, you never leave a db_session, that is why we need
to commit manually if we want to store data in the database.

8.1 Establishing a relationship


Right after weve created the instances p1 and c1, they dont have an established relationship. Lets check the values
of the relationship attributes:

61

Pony ORM, Release 0.6

>>> print c1.owner


None
>>> print p1.cars
CarSet([])

The attribute cars has an empty set.


Now lets establish a relationship between these two instances:
>>> c1.owner = p1

If we print the values of relationship attributes now, then well see the following:
>>> print c1.owner
Person[1]
>>> print p1.cars
CarSet([Car[1]])

When we assigned an owner to the Car instance, the Persons relationship attribute cars reflected the change
immediately.
We also could establish a relationship by assigning the relationship attribute during the creation of the Car instance:
>>> p1 = Person(name=John)
>>> c1 = Car(make=Toyota, model=Camry, owner=p1)

In our example the attribute owner is optional, so we can assign a value to it at any time, either during the creation of
the Car instance, or later.

8.2 Operations with collections


The attribute cars of Person entity is represented as a collection and hence we can use regular operations that
applicable to collections: add, remove, in, len, clear.
You can add or remove relationships using the add() and remove() methods:
>>> p1.cars.remove(Car[1])
>>> print p1.cars
CarSet([])
>>> p1.cars.add(Car[1])
>>> print p1.cars
CarSet([Car[1]])

You can check if a collection contains an element:


>>> Car[1] in p1.cars
True

Or make sure that there is no such element in the collection:


>>> Car[1] not in p1.cars
False

Check the collection length:

62

Chapter 8. Working with relationships

Pony ORM, Release 0.6

>>> len(p1.cars)
1

If you need to create an instance of a car and assign it with a particular person instance, there are several ways to do it.
One of the options is to call the create() method of a collection attribute:
>>> p1.cars.create(model=Toyota, make=Prius)
>>> commit()

Now we can check that a new Car instance was added to the cars collection attribute of the Person instance:
>>> print p1.cars
CarSet([Car[2], Car[1]])
>>> p1.cars.count()
2

You can iterate over a collection attribute:


>>> for car in p1.cars:
...
print car.model
Toyota
Camry

8.2.1 Attribute lifting


In Pony, the collection attributes provide an attribute lifting capability: a collection gets its items attributes.
>>> show(Car)
class Car(Entity):
id = PrimaryKey(int, auto=True)
make = Required(str)
model = Required(str)
owner = Optional(Person)
>>> p1 = Person[1]
>>> print p1.cars.model
Multiset({uCamry: 1, uPrius: 1})

Here we print out the entity class attributes using the show() function and then print the value of the model attribute
of the cars relationship attribute. The cars attribute has all the attributes of the Car entity: id, make, model
and owner. In Pony we call this a Multiset and it is implemented using a dictionary. The dictionarys key represents
the value of the attribute - Camry and Prius in our example. And the dictionarys value shows how many times it
encounters in this collection.
>>> print p1.cars.make
Multiset({uToyota: 2})

Person[1] has two Toyotas.


We can iterate over the multiset:
>>> for m in p1.cars.make:
...
print m
...
Toyota
Toyota

8.2. Operations with collections

63

Pony ORM, Release 0.6

8.2.2 Multisets
TBD:
aggregate functions
distinct
subquery in declarative queries

8.2.3 Collection attribute parameters


Collection attributes are used for defining a to-many side of a relationship. They can be used for defining one-tomany or many-to-many relationships. For example:
class Photo(db.Entity):
tags = Set(Tag, lazy=True, table=Photo_to_Tag)
class Tag(db.Entity):
photos = Set(Photo)

Here the attributes tags and photos are collections.


Below are the parameters which you can specify while creating a collection attribute.
class Set
Represents the to-many relationship.
lazy
When we access a specific collection item (check if an element belongs to a collection, add or delete
items), Pony loads the whole collection to the db_session cache. Usually it increases the performance
by reducing the database round trips. But if you have large collections you may prefer not to load them
into the cache. Setting lazy=True tells Pony that it shouldnt load the collection to the cache, but always
send queries to the database. Default is lazy=False.
reverse
Specifies the name of the attribute of related entity which is used for the relationship. This parameter
should be used when there are more than one relationship between two entities.
table
This parameter is used for many-to-many relationships only and allows you to specify the name of the
intermediate table used for representing this relationship in the database.
column
columns
reverse_column
reverse_columns
These parameters are used for many-to-many relationships and allows you to specify the name of the
intermediate columns. The columns and reverse_columns parameters receive a list and used when
the entity has a composite key. Typically you use the column or columns parameters in both relationship
attributes if you dont like the default column name.
cascade_delete
Boolean value which controls the cascade deletion of the related objects. Default value depends on the
another side of the relationship. If it is Optional - the default value is False and if it is Required
then True.
nplus1_threshold
This parameter is used for fine tuning the threshold used for the N+1 problem solution.

64

Chapter 8. Working with relationships

Pony ORM, Release 0.6

8.2.4 Collection instance methods


You can treat a collection attribute as a regular Python collection and use standard operations like in, not in, len:
class Set
len()
Returns the number of objects in the collection. If the collection is not loaded into cache, this methods
loads all the collection instances into the cache first, and then returns the number of objects. Use this
method if you are going to iterate over the objects and you need them loaded into the cache. If you dont
need the collection to be loaded into the memory, you can use the count() method.
>>> p1 = Person[1]
>>> Car[1] in p1.cars
True
>>> len(p1.cars)
2

Also there is a number of methods which you can call on a collection attribute.
class Set
Below you can find methods which you can call on a to-many relationship attribute.
add(item)
add(iter)
Adds instances to a collection and establishes a two-way relationship between entity instances:
photo = Photo[123]
photo.tags.add(Tag[Outdoors])

Now the instance of the Photo entity with the primary key 123 has a relationship with the
Tag[Outdoors] instance. The attribute photos of the Tag[Outdoors] instance contains
the reference to the Photo[123] as well.
We can also establish several relationships at once passing the list of tags to the add() method:
photo.tags.add([Tag[Party], Tag[New Year]])

remove(item)
remove(iter)
Removes an item or items from the collection and thus breaks the relationship between entity instances.
clear()
Removes all items from the collection which means breaking relationships between entity instances.
is_empty()
Returns False if there is at lease one relationship and True if this attribute has no relationships.
copy()
Returns a Python set object which contains the same items as the given collection.
count()
Returns the number of objects in the collection. This method doesnt load the collection instances into
the cache, but generates an SQL query which returns the number of objects from the database. If you are
going to work with the collection objects (iterate over the collection or change the object attributes), you
might want to use the len() method.
create(**kwargs)
Creates an returns an instance of the related entity and establishes a relationship with it:

8.2. Operations with collections

65

Pony ORM, Release 0.6

new_tag = Photo[123].tags.create(name=New tag)

is an equivalent of the following:


new_tag = Tag(name=New tag)
Photo[123].tags.add(new_tag)

load()
Loads all related objects from the database.

8.2.5 Collection class methods


This method can be called on the entity class, not instance. For example:
from pony.orm import *
db = Database(sqlite, :memory:)
class Photo(db.Entity):
tags = Set(Tag)
class Tag(db.Entity):
photos = Set(Photo)
db.generate_mapping(create_tables=True)
Photo.tags.drop_table() # drops the Photo-Tag intermediate table

class Set
drop_table(with_all_data=False)
Drops the intermediate table which is created for establishing many-to-many relationship. If the table is
not empty and with_all_data=False, the method raises the TableIsNotEmpty exception and
doesnt delete anything. Setting the with_all_data=True allows you to delete the table even if it is
not empty.

8.2.6 Collection queries


Starting with the release 0.6.1, Pony introduces queries for the relationship attributes.
You can apply select(), Query.filter(), Query.order_by(), Query.page(), Query.limit(),
Query.random() methods to the relationships to-many. The method names select and filter are synonyms.
Below you can find several examples of using these methods. Well use the University schema for showing these
queries, here are python entity definitions and Entity-Relationship diagram.
The example below selects all students with the gpa greater than 3 within the group 101:
g = Group[101]
g.students.filter(lambda student: student.gpa > 3)[:]

This query can be used for displaying the second page of group 101 students list ordered by the name attribute:
g.students.order_by(Student.name).page(2, pagesize=3)

The same query can be also written in the following form:

66

Chapter 8. Working with relationships

Pony ORM, Release 0.6

g.students.order_by(lambda s: s.name).limit(3, offset=3)

The following query returns two random students from the group 101:
g.students.random(2)

And one more example. This query returns the first page of courses which were taken by Student[1] in the second
semester, ordered by the course name:
s = Student[1]
s.courses.select(lambda c: c.semester == 2).order_by(Course.name).page(1)

8.2. Operations with collections

67

Pony ORM, Release 0.6

68

Chapter 8. Working with relationships

CHAPTER 9

Queries

Pony provides a very convenient way to query the database using the generator expression syntax. Pony allows
programmers to work with objects which are stored in a database as if they were stored in memory, using native
Python syntax. It makes development easier.

9.1 Pony ORM functions used to query the database


select(gen[, globals[, locals])
This function translates the generator expression into SQL query and returns an instance of the Query class. If
necessary, you can apply any Query method to the result, e.g. Query.order_by() or Query.count().
If you just need to get a list of objects you can either iterate over the result or get a full slice:
for p in select(p for p in Product):
print p.name, p.price
prod_list = select(p for p in Product)[:]

The select() function can also return a list of single attributes or a list of tuples:
select(p.name for p in Product)
select((p1, p2) for p1 in Product
for p2 in Product if p1.name == p2.name and p1 != p2)
select((p.name, count(p.orders)) for p in Product)

You can pass the globals and locals dictionaries for using them as global and local namespace.
Also, you can apply the select method to relationship attributes. See the examples
get(gen[, globals[, locals])
Extracts one entity instance from the database. The function returns the object if an object with the specified
parameters exists, or None if there is no such object. If there are more than one objects with the specified parameters, raises the MultipleObjectsFoundError: Multiple objects were found. Use
select(...) to retrieve them exception. Example:
get(o for o in Order if o.id == 123)

The equivalent query can be generated using the Query.get() method:


select(o for o in Order if o.id == 123).get()

69

Pony ORM, Release 0.6

left_join(gen[, globals[, locals])


The results of a left join always contain the result from the left table, even if the join condition doesnt find
any matching record in the right table.
Lets say we need to calculate the amount of orders for each customer. Lets use the example which comes with
Pony distribution and write the following query:
from pony.orm.examples.estore import *
populate_database()
select((c, count(o)) for c in Customer for o in c.orders)[:]

It will be translated to the following SQL:


SELECT "c"."id", COUNT(DISTINCT "o"."id")
FROM "Customer" "c", "Order" "o"
WHERE "c"."id" = "o"."customer"
GROUP BY "c"."id"

And return the following result:


[(Customer[1], 2), (Customer[2], 1), (Customer[3], 1), (Customer[4], 1)]

But if there are customers that have no orders, they will not be selected by this query, because the condition
WHERE "c"."id" = "o"."customer" doesnt find any matching record in the Order table. In order to
get the list of all customers, we should use the left_join function:
left_join((c, count(o)) for c in Customer for o in c.orders)[:]
SELECT "c"."id", COUNT(DISTINCT "o"."id")
FROM "Customer" "c"
LEFT JOIN "Order" "o"
ON "c"."id" = "o"."customer"
GROUP BY "c"."id"

Now we will get the list of all customers with the number of order equal to zero for customers which have no
orders:
[(Customer[1], 2), (Customer[2], 1), (Customer[3], 1), (Customer[4], 1), (Customer[5], 0)]

We should mention that in most cases Pony can understand where LEFT JOIN is needed. For example, the same
query can be written this way:
select((c, count(c.orders)) for c in Customer)[:]
SELECT "c"."id", COUNT(DISTINCT "order-1"."id")
FROM "Customer" "c"
LEFT JOIN "Order" "order-1"
ON "c"."id" = "order-1"."customer"
GROUP BY "c"."id"

count(gen)
Returns the number of objects that match the query condition. Example:
count(c for c in Customer if len(c.orders) > 2)

This query will be translated to the following SQL:


SELECT COUNT(*)
FROM "Customer" "c"
LEFT JOIN "Order" "order-1"

70

Chapter 9. Queries

Pony ORM, Release 0.6

ON "c"."id" = "order-1"."customer"
GROUP BY "c"."id"
HAVING COUNT(DISTINCT "order-1"."id") > 2

The equivalent query can be generated using the Query.count() method:


select(c for c in Customer if len(c.orders) > 2).count()

min(gen)
Returns the minimum value from the database. The query should return a single attribute:
min(p.price for p in Product)

The equivalent query can be generated using the Query.min() method:


select(p.price for p in Product).min()

max(gen)
Returns the maximum value from the database. The query should return a single attribute:
max(o.date_shipped for o in Order)

The equivalent query can be generated using the Query.max() method:


select(o.date_shipped for o in Order).max()

sum(gen)
Returns the sum of all values selected from the database:
sum(o.total_price for o in Order)

The equivalent query can be generated using the Query.sum() method:


select(o.total_price for o in Order).sum()

If the query returns no items, the sum() method returns 0.


avg(gen)
Returns the average value for all selected attributes:
avg(o.total_price for o in Order)

The equivalent query can be generated using the Query.avg() method:


select(o.total_price for o in Order).avg()

exists(gen[, globals[, locals])


Returns True if at least one instance with the specified condition exists and False otherwise:
exists(o for o in Order if o.date_delivered is None)

distinct(gen)
When you need to force DISTINCT in a query, it can be done using the distinct() function:
distinct(o.date_shipped for o in Order)

But usually this is not necessary, because Pony adds DISTINCT keyword automatically in an intelligent way.
See more information about it in the Automatic DISTINCT section later in this chapter.
Another usage of distinct() function is with the sum() aggregate function - you can write:

9.1. Pony ORM functions used to query the database

71

Pony ORM, Release 0.6

select(sum(distinct(x.val)) for x in X)

to generate the following SQL:


SELECT SUM(DISTINCT x.val)
FROM X x

but it is rarely used in practice.


desc()
desc(attribute)
This function is used inside Query.order_by() for ordering in descending order.

9.2 Query object methods


class Query
[start:end]
limit(limit, offset=None)
This method is used for limiting the number of instances selected from the database. In the example below
we select the first ten instances:
select(c for c in Customer).order_by(Customer.name).limit(10)

Generates the following SQL:


SELECT "c"."id", "c"."email", "c"."password", "c"."name", "c"."country", "c"."address"
FROM "Customer" "c"
ORDER BY "c"."name"
LIMIT 10

The same effect can be reached using the Python slice operator:
select(c for c in Customer).order_by(Customer.name)[:10]

If we need select instances with offset, we should use the second parameter:
select(c for c in Customer).order_by(Customer.name).limit(10, 20)

Or using the slice operator:


select(c for c in Customer).order_by(Customer.name)[20:30]

It generates the following SQL:


SELECT "c"."id", "c"."email", "c"."password", "c"."name", "c"."country", "c"."address"
FROM "Customer" "c"
ORDER BY "c"."name"
LIMIT 10 OFFSET 20

Also you can use the page() method for the same purpose.
avg()
Returns the average value for all selected attributes:
select(o.total_price for o in Order).avg()

The function avg() does a similar thing.

72

Chapter 9. Queries

Pony ORM, Release 0.6

count()
Returns the number of objects that match the query condition:
select(c for c in Customer if len(c.orders) > 2).count()

The function count() does a similar thing.


distinct()
Forces DISTINCT in a query:
select(c.name for c in Customer).distinct()

But usually this is not necessary, because Pony adds DISTINCT keyword automatically in an intelligent
way. See more information about it in the Automatic DISTINCT section later in this chapter. The function
distinct() does a similar thing.
exists()
Returns True if at least one instance with the specified condition exists and False otherwise:
select(c for c in Customer if len(c.cart_items) > 10).exists()

This query generates the following SQL:


SELECT "c"."id"
FROM "Customer" "c"
LEFT JOIN "CartItem" "cartitem-1"
ON "c"."id" = "cartitem-1"."customer"
GROUP BY "c"."id"
HAVING COUNT(DISTINCT "cartitem-1"."id") > 20
LIMIT 1

filter(lambda[, globals[, locals])


filter(str)
The filter() method of the Query object is used for filtering the result of a query. The conditions
which are passed as parameters to the filter() method will be translated into the WHERE section of
the resulting SQL query.
Before Pony ORM release 0.5 the filter() method affected the underlying query updating the query
in-place, but since the release 0.5 it creates and returns a new Query object with the applied conditions.
The number of filter() arguments should correspond to the query result. The filter() method can
receive a lambda expression with a condition:
q = select(p for p in Product)
q2 = q.filter(lambda x: x.price > 100)
q = select((p.name, p.price) for p in Product)
q2 = q.filter(lambda n, p: n.name.startswith("A") and p > 100)

Also the filter() method can receive a text string where you can specify just the expression:
q = select(p for p in Product)
x = 100
q2 = q.filter("p.price > x")

Another way to filter the query result is to pass parameters in the form of named arguments:
q = select(p for p in Product)
q2 = q.filter(price=100, name="iPod")

first()
Returns the first element from the selected results or None if no objects were found:
9.2. Query object methods

73

Pony ORM, Release 0.6

select(p for p in Product if p.price > 100).first()

for_update(nowait=False)
Sometimes there is a need to lock objects in the database in order to prevent other transactions from
modifying the same instances simultaneously. Within the database such lock should be done using the
SELECT FOR UPDATE query. In order to generate such a lock using Pony you can call the for_update
method:
select(p for p in Product if p.picture is None).for_update()[:]

This query selects all instances of Product without a picture and locks the corresponding rows in the
database. The lock will be released upon commit or rollback of current transaction.
get()
Extracts one entity instance from the database. The function returns the object if an object with the specified parameters exists, or None if there is no such object. If there are more than one objects with the
specified parameters, raises the MultipleObjectsFoundError: Multiple objects were
found. Use select(...) to retrieve them exception. Example:
select(o for o in Order if o.id == 123).get()

The function get() does a similar thing.


max()
Returns the maximum value from the database. The query should return a single attribute:
select(o.date_shipped for o in Order).max()

The function max() does a similar thing.


min()
Returns the minimum value from the database. The query should return a single attribute:
select(p.price for p in Product).min()

The function min() does a similar thing.


order_by(attr1[, attr2, ... ])
order_by(pos1[, pos2, ... ])
order_by(lambda[, globals[, locals])
order_by(str)
This method is used for ordering the results of a query. There are several options options available:
Using entity attributes
select(o for o in Order).order_by(Order.customer, Order.date_created)

For ordering in descending order, use the function desc() or the method desc() of any attribute:
select(o for o in Order).order_by(Order.date_created.desc())

Which is similar to:


select(o for o in Order).order_by(desc(Order.date_created))

Using position of query result variables


select((o.customer.name, o.total_price) for o in Order).order_by(-2, 1)

74

Chapter 9. Queries

Pony ORM, Release 0.6

Minus means sorting in descending order. In this example we sort the result by the total price in descending
order and by the customer name in ascending order.
Using lambda
select(o for o in Order).order_by(lambda o: (o.customer.name, o.date_shipped))

If the lambda has a parameter (o in our example) then o represents the result of the select and will be
applied to it. If you specify the lambda without a parameter, then inside lambda you have access to all
names defined inside the query:
select(o.total_price for o in Order).order_by(lambda: o.customer.id)

Using a string
This approach is similar to the previous one, but you specify the body of a lambda as a string:
select(o for o in Order).order_by("o.customer.name, o.date_shipped")

page(pagenum, pagesize=10)
Pagination is used when you need to display results of a query divided into multiple pages. The page
numbering starts with page 1. This method returns a slice [start:stop] where start = (pagenum 1) * pagesize, stop = pagenum * pagesize.
prefetch()
Allows you to specify which related objects or attributes should be loaded from the database along with
the query result.
Usually there is no need to prefetch related objects. When you work with the query result within the
@db_session, Pony gets all related objects once you need them. Pony uses the most effective way for
loading related objects from the database, avoiding the N+1 Query problem.
So, if you use Flask, the recommended approach is to use the @db_session decorator at the top level,
at the same place where you put the Flasks app.route decorator:
@app.route(/index)
@db_session
def index():
...
objects = select(...)
...
return render_template(template.html, objects=objects)

Or, even better, wrapping the wsgi application with the db_session decorator:
app.wsgi_app = db_session(app.wsgi_app)

If for some reason you need to pass the selected instances along with related objects outside of the
db_session, then you can use this method. Otherwise, if youll try to access the related objects outside
of the db_session, you might get the DatabaseSessionIsOver exception, e.g.:
DatabaseSessionIsOver: Cannot load attribute Customer[3].name: the database session is over

More information regarding working with the db_session can be found here.
You can specify entities and/or attributes as parameters. When you specify an entity, then all to-one
and non-lazy attributes of corresponding related objects will be prefetched. The to-many attributes of an
entity are prefetched only when specified explicitly.

9.2. Query object methods

75

Pony ORM, Release 0.6

If you specify an attribute, then only this specific attribute will be prefetched. You can specify attribute
chains, e.g. order.customer.address. The prefetching works recursively - it applies the specified parameters
to each selected object.
Examples:
from pony.orm.examples.presentation import *

Loading Student objects only, without prefetching:


students = select(s for s in Student)[:]

Loading students along with groups and departments:


students = select(s for s in Student).prefetch(Group, Department)[:]
for s in students: # no additional query to the DB will be sent
print s.name, s.group.major, s.group.dept.name

The same as above, but specifying attributes instead of entities:


students = select(s for s in Student).prefetch(Student.group, Group.dept)[:]
for s in students: # no additional query to the DB will be sent
print s.name, s.group.major, s.group.dept.name

Loading students and related courses (many-to-many relationship):


students = select(s for s in Student).prefetch(Student.courses)
for s in students:
print s.name
for c in s.courses: # no additional query to the DB will be sent
print c.name

random(limit)
Selects limit random objects from the database. This method will be translated using the ORDER BY
RANDOM() SQL expression. The entity class method select_random() provides better performance,
although doesnt allow to specify query conditions.
show()
Prints the results of a query to the console. The result is formatted in the form of a table. This method
doesnt display to-many attributes because it would require additional query to the database and could
be bulky.
sum()
Return the sum of all selected items. Can be applied to the queries which return a single numeric expression
only. Example:
select(o.total_price for o in Order).sum()

If the query returns no items, the query result will be 0.


without_distinct()
By default Pony tries to avoid duplicates in the query result and intellectually adds the DISTINCT SQL
keyword to a query where it thinks it necessary. If you dont want Pony to add DISTINCT and get possible
duplicates, you can use this method. This method returns a new instance of the Query object, so you can
chain it with other query methods:

76

Chapter 9. Queries

Pony ORM, Release 0.6

select(p.name for p in Person).without_distinct().order_by(Person.name)

Before Pony Release 0.6 the method without_distinct() returned query result and not a new query
instance.

9.3 Automatic DISTINCT


Pony tries to avoid duplicates in a query result by automatically adding the DISTINCT SQL keyword where it is
necessary, because useful queries with duplicates are very rare. When someone wants to retrieve objects with a
specific criteria, they typically dont expect that the same object will be returned more than once. Also, avoiding
duplicates makes the query result more predictable: you dont need to filter duplicates out of a query result.
Pony adds the DISCTINCT keyword only when there could be potential duplicates. Lets consider a couple of examples.
1. Retrieving objects with a criteria:
select(p for p in Person if p.age > 20 and p.name == "John")

In this example, the query doesnt return duplicates, because the result contains the primary key column of a Person.
Since duplicates are not possible here, there is no need in the DISTINCT keyword, and Pony doesnt add it:
SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
WHERE "p"."age" > 20
AND "p"."name" = John

2. Retrieving object attributes:


select(p.name for p in Person)

The result of this query returns not objects, but its attribute. This query result can contain duplicates, so Pony will add
DISTINCT to this query:
SELECT DISTINCT "p"."name"
FROM "Person" "p"

The result of a such query typically used for a dropdown list, where duplicates are not expected. It is not easy to come
up with a real use-case when you want to have duplicates here.
If you need to count persons with the same name, youd better use an aggregate query:
select((p.name, count(p)) for p in Person)

But if it is absolutely necessary to get all persons names, including duplicates, you can do so by using the
Query.without_distinct() method:
select(p.name for p in Person).without_distinct()

3. Retrieving objects using joins:


select(p for p in Person for c in p.cars if c.make in ("Toyota", "Honda"))

This query can contain duplicates, so Pony eliminates them using DISTINCT:
SELECT DISTINCT "p"."id", "p"."name", "p"."age"
FROM "Person" "p", "Car" "c"
WHERE "c"."make" IN (Toyota, Honda)
AND "p"."id" = "c"."owner"

9.3. Automatic DISTINCT

77

Pony ORM, Release 0.6

Without using DISTINCT the duplicates are possible, because the query uses two tables (Person and Car), but only
one table is used in the SELECT section. The query above returns only persons (and not their cars), and therefore it
is typically not desirable to get the same person in the result more than once. We believe that without duplicates the
result looks more intuitive.
But if for some reason you dont need to exclude duplicates, you always can add .without_disctinct() to the
query:
select(p for p in Person for c in p.cars
if c.make in ("Toyota", "Honda")).without_distinct()

The user probably would like to see the Person objects duplicates if the query result contains cars owned by each
person. In this case the Pony query would be different:
select((p, c) for p in Person for c in p.cars if c.make in ("Toyota", "Honda"))

And in this case Pony will not add the DISTINCT keyword to SQL query.
To summarize:
1. The principle all queries do not return duplicates by default is easy to understand and doesnt lead to surprises.
2. Such behavior is what most users want in most cases.
3. Pony doesnt add DISTINCT when a query is not supposed to have duplicates.
4. The query method without_distinct() can be used for forcing Pony do not eliminate duplicates.

9.4 Functions which can be used inside Query


Here is the list of functions that can be used inside a generator query:
min, max, avg, sum, count, len, concat, abs, random, select, exists
Examples:
select(avg(c.orders.total_price) for c in Customer)[:]
SELECT AVG("order-1"."total_price")
FROM "Customer" "c"
LEFT JOIN "Order" "order-1"
ON "c"."id" = "order-1"."customer"
select(o for o in Order if o.customer in
select(c for c in Customer if c.name.startswith(A)))[:]
SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped",
"o"."date_delivered", "o"."total_price", "o"."customer"
FROM "Order" "o"
WHERE "o"."customer" IN (
SELECT "c"."id"
FROM "Customer" "c"
WHERE "c"."name" LIKE A%
)

78

Chapter 9. Queries

CHAPTER 10

Aggregation

Pony allows the use of five aggregate functions in declarative queries: sum, count, min, max, and avg. Lets see
some examples of simple queries using these functions.
Total GPA of students from group 101:
sum(s.gpa for s in Student if s.group.number == 101)

Number of students with a GPA above three:


count(s for s in Student if s.gpa > 3)

First name of a student, who studies philosophy, sorted alphabetically:


min(s.name for s in Student if "Philosophy" in s.courses.name)

Birth date of the youngest student in group 101:


max(s.dob for s in Student if s.group.number == 101)

Average GPA in department 44:


avg(s.gpa for s in Student if s.group.dept.number == 44)

Note: Although Python already has standard functions for sum, count, min, and max, Pony adds its own functions
under the same names. Also, Pony adds its own avg function. These functions are implemented in the pony.orm
module and they can be imported from there either by the star, or by the name.
Functions implemented in Pony expand the behavior of standard functions in Python; thus, if in a program these
functions are used in their standard designation, the import will not affect their behavior. But it also allows you to
specify a declarative query inside the function.
If one forgets to import, then an error will appear upon use of the Python standard functions sum, count, min, and
max with a declarative query as a parameter:
TypeError: Use a declarative query in order to iterate over entity

Aggregate functions can also be used inside a query. For example, if we need to find not only the birth date of the
youngest student in the group, but also the student himself:
select(s for s in Student
if s.group.number == 101
and s.dob == max(s.dob for s in Student
if s.group.number == 101))

79

Pony ORM, Release 0.6

Or, for example, to list all groups with an average GPA above 4.5:
select(g for g in Group if avg(s.gpa for s in g.students) > 4.5)

This query can be shorter if we use Ponys attribute propagation feature:


select(g for g in Group if avg(g.students.gpa) > 4.5)

10.1 Several aggregate functions in one query


SQL allows you to include several aggregate functions in the same query. For example, we might want to receive both
the lowest and the highest GPA for each group. In SQL, such a query would look like this:
SELECT s.group_number, MIN(s.gpa), MAX(s.gpa)
FROM Student s
GROUP BY s.group_number

This request will return the lowest and the highest GPA for each group. Pony allows you to use the same approach:
select((s.group, min(s.gpa), max(s.gpa)) for s in Student)

10.2 Grouping
Queries in Pony look shorter than a similar queries in SQL, since in SQL we have to indicate a GROUP BY section.
Pony, on the other hand, understands the need for this section and includes it automatically. How does Pony do it?
One might note that the GROUP BY SQL query section includes the columns, which are also included in the SELECT
section, and are not included in aggregative functions. That is, it is necessary to duplicate the list of these columns
in SQL. Pony avoids this duplication, as it understands that if an expression is included in a query result and is not
included in the aggregative function, it should be added to the GROUP BY section.

10.3 Function count


Aggregative queries often request to calculate the quantity of something, and in Pony this request is served by the
function count. For example, we want to count the number of students in Group 101:
count(s for s in Student if s.group.number == 101)

Or the number of students in each group related to 44th Department:


select((g, count(g.students)) for g in Group if g.dept.number == 44)

or:
select((s.group, count(s)) for s in Student if s.group.dept.number == 44)

In the first example the aggregate function count receives a collection, and Pony will translate it into a subquery
(although Pony will try to optimize the query and replace it with LEFT JOIN).
In the second example, the function count receives a single object instead of a collection. In this case Pony will add
a GROUP BY section to the SQL query and the grouping will be done on the s.group attribute.
If you use the count() function without arguments, this will be translated to COUNT(*). If you specify an argument,
it will be translated to COUNT(DISTINCT column)
80

Chapter 10. Aggregation

Pony ORM, Release 0.6

10.4 Conditional COUNT


There is also another way to use the COUNT function. Lets assume that we want to calculate three numbers for each
group - the number of students that have a GPA less than 3, the number of students with GPA between 3 to 4, and the
number of students with GPA higher than 4. A traditional expression of this query would be cumbersome:
select((g, count(s for s in g.students if s.gpa <= 3),
count(s for s in g.students if s.gpa > 3 and s.gpa <= 4),
count(s for s in g.students if s.gpa > 4)) for g in Group)

not only would this query be pretty long, but it would also be very ineffective, as it will execute each COUNT as a
separate subquery. For these cases, Pony has a conditional COUNT syntax:
select((s.group, count(s.gpa <= 3),
count(s.gpa > 3 and s.gpa <= 4),
count(s.gpa > 4)) for s in Student)

This way, we indicate in the count function a certain condition, rather than a column; and count calculates the
number of objects for which this condition is true. This query will not include subqueries which makes it more
effective.
Note: The queries above are not entirely equivalent: if a group doesnt have any students, then the first query will
select that group having zeros as the result of count, while the second query simply will not select the group at all.
This happens because the second query selects the rows from the table Student, and if the group doesnt have any
students, then the table Student will not have any rows for this group.
If we want to get rows with zeros, then an effective SQL query should use LEFT JOIN:
left_join((g, count(s.gpa <= 3),
count(s.gpa > 3 and s.gpa <= 4),
count(s.gpa > 4)) for g in Group for s in g.students)

10.5 More complex grouping options


Pony allows you to carry out grouping not only by object attributes, but also by more complex expressions such
as grouping a set of students by birth year and calculating their average GPA. Birth year in this case is not a distinct
attribute it is a part of the dob attribute. Therefore, the query will look like this:
select((s.dob.year, avg(s.gpa)) for s in Student)

Similarly, inside aggregate functions you can indicate not only simple attributes, but also expressions. For example,
lets suppose we have the database of an internet retailer, which contains information regarding goods and orders:
select((item.order, sum(item.price * item.quantity))
for item in OrderItem if item.order.id == 123)

or like this:
select((order, sum(order.items.price * order.items.quantity))
for order in Order if order.id == 123)

In the second case, we make use of the attribute propagation concept, and the expression order.items.price
creates an array of prices, while order.items.quantity generates an array of quantities. It might appear, that
these two arrays are impossible to multiply correctly, as they are not just numbers, but Pony can do the right thing
and multiply the quantity by the price for each order item.

10.4. Conditional COUNT

81

Pony ORM, Release 0.6

As usual, the option with attribute propagation is translated to the subquery, while the first option is translated to the
more effective grouping query.

10.6 Queries with HAVING


SELECT construction in SQL includes two sections, conditions can be written using WHERE and HAVING. The
WHERE component includes those conditions that are applied before the grouping, while the HAVING conditions are
applied after the grouping. In Pony, all conditions in a query are written after if. If Pony recognizes the use of an
aggregative function that includes a single condition, rather than a subquery, it understands that this condition should
be applied to the HAVING section.
Lets assume that we want to write a query that lists the groups of 44th Department with average GPAs higher than
4.0, and the number of students in every such group. This type of query can be written like:
select((s.group, count(s)) for s in Student
if s.group.dept.number == 44 and avg(s.gpa) > 4)

In this query, the if section includes two conditions. The first condition s.group.dept.number = 44 is not
included in the aggregative functions and therefore it will be used as a WHERE condition; while the second condition
avg(s.gpa) > 4 is passed to the avg function, and thus will be used as a HAVING condition.
Note: It is assumed that conditions are separated by a logical and; that is, if conditions are separated by or, then
Pony will assume it is a single condition and put it entirely in the HAVING section.
If a condition intended for the HAVING section has an expression located outside the limits of the aggregate functions,
and at the same time is not contained by GROUP BY, it will be added to GROUP BY.
For example, if we want to find orders where the total order price differs from the sum of the order items (due to a
discount), our query would look like this:
select((item.order, item.order.total_price,
sum(item.price * item.quantity))
for item in OrderItem
if item.order.total_price < sum(item.price * item.quantity))

In this query, the condition contains an aggregate function; this is why it will go into the HAVING section. The GROUP
BY section will contain item.order, because it is indicated in the list of criteria. But besides this, the GROUP BY
section will contain item.order.total_price, because this attribute falls into the HAVING section and is not
inside the aggregate function. Why is this attribute added? Because without it, a DBMS such as Oracle, PostgreSQL
and Microsoft SQL Server will refuse to execute the query, and will return a syntax error. In any case, this is a standard
requirement of SQL.
In this case, an order has a single value total_price, therefore adding a column will not affect the result. It is
importart to be careful here, since additing extra columns might lead to grouping based on smaller row groups which
could affect the result of the query. In general, creating queries with conditions in the HAVING section requires high
level of professionalism.

10.7 Query optimization


When the speed of a query is an important factor, we can construct the query in such a way that will force the database
to use grouping instead of subqueries. However, finding a way to create such an optimized query is not always simple.
In such cases, we can use the special function called JOIN, which serves as a hint to Pony that we want to use JOIN,
instead of generating subqueries.

82

Chapter 10. Aggregation

Pony ORM, Release 0.6

Lets assume that we need to create the following query: find all groups, where the highest GPA is lower than 4.0. We
can use this expression:
select(g for g in Group if max(g.students.gpa) < 4)

If we do not want to search by way of subqueries, we can simply wrap an expression in a JOIN function, which should
join the relevant tables:
select(g for g in Group if JOIN(max(g.students.gpa) < 4))

We used JOIN to wrap the whole condition, and received an optimized query as an outcome.
In this specific case, we could try to find a formulation, which would make an effective request without using the JOIN
function:
select(s.group for s in Student if max(s.gpa) < 4)

However, if a declarative expression includes more than one query, we will not be able to find better formulation for
the query, and we will have to use the JOIN hint.

10.8 Aggregation queries with sorting


Lets suppose that we want, for each group, to calculate average GPA and sort the results so that groups with the lowest
average GPA appear first. We can accomplish the sorting like this:
select((s.group, avg(s.gpa)) for s in Student) \
.order_by(lambda: avg(s.gpa))

If we want to sort the rows in reverse order, we can use the desc() function:
select((s.group, avg(s.gpa)) for s in Student) \
.order_by(lambda: desc(avg(s.gpa)))

In other words, from the received query we call up the order_by method, passing it a lambda function without parameters, in which we parenthetically list the sorting expressions, using the same variable names as in the actual
query.
Another variation, simpler but also more limited, would be to parenthetically indicate in the order_by method the
number of the column (starting with 1), that we wish to sort by. A negative number indicates sorting by descending.
Using this method, the two queries mentioned above will look like this:
Ascending by the second column:
select((s.group, avg(s.gpa)) for s in Student).order_by(2)

descending by the second column:


select((s.group, avg(s.gpa)) for s in Student).order_by(-2)

If necessary, aggregative functions can be listed as methods. That is, there are two possible options:
select(sum(s.gpa) for s in Student)
select(s.gpa for s in Student).sum()

and so on for other functions.

10.8. Aggregation queries with sorting

83

Pony ORM, Release 0.6

84

Chapter 10. Aggregation

Index

A
add() (Set method), 65
after_delete() (Entity method), 55
after_insert() (Entity method), 54
after_update() (Entity method), 55
allowed_exceptions, 40
auto, 26
avg() (built-in function), 71
avg() (Query method), 72

B
before_delete() (Entity method), 54
before_insert() (Entity method), 54
before_update() (Entity method), 54

C
cascade_delete, 27
cascade_delete (Set attribute), 64
clear() (Set method), 65
column, 27
column (Set attribute), 64
columns, 27
columns (Set attribute), 64
commit() (built-in function), 39
commit() (Database method), 15
copy() (Set method), 65
count() (built-in function), 70
count() (Query method), 72
count() (Set method), 65
create() (Set method), 65
create_tables() (Database method), 14

D
Database (built-in class), 14, 15, 17
Database.QueryStat (built-in class), 17
default, 26
delete() (Entity method), 52
desc() (built-in function), 72
describe() (Entity method), 50
disconnect() (Database method), 17

distinct() (built-in function), 71


distinct() (Query method), 73
drop_all_tables() (Database method), 14
drop_table() (Database method), 14
drop_table() (Entity method), 50
drop_table() (Set method), 66

E
Entity (built-in class), 50, 52, 54
Entity (Database attribute), 15
execute() (Database method), 17
exists() (built-in function), 71
exists() (Database method), 16
exists() (Entity method), 50
exists() (Query method), 73

F
filter() (Query method), 73
first() (Query method), 73
flush() (built-in function), 39
flush() (Database method), 15
flush() (Entity method), 54
for_update() (Query method), 74

G
generate_mapping() (Database method), 14
get() (built-in function), 69
get() (Database method), 16
get() (Entity method), 51
get() (Query method), 74
get_by_sql() (Entity method), 51
get_connection() (Database method), 17
get_for_update() (Entity method), 51
get_pk() (Entity method), 52
global_stats, 18

I
immediate, 40
index, 26
insert() (Database method), 16
85

Pony ORM, Release 0.6

is_empty() (Set method), 65

L
last_sql (Database attribute), 15
lazy, 26
lazy (Set attribute), 64
left_join() (built-in function), 69
len() (Set method), 65
limit() (Query method), 72
load() (Entity method), 51
load() (Set method), 66
local_stats (Database attribute), 17

M
max() (built-in function), 71
max() (Query method), 74
merge_local_stats(), 17
min() (built-in function), 71
min() (Query method), 74

select_by_sql() (Entity method), 51


select_random() (Entity method), 51
sequence_name, 27
serializable, 40
Set (built-in class), 6466
set() (Entity method), 52
show() (Query method), 76
sql_default, 26
sql_type, 26
sum() (built-in function), 71
sum() (Query method), 76

T
table, 27
table (Set attribute), 64
to_dict() (built-in function), 55
to_dict() (Entity method), 52
to_json() (built-in function), 57

unique, 26

nplus1_threshold (Set attribute), 64


nullable, 27

O
order_by() (Query method), 74

volatile, 27

W
without_distinct() (Query method), 76

page() (Query method), 75


prefetch() (Query method), 75
py_check, 27

Q
Query (built-in class), 72

R
random() (Query method), 76
remove() (Set method), 65
retry, 40
retry_exceptions, 40
reverse, 27
reverse (Set attribute), 64
reverse_column, 27
reverse_column (Set attribute), 64
reverse_columns, 27
reverse_columns (Set attribute), 64
rollback() (built-in function), 39
rollback() (Database method), 15

S
select() (built-in function), 69
select() (Database method), 15
select() (Entity method), 51
86

Index

You might also like