Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30854 closed Bug (fixed)

Selecting multiple FilteredRelation's returns only the last one.

Reported by: Morteza PRK Owned by: Hasan Ramezani
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords: FilteredRelation annotate
Cc: Morteza PRK Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When using FilteredRelation multiple times in single query, results are wrong.
consider following example (with Django 2.2.6):

The models are:

from django.db import models


class UserType(models.Model):
    pass


class Commodity(models.Model):
    pass


class CommodityCount(models.Model):
    commodity = models.ForeignKey(Commodity, on_delete=models.CASCADE)
    user_type = models.ForeignKey(UserType, on_delete=models.CASCADE)
    small_box = models.IntegerField(default=0)

    class Meta:
        unique_together = ('commodity', 'user_type')


class CommodityDiscount(models.Model):
    commodity = models.ForeignKey(Commodity, on_delete=models.CASCADE)
    user_type = models.ForeignKey(UserType, on_delete=models.CASCADE)
    small_box = models.IntegerField(default=0)

    class Meta:
        unique_together = ('commodity', 'user_type')

following query is what I want:

query = Commodity.objects.annotate(
    cnt=FilteredRelation('commoditycount', condition=Q(commoditycount__user_type_id=1)), 
    dst=FilteredRelation('commoditydiscount', condition=Q(commoditydiscount__user_type_id=1))
).filter(
    cnt__isnull=False, 
    dst__isnull=False
).select_related('cnt','dst')

resulting query is ok:

SELECT
    "ma_commodity"."id",
    cnt."id",
    cnt."commodity_id",
    cnt."user_type_id",
    cnt."small_box",
    dst."id",
    dst."commodity_id",
    dst."user_type_id",
    dst."small_box"
FROM
    "ma_commodity"
    INNER JOIN "ma_commoditycount" cnt ON (
        "ma_commodity"."id" = cnt."commodity_id"
        AND (cnt."user_type_id" = 1)
    )
    INNER JOIN "ma_commoditydiscount" dst ON (
        "ma_commodity"."id" = dst."commodity_id"
        AND (dst."user_type_id" = 1)
    )
WHERE
    (
        cnt."id" IS NOT NULL
        AND dst."id" IS NOT NULL
    )

but results are not ok:

first_item = query.first()
print(dir(first_item))
>>> [ ... '_state', 'check', 'clean', 'clean_fields', 'commoditycount_set', 'commoditydiscount_set', 
    'date_error_message', 'delete', 'dst', 'from_db', 'full_clean', 'get_deferred_fields', 'id', 'objects', 
    'pk', 'prepare_database_save', 'refresh_from_db', 'save', 'save_base', 'serializable_value', 'unique_error_message', 'validate_unique'
    ]

as you can see, there is dst, but no cnt.
if I remove dst and its related FilteredRelation, cnt re appear.

Attachments (1)

test-30854.diff (1.2 KB ) - added by Mariusz Felisiak 5 years ago.
Test.

Download all attachments as: .zip

Change History (8)

comment:1 by Morteza PRK, 5 years ago

Cc: Morteza PRK added

comment:2 by Mariusz Felisiak, 5 years ago

Summary: FilteredRelation on ManyToOne generates wrong resultSelecting multiple FilteredRelation's returns only the last one.
Triage Stage: UnreviewedAccepted
Version: 2.2master

Thanks for this report. I attached a simple test.

Reproduced at dafdfd6a60638c4edcca7c4e65d11c0af654d759.

by Mariusz Felisiak, 5 years ago

Attachment: test-30854.diff added

Test.

comment:3 by Hasan Ramezani, 5 years ago

Owner: changed from nobody to Hasan Ramezani
Status: newassigned

comment:4 by Hasan Ramezani, 5 years ago

Has patch: set
Last edited 5 years ago by Mariusz Felisiak (previous) (diff)

comment:5 by Mariusz Felisiak <felisiak.mariusz@…>, 5 years ago

In e1ae2b0:

Refs #30854 -- Moved local_setter() outside the loop in SQLCompiler.get_related_selections().

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 5 years ago

Resolution: fixed
Status: assignedclosed

In 6a75cea7:

Fixed #30854 -- Fixed QuerySet.select_related() with multiple FilteredRelations.

comment:7 by Mariusz Felisiak <felisiak.mariusz@…>, 5 years ago

In c1cfec6b:

[3.0.x] Fixed #30854 -- Fixed QuerySet.select_related() with multiple FilteredRelations.

Backport of 6a75cea76a98c08bf2e20d787be9b14c2cd94860 from master.

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