Python 3.5 support
Pony now supports Python 3.5
Better raw SQL support
Before this release Pony provided an ability to write raw SQL queries using the Entity.select_by_sql() method. But in this case you had to write the whole SQL query by itself.
Starting with this release Pony allows embedding raw SQL fragments into a lambda or generator query using the
Here is an example of using
s = 'J%' select(p for p in Person if p.age > 20 and raw_sql('"p"."name" LIKE $s'))
'"p"."name" LIKE <param>' will be embedded into generated SQL query. The value of the parameter will be taken from the
p is an alias of SQL table used in this query, not Python generator variable. Pony uses the variable from the generator as an alias for SQL table.
You also can embed more complex Python expressions into raw SQL fragment:
import datetime Task.select(lambda t: raw_sql("t.due_date < date($datetime.date.today(), '+1 day')"))
datetime.date.today() is a Python expression which will be evaluated and replaced with a single parameter.
You can find more examples of using
raw_sql() function in Pony docs.
Using @db_session with generator functions
@db_session decorator was used for decorating functions that work with the database. But it didn't work correctly when was applied to generators (functions that return value using the
yield expression). Starting with this release you can use the
@db_session decorator for generators too.
With regular functions, the
@db_session decorator works as a scope. When your program leaves the db_session scope, Pony finishes the transaction by performing commit (or rollback) and clears the db_session cache.
In case of a generator, the program can reenter the generator code for several times. In this case, when your program leaves the generator code, the db_session is not over, but suspended and Pony doesn't clear the cache. In the same time, we don't know if the program will come back to this generator code again. That is why you have to explicitly commit or rollback current transaction before the program leaves the generator on
yield. On regular functions Pony calls
rollback() automatically on leaving the
In essence, here is the difference with using
@db_session with generator functions:
1. You have to call
rollback() before the
yield expression explicitly.
2. Pony doesn't clear the transaction cache, so you can continue using loaded objects when coming back to the same generator.
3. With a generator function, the
@db_session can be used only as a decorator, not a context manager. This is because in Python the context manager cannot understand that it was left on
@db_session parameters, such as
serializable cannot be used with generator functions. The only parameter that can be used in this case is
This fixes the issue #126.
Getting SQL statement as a string
Now you can use Query.get_sql() method in order to get SQL statement that will be sent to the database:
sql = select(c for c in Category if c.name.startswith('a')).get_sql() print sql SELECT "c"."id", "c"."name" FROM "category" "c" WHERE "c"."name" LIKE 'a%%'
Before Pony release 0.6.2 you could delete objects only by calling the
delete() method on an entity instance. Now you can use the
delete(p for p in Product if p.picture is None)
Another option is calling the
delete() method on a query:
select(p for p in Product if p.picture is None).delete()
The Query.delete() method has the
bulk parameter, which is
False by default. When
bulk=False Pony loads each instance into memory and calls the
delete() method on each instance (calling
after_delete hooks if they were defined). If
bulk=True Pony doesn't load instances, it just generates the SQL DELETE statement which deletes objects in the database.
Ability to override entity constructor and add methods to an entity
Now you can override the
__init__() method of an entity, and also monkeypatch your own methods in an entity.
Normalizing table names for symmetric relationships
Pony can automatically generate database table names when it creates tables for entities and many-to-many relationships. Depending on the database, it normalizes the table name using either upper or lower case letters. In previous releases this normalization was not applied to symmetric relationships (where both ends of a relationships are specified using the same attribute). Here is an example of a symmetric relationship:
class Person(db.Entity): friends = Set("Person", reverse="friends")
Now, when this bug is fixed, Pony applies the same normalization rules to all table names. So, you might need to change the database table name or use the table option of a symmetric attribute for specifying your current table name:
class Person(db.Entity): friends = Set("Person", reverse="friends", table="current_table_name")
Now Pony automatically removes leading and trailing whitespace characters in a string attribute. You can control it by using the
autostrip option. By default
autostrip=True. The behavior is similar to Python
string.strip() function. If you want to keep leading and trailing characters, you have to set
autostrip parameter to
class Person(db.Entity): name = Required(str, autostrip=False)
We have moved Pony ORM documentation to a separate repo at https://github.com/ponyorm/pony-doc. Also we have changed the license of documentation to Apache 2.0. This way it will be easier to receive pull request for docs and it makes collaboration easier. Please create new documentation related issues here.
The compiled version of docs still can be found at https://docs.ponyorm.com
Other changes and bug fixes
- Fixed #87: Pony fails with pymysql installed as MySQLdb
- Fixed #116: Add support to select by UUID
- Fixed #118: Pony should reconnect if previous connection was created before process was forked
- Fixed #121: Unable to update value of unique attribute
- Fixed #122: AssertionError when changing part of a composite key
- Fixed #127: a workaround for incorrect pysqlite locking behavior
- Fixed #136: Cascade delete does not work correctly for one-to-one relationships
- Fixed #141, #143: remove restriction on adding new methods to entities
- Fixed #142: Entity.select_random() AssertionError
- Fixed #147: Add 'atom_expr' symbol handling for Python 3.5 grammar