Navigation

Orator 0.6 is now out. This version introduces model events, query pagination and performance improvements and fixes.

The stable version is actually the 0.6.1 version.

The 0.6 version introduced bugs in how relationships were handled, breaking the functionality. Everything should now be fixed in 0.6.1.

Model events

Orator models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored.

Whenever a new item is saved for the first time, the creating and created events will fire. If an item is not new and the save method is called, the updating / updated events will fire. In both cases, the saving / saved events will fire.

Cancelling save operations via events

If False is returned from the creating, updating, saving, or deleting events, the action will be cancelled:

User.creating(lambda user: user.is_valid())

Model observers

To consolidate the handling of model events, you can register a model observer. An observer class can have methods that correspond to the various model events. For example, creating, updating, saving methods can be on an observer, in addition to any other model event name.

So, for example, a model observer might look like this:

class UserObserver(object):

    def saving(user):
        # ...

    def saved(user):
        # ...

You can register an observer instance using the observe method:

User.observe(UserObserver())

There is a lot more you can do with Orator, just give a look at the documentation to see all available features.

Pagination

Paginate database records

There are several ways to paginate items. The simplest is by using the paginate method on the Query Builder or an ORM query. The paginate method provided by Orator automatically takes care of setting the proper limit and offset based on the current page. By default, the current page needs to be specified. However, as we'll see it later, you can create a custom current page resolver.

Paginating Query Builder results

First, let's take a look at calling the paginate method on a query generated by the query builder:

users = db.table('users').paginate(15, 2)

In this example, the first argument passed to paginate is the number of items we would like displayed "per page" and the second is the current page we want to display. So, in this case, we want to retrieve 15 items on page 2.

Currently, pagination operations that use a group_by statement cannot be executed efficiently by Orator. If you need to use a group_by with a paginated result set, it is recommended that you query the database and create a paginator manually.

Paginating models

You can also paginate ORM queries. In this example, we will paginate the User model with 15 items per page for the second page. As you can see, the syntax is nearly identical to paginating query builder results:

all_users = User.paginate(15, 2)

Of course, you can call paginate after setting other constraints on the query:

some_users = User.where('votes', '>', 100).paginate(15, 2)
Simple pagination

If you only need "Next" and "Previous" pages in your pagination, you have the option of using the simple_paginate method to perform a more efficient query.

some_users = User.where('votes', '>', 100).simple_paginate(15, 2)

Creating a Paginator manually

Sometimes you may wish to create a pagination instance manually, passing it a list of items. You can do so by creating either a Paginator or a LengthAwarePaginator instance, depending on your needs.

The Paginator class does not need to know the total number of items in the result set; however, because of this, the class does not have methods to retrieve the index of the last page. The LengthAwarePaginator accepts almost the same arguments as the Paginator, except that it does require a count of the total number of items in the result set.

In other words, the Paginator corresponds to the simple_paginate method on the query builder and the ORM, while the LengthAwarePaginator corresponds to the paginate method.

Displaying Results

When you call the paginate or simple_paginate methods on a query builder or ORM query, you will receive a paginator instance. When calling the paginate method, you will receive an instance of LengthAwarePaginator. When calling the simple_paginate method, you will receive an instance of Paginator. These objects provide several methods and attributes that describe the result set. In addition to these helpers methods, the paginator instances are iterators and may be looped as a list.

for user in some_users:
    print(user.name)

Additional attributes and helper methods

You may also access additional pagination information via the following methods and attributes on paginator instances:

| Method or attribute | Description | |------------------------------| -------------------------------------------------------------------------| | results.count() | Returns the number of results on the current page | | results.current_page | The current page of the paginator | | results.has_more_pages() | Returns True if there is more pages else False | | results.last_page | The number of the last page (Not available when using simple_paginate) | | results.next_page | The number of the next page if it exists else None | | results.per_page | The number of results per page | | results.previous_page | The number of the previous page if it exists else None | | results.total | The total number of results (Not available when using simple_paginate |

Converting Results To JSON

The Orator paginator result classes expose the to_json method, so it's very easy to convert your pagination results to JSON.

By default, it will return the JSON formatted underlying Collection:

some_users = User.where('votes', '>', 100).paginate(15, 2)

print(some_users.to_json())

For the full list of changes, see the CHANGELOG

What's next?

Finally, here are some features targeted for future versions (actual roadmap to be determined):

  • Database seeding

  • Extra functionalities, like caching.

Sébastien Eustace

Sébastien Eustace

sebastien.eustace.io

Born & raised in France, and currently living in the beautiful city of Quito, Ecuador, I'm a software engineer, proud pythonista (but knowledgeable in other languages and technologies as well) but overall an open source lover.

View Comments