I have a model Conversation
and a model Message
.
The model Message
has a foreign key to conversation, a text field, and a date field.
How can I list all conversations and for each conversation get the most recent message and the date of the most recent message?
I guess it's something like
Conversation.objects.annotate(last_message=Max('messages__date'))
but it will only give me the latest date. I want last_message
to contain both the text of the last message and the date it was created. Maybe I need to use prefetch_related?
Unlike aggregate() , annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet ; this QuerySet can be modified using any other QuerySet operation, including filter() , order_by() , or even additional calls to annotate() .
Django annotations 2 are a way of enriching the objects returned in QuerySets. That is, when you run queries against your models you can ask for new fields, whose values will be dynamically computed, to be added when evaluating the query. These fields will be accessible as if they were normal attributes of a model.
What is an annotation? Annotate generate an independent summary for each object in a queryset. In simpler terms, annotate allows us to add a pseudo field to our queryset. This field can then further be used for filter lookups or ordering.\
The Django ORM is a convenient way to extract data from the database, and the annotate() clause that you can use with QuerySets is also a useful way to dynamically generate additional data for each object when the data is being extracted.
Since Django 1.11, you could use Subqueries expressions:
latest_message = Subquery(Message.objects.filter(
conversation_id=OuterRef("id"),
).order_by("-date").values('value')[:1])
conversations = Conversation.objects.annotate(
latest_message=latest_message,
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With