Django: how to order_by on a related field of a related field

2024/10/9 4:20:41

I'm using annotate to add a property to an object which I can then use for order_by. However, I want to annotate on a field of a relation on a relation. I know I should be able to get to the field somehow using double-underscore notation, but I just can't seem to wrap my head around it.

Here are the models:

class Group(Taggable, Uploadable):name            = models.CharField(max_length=250, db_index=True)description     = models.TextField(max_length=5000, null=True,blank=True, db_index=True)private         = models.BooleanField(default=False)members         = models.ManyToManyField(User, null=True,related_name='members', through='GroupToUser')pending_members = models.ManyToManyField(User, null=True,related_name='pending_members')admin           = models.ForeignKey(User, null=True)timestamp       = models.DateTimeField(auto_now_add=True)author          = models.ForeignKey(User, related_name='author')class Discussion(Taggable, Uploadable):author      = models.ForeignKey(User)title       = models.CharField(max_length=250, db_index=True)description = models.TextField(max_length=5000, null=True,blank=True, db_index=True)group       = models.ForeignKey(Group, null=True)timestamp   = models.DateTimeField(auto_now_add=True)class DiscussionResponse(Uploadable):author     = models.ForeignKey(User)discussion = models.ForeignKey(Discussion)message    = models.TextField(max_length=5000)timestamp  = models.DateTimeField(auto_now_add=True)

So, a Discussion can optionally be associated with a Group, and DiscussionResponses are associated with a discussion. What I would like to do is find the most recent DiscussionResponse on any discussions connected to a Group, if it exists, and sort by that.

I've gotten as far as this:

Group.objects.filter(some_filtering).distinct().annotate(last_response=Max('some__reverse__relationship__timestamp').order_by('-last_response')

I just can't seem to figure out the right way to get to the timestamp on a DiscussionResponse in this case.

UPDATE: You can indeed order by an annotated value. Here is an example with an order_by on the timestamp of a related discussion:

>>> groups = Group.objects.all().annotate(last_response=Max('discussion__timestamp')).order_by('-last_response')
>>> for group in groups:
...     print(group.id, group.last_response)
...     
... 
(2L, datetime.datetime(2013, 5, 8, 15, 32, 31))
(1L, None)
(3L, None)
(4L, None)
(6L, None)
(7L, None)
(8L, None)
(9L, None)

In this case, only group #2 has related discussions so it was moved to the top; the rest retain the natural order. What I'd really like to do, though, is move groups that have recent responses to discussions moved to the top of the list. That's why I thought 'discussion__discussionresponse__timestamp' would work, but it doesn't seem to.

Answer

Ok, apparently it is just 'discussion__discussionresponse__timestamp'. I tried it in the Django shell and it didn't work after saving a new DiscussionResponse, but it worked several minutes later when I tried it again:

>>> groups = Group.objects.all().annotate(last_response=Max('discussion__discussionresponse__timestamp')).order_by('-last_response')
>>> for group in groups:
...     print(group.id, group.last_response)
...     
... 
(2L, datetime.datetime(2013, 5, 16, 14, 56, 22))
(1L, None)
(3L, None)
(4L, None)
(6L, None)
(7L, None)
(8L, None)
(9L, None)
>>> 

If anyone knows why it didn't work right after saving a new object to the database, but did work later, that would probably be useful information.

Here's another run at the query with discussions/responses added to another group just for added verification:

>>> groups = Group.objects.all().annotate(last_response=Max('discussion__discussionresponse__timestamp')).order_by('-last_response')
>>> for group in groups:
...     print(group.id, group.last_response)
...     
... 
(4L, datetime.datetime(2013, 5, 16, 15, 25, 40))
(2L, datetime.datetime(2013, 5, 16, 15, 16, 46))
(1L, None)
(3L, None)
(6L, None)
(7L, None)
(8L, None)
(9L, None)
>>> 
https://en.xdnf.cn/q/70060.html

Related Q&A

How to extract the cell state and hidden state from an RNN model in tensorflow?

I am new to TensorFlow and have difficulties understanding the RNN module. I am trying to extract hidden/cell states from an LSTM. For my code, I am using the implementation from https://github.com/ay…

Python - Nested List to Tab Delimited File?

I have a nested list comprising ~30,000 sub-lists, each with three entries, e.g.,nested_list = [[x, y, z], [a, b, c]].I wish to create a function in order to output this data construct into a tab delim…

How to make sure buildout doesnt use the already installed packages?

I am trying to switch fully to buildout - but our development environment already has lot of stuff installed in /usr/lib/pythonxx/How can I make sure that buildout doesnt use the libraries installed on…

Can python setup.py install use wheels?

I am using setuptools. Is there a way to have the following command use wheels instead of source?python setup.py installIn particular, I have a custom package that requires pandas. While pandas insta…

Getting the last element of a level in a multiindex

I have a dataframe in this format:a b x 1 1 31 1 2 1 1 3 42 1 4 423 1 5 42 1 6 3 1 7 44 1 8 65437 1 9 73 2 1 5656 2 2 7 2 3 5 2 4 5 2 5 34a a…

Sphinx and JavaScript Documentation Workflow [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 5…

Getting two characters from string in python [duplicate]

This question already has answers here:Split string every nth character(19 answers)How to iterate over a list in chunks(40 answers)Closed last year.how to get in python from string not one character, b…

I Call API from PYTHON I get the response 406 Not Acceptable

I created a API in my site and Im trying to call an API from python but I always get 406 as a response, however, if I put the url in the browser with the parameters, I can see the correct answerI alrea…

TypeError: unsupported operand type(s) for +=: builtin_function_or_method and int

I am receiving this error (TypeError: unsupported operand type(s) for +=: builtin_function_or_method and int) when trying to run this codetotal_exams = 0 for total_exams in range(1, 100001):sum += tota…

Project Scipy Voronoi diagram from 3d to 2d

I am trying to find a way to calculate a 2d Power Diagram in Python. For this I want to make use of the fact that a 2d power diagram can be interpreted as the intersection of a regular 3d voronoi diagr…