New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QuerySet from subquery #16814
QuerySet from subquery #16814
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello! Thank you for your contribution 💪
As it's your first contribution be sure to check out the patch review checklist.
If you're fixing a ticket from Trac make sure to set the "Has patch" flag and include a link to this PR in the ticket!
If you have any design or process questions then you can ask in the Django forum.
Welcome aboard ⛵️!
Hi @AivanF & welcome! All PRs require a ticket and all feature request tickets require some discussion in the Django Forum first. Is there a ticket that this PR is fixing? |
@shangxiao Nope, there is no ticket yet. Google Groups: Django Developers – is it the forum? |
This is already an accepted ticket for this feature so there's no need for a wider discussion, see ticket-24462 and #11715, #12602 for proposed implementations. This approach won't fly though as this is an abuse of What we need here is a set of primitives that resemble what currently lives |
@AivanF Yup there is that but the new & preferred method is the forum: Info here: |
Closing due to inactivity and lack of follow up. |
1. Problem
Django 4.2 enabled us to filter by calculated values and this is awesome! But for now it's impossible to perform a filter exactly after a filter by annotated value. The following Django ORM code:
Leads to this SQL query:
However, in some cases the order of filtering statements leads to different result data and hence is highly important.
2. Existing Solutions
To overcome this problem, it's possible to use subquery in WHERE clause:
Which has bad performance due to hash join.
Or RawSQL could be used:
But this breaks ORM philosophy and prevents it's features.
There are external libraries solving the problem, but they are limited and unmaintained, e.g PyPI: django-sub-query. Meanwhile, the described logic is pretty simple and could be better implemented inside Django ORM itself.
Honestly, I tried to do it as a separate library, but this was too monstrous. I also aimed to create subqueries without much new code, using existing features that generate
FROM (...)
, but it also was overcomplicated.3. My Solution with From-Subquery Feature
Now
QuerySet
providesas_subquery
method:Which leads to a SQL query like:
To achieve this, I:
as_subquery
method toQuerySet
class which created a separatedjango.db.models.sql.Query
object referencing old one as a subquery.inner_query
property todjango.db.models.sql.Query
classSQLCompiler.get_qualify_sql
. I'm not into this masking stuff, but, as far as I understood, this could be better done with unmasking and masking again... But I don't understand why to add aliases at all?SQLCompiler.get_from_clause
returns subquery when it is presented.