Hey,
I originally submitted the window functions expressions to Django a couple of years ago for Django 2.0. In hindsight,
there are probably things that could be implemented a bit better although I'm not sure how I easily could have used the
SQLCompiler or QuerySet/Query classes directly, especially considering the fact that there are slight discrepencies in
how window expressions are supported between the different databases that Django officielly supports.
Anyway, it spawned a ticket #28333 [1] that I like to dedicate some time to implement since the feature appears to be wanted.
I have some thoughts about the process:
1. Include another flag: filtering_requires_subquery (should default to False, just filterable defaults to True)
2. Edit in QuerySet._filter_or_exclude to add somehow the following logic:
1. If the expression is not filterable, then we can introduce a subquery and filter directly there.
I surmise that this statement would be generic for SQL: if something is not filterable in a main query,
then it will be including it in another query as a subquery, and filtering that way?
2. Everything related to existing ordering etc. is a bit blurry.
3. Having to work with table aliases doesn't seem to be something that I'd want to worry about.
There's Query.rewrite_cols for the case when there's an annotation from a joined table,
Sum(F('author__awards')) is the example given in the comment in that function.
3. I think it's a general lacune that it's difficult to add a subquery to an existing query.
Although there's a boolean flag Query.subquery, it doesn't seem to make it easier to deal with filtering and other
things related to a subquery. I found this when searching for tickets that have "subquery" in the description:
https://code.djangoproject.com/ticket/20127 When are the table aliases used (T1, T2 etc.), and when are the actual table names used? I think it's when a table is auto-joined?
I'm not sure how much work that is required in SQLCompiler and Query, or if those two parts can stay untouched.
I tend to overthink things and sometimes make them more complex, so it's likely that there are things in the above that
Query.as_sql has this:
def as_sql(self, compiler, connection):
sql, params = self.get_compiler(connection=connection).as_sql()
if self.subquery:
sql = '(%s)' % sql
return sql, params
If someone is willing to discuss ideas about the process, please reach out to me. Devil lies in the details, and I suppose some
of the problem that subqueries are difficult in the ORM could be mended with work on this patch. However, I'd like to interact with
people who have worked more with the internals of the ORM than I did. One particular name Simon Charettes comes to mind,
since he also volunteered to mentor GSOC in the ORM area.
[1]
https://code.djangoproject.com/ticket/28333--
Med venlig hilsen / Kind regards,
Mads Jensen