Alex K
Alex K

Reputation: 35

How do I select from a subquery using the Django ORM?

I have a table that is meant to be insert only. It has columns for id, object_id, and user_id. When you update a record, instead of updating the row, you create a new record with a matching object_id.

I'm trying to pull all records that match a given user_id with the highest id for each individual object_id.

I can do what I'm attempting to describe with a subquery like so:

SELECT * FROM (SELECT * FROM table WHERE user_id = 100 ORDER BY object_id, id DESC) adr_table GROUP BY object_id

I've tried using the raw() method, but it returns a RawQuerySet object and I'm trying to feed it to a form that needs a QuerySet.

I'd ideally like to get rid of the raw() and just use the Django ORM, but if that isn't possible, how can I convert the RawQuerySet to a regular QuerySet?

Upvotes: 3

Views: 1922

Answers (2)

Nikita
Nikita

Reputation: 6341

If I got you right the table structure is:

----------------------------
|           Table          |
----------------------------
| id | user_id | object_id |
----------------------------
| 1  |   100   |    10     |
----------------------------
| 2  |   100   |    20     |
----------------------------
| 3  |   200   |    80     |
----------------------------
| 4  |   100   |    80     |
----------------------------
| 5  |   100   |    10     |
----------------------------

And the result of your query should be:

----------------------------
|           Table          |
----------------------------
| id | user_id | object_id |
----------------------------
| 4  |   100   |    80     |
----------------------------
| 2  |   100   |    20     |
----------------------------
| 5  |   100   |    10     |
----------------------------

Then try distinct(), like so:

Model.objects.filter(user_id=100).order_by('-object_id', '-id').distinct('object_id')

this should return QuerySet with your records with user_id equal 100, then ordered by object_id first and id second in descending order, and due to distinct on object_id only the first record for each same object_id will be take, which with the ordering specified will be the one with the highest id.

Upvotes: 1

Shang Wang
Shang Wang

Reputation: 25559

Please try this:

from django.db.models import Max

Model.objects.filter(user_id=100).values('object_id').annotate(Max('id'))

Upvotes: 1

Related Questions