Fixed #26153 -- Reallowed Q-objects in ForeignObject.get_extra_descriptor_filter().

This commit is contained in:
Anssi Kääriäinen 2016-01-29 11:03:47 +02:00 committed by Tim Graham
parent 1d86d4c72b
commit 353aecbf8c
5 changed files with 39 additions and 3 deletions

View File

@ -8,6 +8,7 @@ from django.apps import apps
from django.core import checks, exceptions from django.core import checks, exceptions
from django.db import connection, router from django.db import connection, router
from django.db.backends import utils 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.deletion import CASCADE, SET_DEFAULT, SET_NULL
from django.db.models.query_utils import PathInfo from django.db.models.query_utils import PathInfo
from django.db.models.utils import make_model_tuple from django.db.models.utils import make_model_tuple
@ -337,8 +338,13 @@ class RelatedField(Field):
rh_field.attname: getattr(obj, lh_field.attname) rh_field.attname: getattr(obj, lh_field.attname)
for lh_field, rh_field in self.related_fields for lh_field, rh_field in self.related_fields
} }
base_filter.update(self.get_extra_descriptor_filter(obj) or {}) descriptor_filter = self.get_extra_descriptor_filter(obj)
return base_filter 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 @property
def swappable_setting(self): def swappable_setting(self):

View File

@ -166,7 +166,7 @@ class ForwardManyToOneDescriptor(object):
rel_obj = None rel_obj = None
else: else:
qs = self.get_queryset(instance=instance) 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. # Assuming the database enforces foreign keys, this won't fail.
rel_obj = qs.get() rel_obj = qs.get()
# If this is a one-to-one relation, set the reverse accessor # If this is a one-to-one relation, set the reverse accessor

View File

@ -17,3 +17,7 @@ Bugfixes
* Added system checks for query name clashes of hidden relationships * Added system checks for query name clashes of hidden relationships
(:ticket:`26162`). (:ticket:`26162`).
* Fixed a regression for cases where
``ForeignObject.get_extra_descriptor_filter()`` returned a ``Q`` object
(:ticket:`26153`).

View File

@ -44,6 +44,11 @@ class ActiveTranslationField(models.ForeignObject):
setattr(cls, self.name, ArticleTranslationDescriptor(self)) 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 @python_2_unicode_compatible
class Article(models.Model): class Article(models.Model):
active_translation = ActiveTranslationField( active_translation = ActiveTranslationField(
@ -54,6 +59,14 @@ class Article(models.Model):
on_delete=models.CASCADE, on_delete=models.CASCADE,
null=True, 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() pub_date = models.DateField()
def __str__(self): def __str__(self):

View File

@ -458,3 +458,16 @@ class TestModelCheckTests(SimpleTestCase):
) )
self.assertEqual(Child._meta.get_field('parent').check(from_model=Child), []) 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')