From 8b6974a6857bdc48ad50bf21527b840c27648891 Mon Sep 17 00:00:00 2001 From: Tomo Otsuka Date: Tue, 22 Dec 2015 23:22:54 +0000 Subject: [PATCH] Fixed #25972 -- Restored support for the isnull lookup with ForeignObject. --- django/db/models/fields/related.py | 7 ++++--- django/db/models/fields/related_lookups.py | 7 ++++++- docs/releases/1.9.1.txt | 3 +++ tests/foreign_object/models/person.py | 13 +++++++------ tests/foreign_object/tests.py | 12 ++++++++++++ 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index ea4d8d3218..9d2895fb54 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -25,7 +25,7 @@ from .related_descriptors import ( ) from .related_lookups import ( RelatedExact, RelatedGreaterThan, RelatedGreaterThanOrEqual, RelatedIn, - RelatedLessThan, RelatedLessThanOrEqual, + RelatedIsNull, RelatedLessThan, RelatedLessThanOrEqual, ) from .reverse_related import ( ForeignObjectRel, ManyToManyRel, ManyToOneRel, OneToOneRel, @@ -672,9 +672,10 @@ class ForeignObject(RelatedField): return RelatedLessThan elif lookup_name == 'lte': return RelatedLessThanOrEqual - elif lookup_name != 'isnull': + elif lookup_name == 'isnull': + return RelatedIsNull + else: raise TypeError('Related Field got invalid lookup: %s' % lookup_name) - return super(ForeignObject, self).get_lookup(lookup_name) def get_transform(self, *args, **kwargs): raise NotImplementedError('Relational fields do not support transforms.') diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py index d3e4f8fa8a..0f5a8b5e21 100644 --- a/django/db/models/fields/related_lookups.py +++ b/django/db/models/fields/related_lookups.py @@ -1,5 +1,6 @@ from django.db.models.lookups import ( - Exact, GreaterThan, GreaterThanOrEqual, In, LessThan, LessThanOrEqual, + Exact, GreaterThan, GreaterThanOrEqual, In, IsNull, LessThan, + LessThanOrEqual, ) @@ -131,3 +132,7 @@ class RelatedGreaterThanOrEqual(RelatedLookupMixin, GreaterThanOrEqual): class RelatedLessThanOrEqual(RelatedLookupMixin, LessThanOrEqual): pass + + +class RelatedIsNull(RelatedLookupMixin, IsNull): + pass diff --git a/docs/releases/1.9.1.txt b/docs/releases/1.9.1.txt index a40604780f..f7fa7cf37c 100644 --- a/docs/releases/1.9.1.txt +++ b/docs/releases/1.9.1.txt @@ -64,3 +64,6 @@ Bugfixes * Restored the functionality of the admin's ``list_editable`` add and change buttons (:ticket:`25903`). + +* Fixed ``isnull`` query lookup for ``ForeignObject`` + (:ticket:`25972`). diff --git a/tests/foreign_object/models/person.py b/tests/foreign_object/models/person.py index eeb3da832e..26d88007fb 100644 --- a/tests/foreign_object/models/person.py +++ b/tests/foreign_object/models/person.py @@ -56,19 +56,19 @@ class Membership(models.Model): date_joined = models.DateTimeField(default=datetime.datetime.now) invite_reason = models.CharField(max_length=64, null=True) person_id = models.IntegerField() - group_id = models.IntegerField() + group_id = models.IntegerField(blank=True, null=True) # Relation Fields person = models.ForeignObject( Person, - from_fields=['membership_country', 'person_id'], - to_fields=['person_country_id', 'id'], + from_fields=['person_id', 'membership_country'], + to_fields=['id', 'person_country_id'], on_delete=models.CASCADE, ) group = models.ForeignObject( Group, - from_fields=['membership_country', 'group_id'], - to_fields=['group_country', 'id'], + from_fields=['group_id', 'membership_country'], + to_fields=['id', 'group_country'], on_delete=models.CASCADE, ) @@ -76,7 +76,8 @@ class Membership(models.Model): ordering = ('date_joined', 'invite_reason') def __str__(self): - return "%s is a member of %s" % (self.person.name, self.group.name) + group_name = self.group.name if self.group_id else 'NULL' + return "%s is a member of %s" % (self.person.name, group_name) class Friendship(models.Model): diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py index 5291275b25..bcdadc6d6d 100644 --- a/tests/foreign_object/tests.py +++ b/tests/foreign_object/tests.py @@ -395,6 +395,18 @@ class MultiColumnFKTests(TestCase): objs = [Person(name="abcd_%s" % i, person_country=self.usa) for i in range(0, 5)] Person.objects.bulk_create(objs, 10) + def test_isnull_lookup(self): + Membership.objects.create(membership_country=self.usa, person=self.bob, group_id=None) + Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia) + self.assertQuerysetEqual( + Membership.objects.filter(group__isnull=True), + [''] + ) + self.assertQuerysetEqual( + Membership.objects.filter(group__isnull=False), + [''] + ) + class TestModelCheckTests(SimpleTestCase):