2

I have following Schema in Django with PostgreSQL.

Class Person (models.Model):
    name = models.CharField(max_length=255)
    email= models.CharField(max_legth = 255)
    created_at = models.DateTimeField()

Class PersonTask(models.Model):
   person = models.ForeignKey(Person)
   title = models.TextField()
   created_at = models.DateTimeField()

Class PersonHistory(models.Model):
   person = models.ForeignKey(Person)
   note = models.TextField()
   created_at = models.DateTimeField()

Now I need to query the DB like all values of Person with latest PersonTask__title as max_task and latest PersonHistory__note as max_note

Eg:

<Queryset: [
{name: "abc" ,email:"[email protected]",created_at :"2019-01-02", max_task:"This is my latest tasktitle" , max_note: "This is my latest history note"},
{name: "abcd" ,email:"[email protected]",created_at :"2019-03-02", max_task:"This is my latest tasktitle for abcd" , max_note: "This is my latest history note for abcd"}
]>

But, I could max get is either id of Latest Task and Latest History by

Person.objects.filter(customer_id= 1).\
               annotate( max_task = Max('persontask')).\
               annotate(max_note = Max('personhistory')).\
               order_by('-id')

Or a random task or note texts using below query

Person.objects.filter(customer_id= 1).\
               annotate( max_task = Max('persontask__title')).\
               annotate(max_note = Max('personhistory__note')).\
               order_by('-id')

How this can be tackled??

2 Answers 2

1

As you did not mention the ForeignKeys between these models, I suspect that Task and History have FK to Person in field named person.

I would use Subquery with combination of OuterRef to tackle this query

from django.db.models import OuterRef, Subquery

result = (
    Person.objects
        .filter(customer_id=1)
        .annotate(
            task_title=Subquery(Task.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('title')[:1]),
            history_note=Subquery(HistoryNote.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('note')[:1])
        )
        .order_by('-id')
)
Sign up to request clarification or add additional context in comments.

6 Comments

Yeah you are right about the DB models. I have updated the Models. But May I know, which version of Django will support this one?
I've looked to the django docs and it looks it's supported even in 1.11 :-) docs.djangoproject.com/en/1.11/ref/models/expressions/…
Thank you so much. Yeah I have tried them and are working fine
I did :-) . One more doubt is there any option to get date along with the title or task??
Sure, you can take more values from the subquery like Subquery(Task.objects.filter(person=OuterRef('pk')).order_by('-created_at').values('title', 'created_at')[:1])
|
0

If tasks and history are related with person you need a relationship between your models. something like this.

class PersonTask(models.Model):
    person = models.ForeignKey(Person, related_name="tasks", on_delete=models.CASCADE)
    title = models.TextField()
    created_at = models.DateTimeField()

class PersonHistory(models.Model):
    person = models.ForeignKey(Person, related_name="histories", on_delete=models.CASCADE)
    note = models.TextField()
    created_at = models.DateTimeField()

And then you could get last task and last history:

person = Person.objects.get(name="name")

person.tasks.last()
person.histories.last()

1 Comment

Models Have been updated. But I need the latest task and history as an annotated qiueryset for all the lead objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.