Joining on arbitrary fields

If a foreign key does not exist between two tables you can still perform a join, but you must manually specify the join predicate.

In the following example, there is no explicit foreign-key between User and ActivityLog, but there is an implied relationship between the ActivityLog.object_id field and User.id. Rather than joining on a specific Field, we will join using an Expression.

  1. user_log = (User
  2. .select(User, ActivityLog)
  3. .join(ActivityLog, on=(User.id == ActivityLog.object_id), attr='log')
  4. .where(
  5. (ActivityLog.activity_type == 'user_activity') &
  6. (User.username == 'charlie')))
  7. for user in user_log:
  8. print(user.username, user.log.description)
  9. #### Print something like ####
  10. charlie logged in
  11. charlie posted a tweet
  12. charlie retweeted
  13. charlie posted a tweet
  14. charlie logged out

Note

Recall that we can control the attribute Peewee will assign the joined instance to by specifying the attr parameter in the join() method. In the previous example, we used the following join:

  1. join(ActivityLog, on=(User.id == ActivityLog.object_id), attr='log')

Then when iterating over the query, we were able to directly access the joined ActivityLog without incurring an additional query:

  1. for user in user_log:
  2. print(user.username, user.log.description)