summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAnubhav Joshi <anubhav9042@gmail.com>2014-06-14 12:54:19 +0530
committerTim Graham <timograham@gmail.com>2014-07-01 06:12:58 -0400
commit34ba86706f0db33d9a0ab44e4abb78703e7262a9 (patch)
tree03eecf917508ff81d80ab262d4b3336973f082da /tests
parent81edf2d006f57d53ef08d0c881adf66f9aa391f7 (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.py1
-rw-r--r--tests/queries/models.py15
-rw-r--r--tests/queries/tests.py103
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):