The ORM doesn't offer a way to do the query you want. The query will
be something like this:
select * from post
left join comment on comment.object_id =
post.id and
comment.object_type = 'post'
and comment.timestamp = (select max(timestamp) from
comment
where object_id =
post.id and
comment.object_type = 'post'
)
order by comment.timestamp;
(Assuming unique comment timestamp per post).
There are two underlying problems. First, Django's ORM doesn't
currently offer any way to generate more than single column equality
comparison in the JOIN clause. We are working on removing this
limitation from 1.6 (actually, the underlying limitation is already
somewhat gone). Second, the SQL needed isn't exactly nice. There are
multiple ways to write the same SQL, and how they perform differ
somewhat depending on the used DB and the amount of data.
So, what can you do pre 1.6? One way is to use views and some hackery
to do what you want.
class LatestComment(models.Model):
post = models.OneToOneField(Post, primary_key=True,
on_delete=models.DO_NOTHING, related_name='latest_comment')
{{ duplicate the columns in comment model here - you don't need
content type id }}
class Meta:
managed = False
db_table = 'latest_post_comment_view'
Then, create a view like this in the DB:
create or replace view "latest_post_comment_view" as (
select object_id as post_id, ...
from comment
where object_type = 'post'
group by post_id, ...
having max(timestamp) = timestamp
);
The SQL above is untested. In any case, you should now be able to do:
Post.objects.select_related('latest_comment').order_by('latest_comment__timestamp')
You will need to repeat the above for all the models with comments
Managing the raw SQL needed for the views can be somewhat ugly. The
last_comment_time field might be easier to implement & maintain. That
being said I have been using the above technique successfully in
production systems.
I do wish Django will one day have latest_related() functionality. I
find I need that often, and as the above shows this isn't easily
doable currently.
- Anssi