Aggregates with joins ignore extra filters provided by setup_joins
|Reported by:||fas||Owned by:||fas|
|Component:||Database layer (models, ORM)||Version:||master|
|Severity:||Normal||Keywords:||orm, aggregation, join, contenttypes, filter|
|Cc:||mbencun@…, jdunck@…, michaelg@…, robin, coderanger, carljm, chrischambers, joeri@…, anssi.kaariainen@…, ris, alanjds, daevaorn@…, fhahn, herve||Triage Stage:||Accepted|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
(In case the description that follows is not understandable, please ask me for a better explanation).
An example where extra filters in joins are used are reverse generic relations (http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations).
class TaggedItem(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') class Bookmark(models.Model): url = models.URLField() tags = generic.GenericRelation(TaggedItem)
By querying Bookmark.objects.filter(tags=some_tag) the generic relation adds extra filters to ensure the correct content type. Those extra filters however are ignored when using aggregates, which leads to wrong results.
For example, the following query is not correct because it does not check the content_type.
What this aggregate actually calculates per bookmark is not the amount of tags for this bookmark but the amount of tags for any model referenced by TaggedItem with the same object id.
The error is isolated in db/models/sql/query.py in the add_aggregate method:
field, source, opts, join_list, last, _ = self.setup_joins( field_list, opts, self.get_initial_alias(), False) # Process the join chain to see if it can be trimmed col, _, join_list = self.trim_joins(source, join_list, last, False)
The last dummy element _ is normally named 'extra' in other uses of setup_joins and contains the extra filters needed to make it work. Adding self.add_filter(*extra) after setup_joins fixes this problem.
Change History (33)
comment:1 Changed 5 years ago by Alex
- Needs documentation unset
- Needs tests unset
- Patch needs improvement unset
- Triage Stage changed from Unreviewed to Accepted
- Version changed from 1.0 to SVN
comment:19 Changed 3 years ago by akaariai
- Cc anssi.kaariainen@… added
- Has patch set
- Needs tests set
- Patch needs improvement set
comment:28 Changed 14 months ago by Anssi Kääriäinen <akaariai@…>
- Resolution set to fixed
- Status changed from new to closed