Opened 16 years ago
Closed 11 years ago
#10461 closed Bug (fixed)
Annotation and generic relations do not work well together
Reported by: | Matthias Kestenholz | Owned by: | fhahn |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | generic relations, annotate |
Cc: | stryderjzw@…, mbencun@…, tim.babych@…, Robin, seldon, flo@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Take the following models.py:
from django.db import models from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db.models import Sum class Note(models.Model): text = models.TextField() content_type = models.ForeignKey(ContentType) object_id = models.IntegerField() content_object = generic.GenericForeignKey() def __unicode__(self): return self.text class Something(models.Model): name = models.CharField(max_length=100) notes = generic.GenericRelation(Note) def __unicode__(self): return self.name
And the following django/python shell session:
In [1]: from genann.models import * In [2]: s = Something.objects.create(name='Diesunddas') In [3]: Note.objects.create(content_object=s, text='note') Out[3]: <Note: note> In [4]: s.notes.all() Out[4]: [<Note: note>] In [5]: Something.objects.all().annotate(Sum('notes')) Out[5]: [<Something: Diesunddas>] In [6]: Something.objects.all().annotate(Sum('notes'))[0].notes__sum Out[6]: 1
So far, everything seems to work. It does not however, since the annotation clause does not take the content type into account:
In [7]: from django.db import connection In [8]: connection.queries[-1] Out[8]: {'sql': u'SELECT "genann_something"."id", "genann_something"."name", SUM("genann_note"."id") AS "notes__sum" FROM "genann_something" LEFT OUTER JOIN "genann_note" ON ("genann_something"."id" = "genann_note"."object_id") GROUP BY "genann_something"."id", "genann_something"."name" LIMIT 1', 'time': '0.000'}
And here it falls completely apart:
In [9]: Something.objects.all().annotate(Sum('notes')).filter(notes__sum__gt=0) --------------------------------------------------------------------------- FieldError Traceback (most recent call last) /home/mk/Projects/bugsquash/genann/<ipython console> in <module>() /home/mk/Projects/bugsquash/django/django/db/models/query.pyc in filter(self, *args, **kwargs) 520 set. 521 """ --> 522 return self._filter_or_exclude(False, *args, **kwargs) 523 524 def exclude(self, *args, **kwargs): /home/mk/Projects/bugsquash/django/django/db/models/query.pyc in _filter_or_exclude(self, negate, *args, **kwargs) 538 clone.query.add_q(~Q(*args, **kwargs)) 539 else: --> 540 clone.query.add_q(Q(*args, **kwargs)) 541 return clone 542 /home/mk/Projects/bugsquash/django/django/db/models/sql/query.pyc in add_q(self, q_object, used_aliases) 1489 else: 1490 self.add_filter(child, connector, q_object.negated, -> 1491 can_reuse=used_aliases) 1492 if connector == OR: 1493 # Aliases that were newly added or not used at all need to /home/mk/Projects/bugsquash/django/django/db/models/sql/query.pyc in add_filter(self, filter_expr, connector, negate, trim, can_reuse, process_extras) 1387 field, target, opts, join_list, last, extra_filters = self.setup_joins( 1388 parts, opts, alias, True, allow_many, can_reuse=can_reuse, -> 1389 negate=negate, process_extras=process_extras) 1390 except MultiJoin, e: 1391 self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]), /home/mk/Projects/bugsquash/django/django/db/models/sql/query.pyc in setup_joins(self, names, opts, alias, dupe_multis, allow_many, allow_explicit_fk, can_reuse, negate, process_extras) 1552 names = opts.get_all_field_names() + self.aggregate_select.keys() 1553 raise FieldError("Cannot resolve keyword %r into field. " -> 1554 "Choices are: %s" % (name, ", ".join(names))) 1555 1556 if not allow_many and (m2m or not direct): FieldError: Cannot resolve keyword 'sum' into field. Choices are: content_type, id, object_id, something, text, notes__sum
It does not let me search for objects containing notes claiming that it does not know notes_ _sum, even though it appears in the list at the end of the traceback.
Thanks for all the awesome work!
Change History (14)
comment:1 by , 16 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 16 years ago
Cc: | added |
---|
comment:3 by , 16 years ago
I opened a new ticket (before seeing this one) that generalizes this ticket. http://code.djangoproject.com/ticket/10870.
comment:4 by , 16 years ago
Cc: | added |
---|
comment:6 by , 15 years ago
Cc: | added |
---|
comment:7 by , 14 years ago
Cc: | added |
---|
comment:8 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Bug |
comment:11 by , 13 years ago
Cc: | added |
---|
comment:12 by , 12 years ago
Component: | ORM aggregation → Database layer (models, ORM) |
---|
comment:13 by , 12 years ago
Cc: | added |
---|---|
Has patch: | set |
Keywords: | annotate added |
Needs documentation: | set |
Owner: | set to |
Status: | new → assigned |
I'm working on a GSOC proposal for "Improve annotation and aggregation" and this issue is mentioned on the wiki page. I looked into it and it seems fixed. I've created a branch and added a test (https://github.com/fhahn/django/commit/71cfbb97dcfacbd282d0467f439e7a1e3fcd1917)
This patch needs a documentation update as well (that's the reason I didn't open a PR yet), but I want to finish my proposal first.
comment:14 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
I can confirm this as of r10173. Aggregate/annotation don't work with generic relations because the query doesn't take Content Types into account.
Not sure what other info is helpful.