I recently had to implement pagination in a TG 2 project that I’m almost finished with. Although I had previously glanced at the paginate webhelper module, I first turned to the updated TurboGears documentation to see what was “officially” written up about this subject.
A lot of work has been going into the TG docs in preparation for the upcoming v2.1 launch, and one little gem that was recently added was the Pagination Quickstart (thanks Lukas). While this sent me down the right path towards pagination perfection, there were a few things that came up that I felt like deserved further explanation:
- The @paginate() decorator is an extremely simple wrapper for the paginate webhelper module.
- When paginating SQLAlchemy queries, paginate runs a duplicate count() query to figure out its current position in the data collection. While the magic of this is nice, the possible performance issues with duplicating complex SQL queries on a high-traffic website could be undesirable.
- It’s common to have controller methods dynamically switch to a “feed template” when doing AJAX pagination. Don’t worry, paginate + override_template makes this a piece of cake!
The @paginate() decorator makes pagination a breeze
The @paginate decorator is a wrapper for the paginate module that can be added to your controller methods. Simply specify your data collection’s name as the first argument of the decorator, and pagination is “automagically” setup for you.
An example controller method with pagination would look like this:
# dead-simple pagination in TurboGears 2 @expose('myproject.templates.posts') @paginate("posts") def posts(self): posts = DBSession.query(Posts) return dict(posts=posts)
Really? That was easy!
The documentation on this decorator seems quite clear to me, so instead of repeating its content here I will simply give you a link for further reading.
While writing scripts, I frequently run into the issue of needing to re-arrange sets of data into a more “process friendly” format. A common issue I encounter is needing to turn a list (array) into a dictionary (associative array) or vice versa. More often than not, I find myself needing to be able to access list elements by a key, but since they aren’t setup in a dictionary I have to pull out a looping technique to reorganize the data for this to be possible.
Take the following set of data for example:
[[1, 'John Smith', 'admin'], [2, 'Jane Doe', 'superuser'], [3, 'Sam Jones', 'user']]
What we have here is a few rows of user data. In this example, the data is in a Python list (which in PHP would be an array).
In PHP, this would look something like (using print_r):
Array (  => Array (  => 1  => John Smith  => admin )  => Array (  => 2  => Jane Doe # (...etc...)
So, what if I found myself writing some code that needed to be able to access each record by its first value, which in this case would be the user_id? (continue reading…)
[A lot of the information below is out of date. Please see the new framework shootout page for the latest benchmarks.]
As I briefly mentioned in Round 1, this whole thing came about as an experiment to satisfy my own curiosity. Unfortunately, I wasn’t expecting these posts to draw the amount of attention they have been getting, and several people informed me of a few “issues” with the first round. Since my initial approach to this topic was somewhat casual, I didn’t really take the time to perform each test in a “proper scientific fashion.” Although this was clearly stated in the introduction to round one, it unfortunately resulted in performance estimations that were somewhat less than accurate.
After input from various people much smarter than myself, I quickly went to work tweaking my test environment and building “proper” test apps. In the midst of this, a conversation about PHP accelerators prompted me to put PHP under the spotlight, which brought about Round 2 as an interim round. This gave me a chance to demonstrate the necessity of PHP acceleration, and only continued to solidify my opinion of PHP as an inferior web development language (remember, I just said my opinion).
Which brings us to Round 3. A lot of work has gone into “doing it right” this time, so I am fairly confident that these results are a much more accurate representation of each test subject’s performance estimations. Remember, benchmark test code typically has no real-world value, so “performance estimations” are about all I can promise here. Your mileage will vary. As a wise person once said:
“All this benchmarking is doing is proving what we already know: More code takes longer to execute.” – Ben Bangert (dev lead of Pylons)