diff options
| author | Anubhav Joshi <anubhav9042@gmail.com> | 2014-06-14 12:54:19 +0530 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2014-07-01 06:12:58 -0400 |
| commit | 34ba86706f0db33d9a0ab44e4abb78703e7262a9 (patch) | |
| tree | 03eecf917508ff81d80ab262d4b3336973f082da /tests | |
| parent | 81edf2d006f57d53ef08d0c881adf66f9aa391f7 (diff) | |
Fixed #14334 -- Query relation lookups now check object types.
Thanks rpbarlow for the suggestion; and loic, akaariai, and jorgecarleitao
for reviews.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/one_to_one/tests.py | 1 | ||||
| -rw-r--r-- | tests/queries/models.py | 15 | ||||
| -rw-r--r-- | tests/queries/tests.py | 103 |
3 files changed, 99 insertions, 20 deletions
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py index f0a7a175a7..af983fed74 100644 --- a/tests/one_to_one/tests.py +++ b/tests/one_to_one/tests.py @@ -100,7 +100,6 @@ class OneToOneTests(TestCase): assert_filter_waiters(restaurant__place__exact=self.p1) assert_filter_waiters(restaurant__place__pk=self.p1.pk) assert_filter_waiters(restaurant__exact=self.p1.pk) - assert_filter_waiters(restaurant__exact=self.p1) assert_filter_waiters(restaurant__pk=self.p1.pk) assert_filter_waiters(restaurant=self.p1.pk) assert_filter_waiters(restaurant=self.r) diff --git a/tests/queries/models.py b/tests/queries/models.py index 0dd4833b53..465b8f2446 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -409,6 +409,15 @@ class ObjectA(models.Model): return self.name +class ProxyObjectA(ObjectA): + class Meta: + proxy = True + + +class ChildObjectA(ObjectA): + pass + + @python_2_unicode_compatible class ObjectB(models.Model): name = models.CharField(max_length=50) @@ -419,11 +428,17 @@ class ObjectB(models.Model): return self.name +class ProxyObjectB(ObjectB): + class Meta: + proxy = True + + @python_2_unicode_compatible class ObjectC(models.Model): name = models.CharField(max_length=50) objecta = models.ForeignKey(ObjectA, null=True) objectb = models.ForeignKey(ObjectB, null=True) + childobjecta = models.ForeignKey(ChildObjectA, null=True, related_name='ca_pk') def __str__(self): return self.name diff --git a/tests/queries/tests.py b/tests/queries/tests.py index f6e8d79309..a47461bb86 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -22,12 +22,12 @@ from .models import ( ExtraInfo, Fan, Item, LeafA, Join, LeafB, LoopX, LoopZ, ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten, Node, ObjectA, - ObjectB, ObjectC, CategoryItem, SimpleCategory, SpecialCategory, - OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject, - ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities, - BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book, - MyObject, Order, OrderItem, SharedConnection, Task, Staff, StaffUser, - CategoryRelationship, Ticket21203Parent, Ticket21203Child, Person, + ProxyObjectA, ChildObjectA, ObjectB, ProxyObjectB, ObjectC, CategoryItem, + SimpleCategory, SpecialCategory, OneToOneCategory, NullableName, ProxyCategory, + SingleObject, RelatedObject, ModelA, ModelB, ModelC, ModelD, Responsibility, Job, + JobResponsibilities, BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, + Chapter, Book, MyObject, Order, OrderItem, SharedConnection, Task, Staff, + StaffUser, CategoryRelationship, Ticket21203Parent, Ticket21203Child, Person, Company, Employment, CustomPk, CustomPkTag, Classroom, School, Student) @@ -3361,20 +3361,85 @@ class Ticket12807Tests(TestCase): class RelatedLookupTypeTests(TestCase): + error = 'Cannot query "%s": Must be "%s" instance.' + + def setUp(self): + self.oa = ObjectA.objects.create(name="oa") + self.poa = ProxyObjectA.objects.get(name="oa") + self.coa = ChildObjectA.objects.create(name="coa") + self.wrong_type = Order.objects.create(id=self.oa.pk) + self.ob = ObjectB.objects.create(name="ob", objecta=self.oa, num=1) + ProxyObjectB.objects.create(name="pob", objecta=self.oa, num=2) + self.pob = ProxyObjectB.objects.all() + ObjectC.objects.create(childobjecta=self.coa) + def test_wrong_type_lookup(self): - oa = ObjectA.objects.create(name="oa") - wrong_type = Order.objects.create(id=oa.pk) - ob = ObjectB.objects.create(name="ob", objecta=oa, num=1) - # Currently Django doesn't care if the object is of correct - # type, it will just use the objecta's related fields attribute - # (id) for model lookup. Making things more restrictive could - # be a good idea... - self.assertQuerysetEqual( - ObjectB.objects.filter(objecta=wrong_type), - [ob], lambda x: x) - self.assertQuerysetEqual( - ObjectB.objects.filter(objecta__in=[wrong_type]), - [ob], lambda x: x) + """ + A ValueError is raised when the incorrect object type is passed to a + query lookup. + """ + # Passing incorrect object type + with self.assertRaisesMessage(ValueError, + self.error % (self.wrong_type, ObjectA._meta.object_name)): + ObjectB.objects.get(objecta=self.wrong_type) + + with self.assertRaisesMessage(ValueError, + self.error % (self.wrong_type, ObjectA._meta.object_name)): + ObjectB.objects.filter(objecta__in=[self.wrong_type]) + + with self.assertRaisesMessage(ValueError, + self.error % (self.wrong_type, ObjectA._meta.object_name)): + ObjectB.objects.filter(objecta=self.wrong_type) + + with self.assertRaisesMessage(ValueError, + self.error % (self.wrong_type, ObjectB._meta.object_name)): + ObjectA.objects.filter(objectb__in=[self.wrong_type, self.ob]) + + # Passing an object of the class on which query is done. + with self.assertRaisesMessage(ValueError, + self.error % (self.ob, ObjectA._meta.object_name)): + ObjectB.objects.filter(objecta__in=[self.poa, self.ob]) + + with self.assertRaisesMessage(ValueError, + self.error % (self.ob, ChildObjectA._meta.object_name)): + ObjectC.objects.exclude(childobjecta__in=[self.coa, self.ob]) + + def test_wrong_backward_lookup(self): + """ + A ValueError is raised when the incorrect object type is passed to a + query lookup for backward relations. + """ + with self.assertRaisesMessage(ValueError, + self.error % (self.oa, ObjectB._meta.object_name)): + ObjectA.objects.filter(objectb__in=[self.oa, self.ob]) + + with self.assertRaisesMessage(ValueError, + self.error % (self.oa, ObjectB._meta.object_name)): + ObjectA.objects.exclude(objectb=self.oa) + + with self.assertRaisesMessage(ValueError, + self.error % (self.wrong_type, ObjectB._meta.object_name)): + ObjectA.objects.get(objectb=self.wrong_type) + + def test_correct_lookup(self): + """ + When passing proxy model objects, child objects, or parent objects, + lookups work fine. + """ + out_a = ['<ObjectA: oa>', ] + out_b = ['<ObjectB: ob>', '<ObjectB: pob>'] + out_c = ['<ObjectC: >'] + + # proxy model objects + self.assertQuerysetEqual(ObjectB.objects.filter(objecta=self.poa).order_by('name'), out_b) + self.assertQuerysetEqual(ObjectA.objects.filter(objectb__in=self.pob).order_by('pk'), out_a * 2) + + # child objects + self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.coa]), []) + self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.poa, self.coa]).order_by('name'), out_b) + + # parent objects + self.assertQuerysetEqual(ObjectC.objects.exclude(childobjecta=self.oa), out_c) class Ticket14056Tests(TestCase): |
