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 Mariusz Felisiak, 2 years ago

Component: UncategorizedDatabase layer (models, ORM)
Resolution: wontfix
Status: newclosed
Summary: Efficient filter with join on soft linkEfficient filter with join on soft link.
Type: Cleanup/optimizationNew feature

As far as I'm aware, using extra() is the right thing to do in your case. You could also try to change ModelB.c to a ForeignKey without a database constraint, e.g.

c = models.ForeignKey(ModelC, ..., db_constraint=False)

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).

Note: See TracTickets for help on using tickets.
Back to Top