What we are experiencing is that when you use GenericForeignKey and
GenericRelation, you can't use exclude on the QuerySet.
Here is our setup:
{{{
from django.contrib.contenttypes.fields import GenericForeignKey,
GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models
class Insights(models.Model):
object_id = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType)
parent_object = GenericForeignKey()
first_field = models.IntegerField()
second_field = models.IntegerField()
class ModelA(models.Model):
name = models.CharField(max_length=40)
insights = GenericRelation('Insights', related_query_name='a')
class ModelB(models.Model):
title = models.CharField(max_length=40)
insights = GenericRelation('Insights', related_query_name='b')
}}}
and here is how to reproduce this bug:
{{{
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 23 2015, 02:52:03)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from app.models import *
>>> a = ModelA.objects.create(name='Test')
>>> a = ModelA.objects.create(name='Test2')
>>> b = ModelB.objects.create(title='B Test')
>>> i = Insights.objects.create(parent_object=a, first_field=1,
second_field=2)
>>> i = Insights.objects.create(parent_object=a, first_field=1,
second_field=2)
>>> i = Insights.objects.create(parent_object=b, first_field=1,
second_field=2)
>>> Insights.objects.count()
3
>>> i = Insights.objects.filter(a__name='Test2')
>>> i
[<Insights: Insights object>]
>>> i = Insights.objects.filter(a__name='Test2').exclude(a__name='Test')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/query.py", line 797, in exclude
return self._filter_or_exclude(True, *args, **kwargs)
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/query.py", line 806, in _filter_or_exclude
clone.query.add_q(~Q(*args, **kwargs))
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/sql/query.py", line 1243, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/sql/query.py", line 1269, in _add_q
allow_joins=allow_joins, split_subq=split_subq,
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/sql/query.py", line 1181, in build_filter
can_reuse, e.names_with_path)
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/sql/query.py", line 1499, in split_exclude
trimmed_prefix, contains_louter = query.trim_start(names_with_path)
File "/Users/ahadi/.virtualenvs/django/lib/python3.4/site-
packages/django/db/models/sql/query.py", line 1934, in trim_start
join_field = path.join_field.field
AttributeError: 'GenericRelation' object has no attribute 'field'
}}}
We have the problem with Django version 1.8.9, but also reproduced it with
Django 1.9.2.
A demo project is attached.
--
Ticket URL: <https://code.djangoproject.com/ticket/26261>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* Attachment "djangogenericrelationbug.zip" added.
Demo Project
* needs_docs: => 0
* type: Uncategorized => Bug
* needs_tests: => 0
* needs_better_patch: => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:1>
Comment (by Muty):
This also happens when you use Q objects combined with NOT.
{{{
Insights.objects.filter(~Q(a__name='Test'))
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:2>
* stage: Unreviewed => Accepted
Comment:
Looks like this hasn't worked since the introduction of
`related_query_name` in Django 1.7. Attaching a regression test.
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:3>
* Attachment "26261-test.diff" added.
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:4>
* cc: steve@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:5>
Comment (by Collederas):
I'm looking into this issue and I have noticed that, referring to the
regression test case that have been attached, when excluding on a
{{{TaggedItem}}} for {{{animal__common_name}}} the PathInfo generated by
the {{{names_to_path}}} methods have the {{{m2m}}} attribute set to True.
Is this correct behaviour or is this the source of the issue? Would love
to know more to move towards a patch.
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:6>
Comment (by Todor Velichkov):
Since this is not fixed yet, a workaround would be to use Conditional
Expressions
{{{
from django.db import models
Insights.objects.annotate(
is_a_name_eq_to_test=models.Case(
models.When(
a__name='Test2',
then=models.Value(True),
),
default=models.Value(False),
output_field=models.BooleanField(),
)
).filter(is_a_name_eq_to_test=False)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:7>
* owner: nobody => gorodovoy9000
* status: new => assigned
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/16305 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:8>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:9>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"04b15022e8d1f49af69d8a1e6cd678f31f1280ff" 04b1502]:
{{{
#!CommitTicketReference repository=""
revision="04b15022e8d1f49af69d8a1e6cd678f31f1280ff"
Fixed #26261 -- Fixed queryset crash when excluding reverse
GenericRelation.
Thanks Amir Hadi for the report.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26261#comment:10>