Opened 2 hours ago

Last modified 95 minutes ago

#36607 new Uncategorized

Improve the documentation by mentioning that "filter(a,b)" may not be the same as "filter(a).filter(b)" on querysets.

Reported by: Aaron Owned by:
Component: Database layer (models, ORM) Version: 5.2
Severity: Normal Keywords:
Cc: Aaron, Egor R Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Dear community,

I just got informed about the fact that "filter(a,b)" might not be the same as
"filter(a).filter(b)". The following example may be useful for illustrating
this. It uses some code that is inspired by our code and won't run without
context, but I hope it is illustrating enough.

The intend is to filter for MaintenanceOperations. Therefore, we create one:

op = MaintenanceOperationFactory()

These objects are children of the MaintenanceOperation:

maint_a = UnscheduledMaintenanceFactory(operation=op, execution_start="2030-03-10T12:00:00Z")
maint_b = UnscheduledMaintenanceFactory(operation=op, execution_start="2030-05-10T12:00:00Z")

We construct a first queryset like this:

qs1 = MaintenanceOperation.objects.filter(maintenances__execution_start__gt="2030-04-10T12:00:00Z", maintenances__execution_start__lt="2030-04-20T12:00:00Z",)

This qs evaluates to: <MaintenanceOperationQuerySet []> (aka the empty list). This happens because
neither UnscheduledMaintenance meets both criteria. The underlying sql is this:

SELECT "maintenance_maintenanceoperation"."id" FROM
"maintenance_maintenanceoperation" INNER JOIN "maintenance_maintenance" ON
("maintenance_maintenanceoperation"."id" =
"maintenance_maintenance"."operation_id") WHERE
("maintenance_maintenanceoperation"."deleted_at" IS NULL AND
"maintenance_maintenance"."execution_start" > 2030-04-10 12:00:00+00:00 AND
"maintenance_maintenance"."execution_start" < 2030-04-20 12:00:00+00:00)

To demonstrate the second case, we build the following queryset:

qs2 = MaintenanceOperation.objects.filter(
maintenances__execution_start__gt="2030-04-10T12:00:00Z",).filter(
maintenances__execution_start__lt="2030-04-20T12:00:00Z",)

This qs evaluates to:<MaintenanceOperationQuerySet [<MaintenanceOperation: #1:
beauftragt>]>(This list contains the MaintenanceOperation we created at the start)
This is different from the first one, because the sql is done with another join:

SELECT "maintenance_maintenanceoperation"."id"
FROM "maintenance_maintenanceoperation" INNER JOIN "maintenance_maintenance" ON
("maintenance_maintenanceoperation"."id" =
"maintenance_maintenance"."operation_id") INNER JOIN "maintenance_maintenance"
T3 ON ("maintenance_maintenanceoperation"."id" = T3."operation_id") WHERE
("maintenance_maintenanceoperation"."deleted_at" IS NULL AND
"maintenance_maintenance"."execution_start" > 2030-04-10 12:00:00+00:00 AND
T3."execution_start" < 2030-04-20 12:00:00+00:00)

I think this should be mentioned in the filter documentation, particularly in the
section on joining filters. If this is met with approval I am open to sketching a
suggestion.

Change History (1)

comment:1 by Egor R, 95 minutes ago

Cc: Egor R added
Note: See TracTickets for help on using tickets.
Back to Top