Opened 2 years ago
Closed 2 years ago
#33999 closed New feature (wontfix)
Efficient filter with join on soft link.
Reported by: | brandic | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.2 |
Severity: | Normal | Keywords: | QuerySet.extra |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
We recently had cause to use "extra" in our codebase. We needed to filter on a table which was linked to another table via an integer (a soft link, for business needs) on an intermediary table. (i.e. Model A has a ForeignKey to Model B which is linked to Model C via an IntegerField; we needed to filter on Model A by a field on Model C.)
Using the solution with "annotate" produced a query with two subqueries (three total queries); using extra we achieved an equivalent query using joins (one total query.)
SQL from query with "annotate":
SELECT [all fields from model_a], (SELECT model_c.target_field FROM model_c JOIN model_b ON model_c.id = model_b.c_id WHERE model_b.a_id = model_a.id) AS "target_field" FROM "model_a" WHERE (SELECT model_c.target_field FROM model_b JOIN model_c ON model_c.id = model_b.c_id WHERE model_b.a_id = model_a.id)::text = 'some string')
SQL from query with "extra":
SELECT [all fields from model_a] FROM "model_a" , "model_b" , "model_c" WHERE (model_c.id = model_b.c_id AND model_b.a_id = model_a.id AND model_c.target_field = 'some string'))
Change History (1)
comment:1 by , 2 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Resolution: | → wontfix |
Status: | new → closed |
Summary: | Efficient filter with join on soft link → Efficient filter with join on soft link. |
Type: | Cleanup/optimization → New feature |
As far as I'm aware, using
extra()
is the right thing to do in your case. You could also try to changeModelB.c
to aForeignKey
without a database constraint, e.g.but it's a bad idea in most of cases (see docs).
Even if it's feasible I don't think there would be consensus to add that complexity to Django itself. You can raise the idea on the DevelopersMailingList to reach a wider audience and see what other think (see also the guidelines with regards to requesting features).