Sorting records

To return rows in order, use the order_by() method:

  1. >>> for t in Tweet.select().order_by(Tweet.created_date):
  2. ... print(t.pub_date)
  3. ...
  4. 2010-01-01 00:00:00
  5. 2011-06-07 14:08:48
  6. 2011-06-07 14:12:57
  7. >>> for t in Tweet.select().order_by(Tweet.created_date.desc()):
  8. ... print(t.pub_date)
  9. ...
  10. 2011-06-07 14:12:57
  11. 2011-06-07 14:08:48
  12. 2010-01-01 00:00:00

You can also use + and - prefix operators to indicate ordering:

  1. # The following queries are equivalent:
  2. Tweet.select().order_by(Tweet.created_date.desc())
  3. Tweet.select().order_by(-Tweet.created_date) # Note the "-" prefix.
  4. # Similarly you can use "+" to indicate ascending order, though ascending
  5. # is the default when no ordering is otherwise specified.
  6. User.select().order_by(+User.username)

You can also order across joins. Assuming you want to order tweets by the username of the author, then by created_date:

  1. query = (Tweet
  2. .select()
  3. .join(User)
  4. .order_by(User.username, Tweet.created_date.desc()))
  1. SELECT t1."id", t1."user_id", t1."message", t1."is_published", t1."created_date"
  2. FROM "tweet" AS t1
  3. INNER JOIN "user" AS t2
  4. ON t1."user_id" = t2."id"
  5. ORDER BY t2."username", t1."created_date" DESC

When sorting on a calculated value, you can either include the necessary SQL expressions, or reference the alias assigned to the value. Here are two examples illustrating these methods:

  1. # Let's start with our base query. We want to get all usernames and the number of
  2. # tweets they've made. We wish to sort this list from users with most tweets to
  3. # users with fewest tweets.
  4. query = (User
  5. .select(User.username, fn.COUNT(Tweet.id).alias('num_tweets'))
  6. .join(Tweet, JOIN.LEFT_OUTER)
  7. .group_by(User.username))

You can order using the same COUNT expression used in the select clause. In the example below we are ordering by the COUNT() of tweet ids descending:

  1. query = (User
  2. .select(User.username, fn.COUNT(Tweet.id).alias('num_tweets'))
  3. .join(Tweet, JOIN.LEFT_OUTER)
  4. .group_by(User.username)
  5. .order_by(fn.COUNT(Tweet.id).desc()))

Alternatively, you can reference the alias assigned to the calculated value in the select clause. This method has the benefit of being a bit easier to read. Note that we are not referring to the named alias directly, but are wrapping it using the SQL helper:

  1. query = (User
  2. .select(User.username, fn.COUNT(Tweet.id).alias('num_tweets'))
  3. .join(Tweet, JOIN.LEFT_OUTER)
  4. .group_by(User.username)
  5. .order_by(SQL('num_tweets').desc()))

Or, to do things the “peewee” way:

  1. ntweets = fn.COUNT(Tweet.id)
  2. query = (User
  3. .select(User.username, ntweets.alias('num_tweets'))
  4. .join(Tweet, JOIN.LEFT_OUTER)
  5. .group_by(User.username)
  6. .order_by(ntweets.desc())