[PonyORM-list] Pony ORM Release 0.6.1

Alexey Malashkevich alexeymalashkevich at gmail.com
Tue Feb 24 19:05:22 UTC 2015

Hi all,

With Pony release 0.6.1 we take into account our users feedback and
introduce some new cool features.

Using queries for collections (relationship attributes)

Now you can apply Entity.select, Query.order_by, Query.page, Query.limit,
Query.random methods to the relationships to-many.

Below you can find several examples of using these methods. We’ll use the
University schema for showing these queries, here are python entity
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
student’s 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 way:

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

The following query returns two random students from the group 101:


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 ==

Now you can pass globals and locals to queries

It allows you to create a context for executing your queries. Example:

    Student.select(lambda s: s.gpa > x, {'x' : 3})
    # or
    select("s for s in Student if s.gpa > x", {'x' : 3})

Even if the variable x has another value within the outer scope, the value
from the dictionary that we pass to the query overrides it.

It behaves the same way as for the standard Python eval expression.

Here is the list of methods and functions that can receive globals and
locals starting with this release:

select, left_join, get, exists, Entity.select, Entity.exists, Entity.get,
Entity.get_for_update, Query.order_by, Query.filter

Improved inheritance support in queries

Now you can iterate over the base entity and use attributes of subclasses
in query conditions:

    select(x for x in BaseClass if x.subclass_attr == y)

As an example, let’s say you want to extract all employee and manager
objects which have their salary or bonus greater then some amount x. We
have classes Employee and Manager inherited from the class Person:

    class Person(db.Entity):
        name = Required(str)

    class Employee(Person):
        salary = Required(Decimal)

    class Manager(Employee):
        bonus = Required(Decimal)

Here is the query:

    select(p for p in Person if p.salary > x or p.bonus > x)

The entity Person doesn’t have the attributes salary and bonus, but the
fact that the descendant classes have it, allows us to use this attribute
in the query conditions section.

db.insert() can receive both table name or entity name

Object of the Database class can be used for direct access to the database.
Now you can specify either the table name or the entity name when usingh
the insert() method:

    db.insert(SomeEntity, column1=x, column2=y)
    # is equal to
    db.insert(SomeEntity._table_, column1=x, column2=y)

When you specify an entity, Pony will use the table which is mapped to this

Discriminator attribute can be part of the composite index

    class Person(db.Entity):
        cls_id = Discriminator(int)
        _discriminator_ = 1
        name = Required(str)
        composite_key(cls_id, name)

Attribute name instead of the attribute itself

Now it is possible to specify the attribute name instead of the attribute
itself in composite index. It can be used if you want to use an
automatically generated attribute (e.g. classtype) as a part of a composite
Let’s use the same example again. Now, in composite_key instead of the name
attribute, you can use the string representation of it:

    class Person(db.Entity):
        cls_id = Discriminator(int)
        _discriminator_ = 1
        name = Required(str)
        composite_key(cls_id, 'name')

Query statistics: global_stats_lock is deprecated

global_stats_lock is deprecated, just use global_stats property without any
Pony gathers statistics on executed queries. Previously you had to acqire
lock on global_stats_lock attribute before accessing the global_stats
property. Now Pony does it itself and you don’t need to bother about it

New load() method for entity instances

The new load() method 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 won’t be loaded again. You can specify
the list of the attributes which need to be loaded, or it’s names. In this
case Pony will load only them:

    p = Person[123]
    p.load(Person.biography, Person.some_other_field)
You can use the string attribute names too:

    p = Person[123]
    p.load('biography', 'some_other_field')

Usually, when Pony loads lazy attributes only when you access them. But if
your object has a lot of lazy attributes and you know that you’re going to
need all of them, it is more optimal to load all of them at once using the
load() method.

New load() method for collections

This method loads all related objects from the database. It is useful when
you intend to work with a collection and want to load all objects from the
database at once. Example:

    customer = Customer[123]

Enhanced error message for descendant classes

Enhanced error message when descendant classes declare attributes with the
same name. Now if you try to declare the following entities:

    class Person(db.Entity):
        name = Required(str)

    class Employee(Person):
        dob = Required(date)

    class Manager(Person):
        dob = Required(date)

    db.generate_mapping(create_tables=True) # raises exception

When Pony will try to generate mapping for the entities above, it will
raise the ERDiagramError exception with the following text:

    Attribute Manager.dob conflicts with attribute Employee.dob because
both entities inherit from Person. To fix this, move attribute definition
to base class

To fix this you need to declare the dob attribute in the entity Person:

    class Person(db.Entity):
        name = Required(str)
        dob = Required(date)

    class Employee(Person):

    class Manager(Person):

Other changes and bug fixes

Fixed #98: Composite index can include attributes of base entity
Fixed #106: incorrect loading of object which consists of primary key only
Fixed pony.converting.check_email()
Prefetching bug fixed: if collection is already fully loaded it shouldn’t
be loaded again
Deprecated Entity.order_by(..) method was removed. Use
Entity.select().order_by(…) instead
Various performance enhancements
Multiple bugs were fixed

As always, we appreciate your feedback which you can send us to our email
list or by email at team [at] ponyorm.com

Alexey Malashkevich
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </ponyorm-list/attachments/20150224/f9d21d45/attachment.html>

More information about the ponyorm-list mailing list