Opened 3 years ago

Closed 3 years ago

#32616 closed Bug (duplicate)

QuerySet filter() does not preserve the argument order for a WHERE clause

Reported by: J. Choi Owned by: nobody
Component: Database layer (models, ORM) Version: 3.1
Severity: Normal Keywords: queryset, filter, sql
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Tested in Django 3.1.7.
QuerySet filter() method allows multiple keyword arguments. And multiple parameters are joined via AND in the underlying SQL statement.

Problem: It seems like the keyword argument order of the filter() method is not preserved for a WHERE clause.

Django Model:

class PvPowerRealDaily(models.Model):
    id = models.AutoField(primary_key=True)
    id_inv = models.IntegerField()
    dt_update = models.DateTimeField(auto_now=True)
    date_target = models.DateField()
    power00 = models.FloatField(null=True, default=None)
    ...

    class Meta:
        managed = False
        app_label = 'pv'
        db_table = 'tbl_power_pv_real_daily'
        constraints = [
            models.UniqueConstraint(fields=['id_inv', 'date_target'], name='pk_pvpowerrealdaily_id_inv_date_target'),
        ]
        indexes = [
            models.Index(fields=['id_inv', 'date_target']),
            models.Index(fields=['id_inv']),
            models.Index(fields=['date_target']),
        ]

PostgreSQL Table:

CREATE TABLE "tbl_power_pv_real_daily" (
        "id" SERIAL,
        "id_inv" INTEGER NOT NULL,
        "dt_update" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
        "date_target" DATE NOT NULL,
        "power00" DOUBLE PRECISION NULL,
        ...
        PRIMARY KEY("id")
);

CREATE UNIQUE INDEX "tbl_power_pv_real_daily_id_inv_date_target_idx" ON tbl_power_pv_real_daily ("id_inv", "date_target");
CREATE INDEX "tbl_power_pv_real_daily_id_inv_idx" ON tbl_power_pv_real_daily ("id_inv");
CREATE INDEX "tbl_power_pv_real_daily_date_target_idx" ON tbl_power_pv_real_daily ("date_target");

Result 1. Argument order is not preserved with a single filter.

PvPowerRealDaily.objects.filter(id_inv__exact=1, date_target__lte=date_now).order_by('-date_target')[:31]
SELECT * FROM "tbl_power_pv_real_daily" WHERE ("tbl_power_pv_real_daily"."date_target" <= '2021-04-07'::date AND "tbl_power_pv_real_daily"."id_inv" = 1) ORDER BY "tbl_power_pv_real_daily"."date_target" DESC LIMIT 31; args=(datetime.date(2021, 4, 7), 1)

Result 2. Argument order is preserved with multiple filters.

PvPowerRealDaily.objects.filter(id_inv__exact=1).filter(date_target__lte=date_now).order_by('-date_target')[:31]
SELECT * FROM "tbl_power_pv_real_daily" WHERE ("tbl_power_pv_real_daily"."id_inv" = 1 AND "tbl_power_pv_real_daily"."date_target" <= '2021-04-07'::date) ORDER BY "tbl_power_pv_real_daily"."date_target" DESC LIMIT 31; args=(1, datetime.date(2021, 4, 7))

ISO/IEC 9075-1 SQL standard states as follows:

Where the precedence is not determined by the Formats or by parentheses, effective evaluation of expressions is generally performed from left to right. However, it is implementation-dependent whether expressions are actually evaluated ...

I know the query optimizer of a DBMS can handle the evaluation order within the WHERE clause. However, keeping the argument order of the filter method for a WHERE clause would be a better choice.

Change History (1)

comment:1 by Mariusz Felisiak, 3 years ago

Resolution: duplicate
Status: newclosed

Duplicate of #31940.

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