Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the django way of doing a subselect?

Tags:

I have a versioned model which (simplified) looks a bit like:

Project(id, ref, version)

unique_together(ref, version)

Where id is the autogenerated primary key, ref is a random UUID and version is an integer incremented by my application. Each time I save the project I create a new instance, add 1 to the version and copy the ref to the new object.

The following SQL will give me back the latest version of every Project, by doing a subselect.

SELECT * FROM myapp_project WHERE (ref, version) IN
(SELECT ref, max(version) FROM myapp_project GROUP BY ref)

Alternatively (slightly simpler perhaps):

SELECT * from myapp_project p
WHERE p.version =
(SELECT max(version) FROM myapp_project p1 WHERE p1.ref = p.ref)

How do I achieve the same query using Django's ORM?

Edit: I've got as far as this -

foo = Project.objects.values('ref').annotate(version=Max('version'))

This gives me something that looks right if I inspect it. As soon as I try to get the id out with:

foo.values('id')

It seems to discard the original result and gives back all the rows.

Edit more:

Worked around it for now with .extra():

maxids = """id in (SELECT id from myapp_project p WHERE p.version = 
(SELECT max(version) FROM myapp_project p1 WHERE p1.ref = p.ref))"""

Project.objects.all().extra(where=[maxids])
like image 883
Darren Avatar asked May 18 '16 14:05

Darren


People also ask

Is Django ORM support subquery?

¶ Django allows using SQL subqueries.

What is Django F expression?

In the Django QuerySet API, F() expressions are used to refer to model field values directly in the database. Let's say you have a Product class with a price field, and you want to increase the price of all products in 20%. A possible solution would be: products = Product. all() for product in products: product.

What is OuterRef?

`OuterRef` is an "outer reference", a construct created to allow a reference to the query surrounding the current subquery.

What is a QuerySet in Django?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.


1 Answers

Using in

here is an example straight from the linked document

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

The exact query that you are using isn't one that is supported by all databases that work with Django. For example while it works on postgresql it does not work on sqlite so you would have to change your approach to use the primary key instead of the unique_together key. Or use a join.

Update the second query can be handled more easily but I will refrain from posting that here since that would seem like plagarizing @anand's answer.

like image 154
e4c5 Avatar answered Sep 28 '22 03:09

e4c5