summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnssi Kääriäinen <anssi.kaariainen@thl.fi>2016-01-29 11:03:47 +0200
committerTim Graham <timograham@gmail.com>2016-02-11 09:00:38 -0500
commit25496f0f7b953b9bca709ab20bc536137f57402d (patch)
treeec2abf41e3b5b76cb9d2d6e8f392fa47be596a2a
parentf7332b3ec552cb0067851fb5a4c0f97c5b2bb1f6 (diff)
[1.9.x] Fixed #26153 -- Reallowed Q-objects in ForeignObject.get_extra_descriptor_filter().
Backport of 353aecbf8c1a8cc6f3985149e2895d49e53dfc1c from master
-rw-r--r--django/db/models/fields/related.py10
-rw-r--r--django/db/models/fields/related_descriptors.py2
-rw-r--r--docs/releases/1.9.3.txt4
-rw-r--r--tests/foreign_object/models/article.py13
-rw-r--r--tests/foreign_object/tests.py13
5 files changed, 39 insertions, 3 deletions
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 211c1cdf86..31434864cd 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -8,6 +8,7 @@ from django.apps import apps
from django.core import checks, exceptions
from django.db import connection, router
from django.db.backends import utils
+from django.db.models import Q
from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL
from django.db.models.query_utils import PathInfo
from django.db.models.utils import make_model_tuple
@@ -332,8 +333,13 @@ class RelatedField(Field):
rh_field.attname: getattr(obj, lh_field.attname)
for lh_field, rh_field in self.related_fields
}
- base_filter.update(self.get_extra_descriptor_filter(obj) or {})
- return base_filter
+ descriptor_filter = self.get_extra_descriptor_filter(obj)
+ base_q = Q(**base_filter)
+ if isinstance(descriptor_filter, dict):
+ return base_q & Q(**descriptor_filter)
+ elif descriptor_filter:
+ return base_q & descriptor_filter
+ return base_q
@property
def swappable_setting(self):
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index e9caa2680f..abfa7283ae 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -164,7 +164,7 @@ class ForwardManyToOneDescriptor(object):
rel_obj = None
else:
qs = self.get_queryset(instance=instance)
- qs = qs.filter(**self.field.get_reverse_related_filter(instance))
+ qs = qs.filter(self.field.get_reverse_related_filter(instance))
# Assuming the database enforces foreign keys, this won't fail.
rel_obj = qs.get()
# If this is a one-to-one relation, set the reverse accessor
diff --git a/docs/releases/1.9.3.txt b/docs/releases/1.9.3.txt
index 994a018fbc..61a92878c7 100644
--- a/docs/releases/1.9.3.txt
+++ b/docs/releases/1.9.3.txt
@@ -17,3 +17,7 @@ Bugfixes
* Added system checks for query name clashes of hidden relationships
(:ticket:`26162`).
+
+* Fixed a regression for cases where
+ ``ForeignObject.get_extra_descriptor_filter()`` returned a ``Q`` object
+ (:ticket:`26153`).
diff --git a/tests/foreign_object/models/article.py b/tests/foreign_object/models/article.py
index f0c2f3fbac..6e16784d2c 100644
--- a/tests/foreign_object/models/article.py
+++ b/tests/foreign_object/models/article.py
@@ -44,6 +44,11 @@ class ActiveTranslationField(models.ForeignObject):
setattr(cls, self.name, ArticleTranslationDescriptor(self))
+class ActiveTranslationFieldWithQ(ActiveTranslationField):
+ def get_extra_descriptor_filter(self, instance):
+ return models.Q(lang=get_language())
+
+
@python_2_unicode_compatible
class Article(models.Model):
active_translation = ActiveTranslationField(
@@ -54,6 +59,14 @@ class Article(models.Model):
on_delete=models.CASCADE,
null=True,
)
+ active_translation_q = ActiveTranslationFieldWithQ(
+ 'ArticleTranslation',
+ from_fields=['id'],
+ to_fields=['article'],
+ related_name='+',
+ on_delete=models.CASCADE,
+ null=True,
+ )
pub_date = models.DateField()
def __str__(self):
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py
index bcdadc6d6d..c838ae4b66 100644
--- a/tests/foreign_object/tests.py
+++ b/tests/foreign_object/tests.py
@@ -467,3 +467,16 @@ class TestModelCheckTests(SimpleTestCase):
apps = test_apps
self.assertEqual(Child._meta.get_field('parent').check(from_model=Child), [])
+
+
+class TestExtraJoinFilterQ(TestCase):
+ @translation.override('fi')
+ def test_extra_join_filter_q(self):
+ a = Article.objects.create(pub_date=datetime.datetime.today())
+ ArticleTranslation.objects.create(article=a, lang='fi', title='title', body='body')
+ qs = Article.objects.all()
+ with self.assertNumQueries(2):
+ self.assertEqual(qs[0].active_translation_q.title, 'title')
+ qs = qs.select_related('active_translation_q')
+ with self.assertNumQueries(1):
+ self.assertEqual(qs[0].active_translation_q.title, 'title')