Writing queries

Now that we have the 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:

  1. >>> select(p for p in Person if p.age > 20)
  2. <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:

  1. >>> select(p for p in Person if p.age > 20)[:]
  2. SELECT "p"."id", "p"."name", "p"."age"
  3. FROM "Person" "p"
  4. WHERE "p"."age" > 20
  5. [Person[2], Person[3]]

As the result you can 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, the entity instance is represented by the entity name and its primary key written in square brackets, e.g. Person[2].

For ordering the resulting list you can use the Query.order_by() method. If you need only a portion of the result set, you can use the slice operator, the exact same way as you would do that on a Python list. For example, if you want to sort all people by their name and extract the first two objects, you do it this way:

  1. >>> select(p for p in Person).order_by(Person.name)[:2]
  2. SELECT "p"."id", "p"."name", "p"."age"
  3. FROM "Person" "p"
  4. ORDER BY "p"."name"
  5. LIMIT 2
  6. [Person[3], Person[1]]

Sometimes, when working in the interactive mode, you might want to see the values of all object attributes. For this purpose, you can use the Query.show() method:

  1. >>> select(p for p in Person).order_by(Person.name)[:2].show()
  2. SELECT "p"."id", "p"."name", "p"."age"
  3. FROM "Person" "p"
  4. ORDER BY "p"."name"
  5. LIMIT 2
  6. id|name|age
  7. --+----+---
  8. 3 |Bob |30
  9. 1 |John|20

The Query.show() method doesn’t 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:

  1. >>> Car.select().show()
  2. id|make |model |owner
  3. --+------+--------+---------
  4. 1 |Toyota|Prius |Person[2]
  5. 2 |Ford |Explorer|Person[3]

If you don’t want to get a list of objects, but need to iterate over the resulting sequence, you can use the for loop without using the slice operator:

  1. >>> persons = select(p for p in Person if 'o' in p.name)
  2. >>> for p in persons:
  3. ... print p.name, p.age
  4. ...
  5. SELECT "p"."id", "p"."name", "p"."age"
  6. FROM "Person" "p"
  7. WHERE "p"."name" LIKE '%o%'
  8. John 20
  9. Bob 30

In the example above we get all Person objects with the name attribute containing the letter ‘o’ and display the person’s name and age.

A query does not necessarily have to return entity objects. For example, you can get a list, consisting of the object attribute:

  1. >>> select(p.name for p in Person if p.age != 30)[:]
  2. SELECT DISTINCT "p"."name"
  3. FROM "Person" "p"
  4. WHERE "p"."age" <> 30
  5. [u'John', u'Mary']

Or a list of tuples:

  1. >>> select((p, count(p.cars)) for p in Person)[:]
  2. SELECT "p"."id", COUNT(DISTINCT "car-1"."id")
  3. FROM "Person" "p"
  4. LEFT JOIN "Car" "car-1"
  5. ON "p"."id" = "car-1"."owner"
  6. GROUP BY "p"."id"
  7. [(Person[1], 0), (Person[2], 1), (Person[3], 1)]

In the example above we get a list of tuples consisting of a Person object and the number of cars they own.

With Pony you can also run aggregate queries. Here is an example of a query which returns the maximum age of a person:

  1. >>> print max(p.age for p in Person)
  2. SELECT MAX("p"."age")
  3. FROM "Person" "p"
  4. 30

In the following parts of this manual you will see how you can write more complex queries.