summaryrefslogtreecommitdiff
path: root/tests/select_related
diff options
context:
space:
mode:
authorNiclas Olofsson <n@niclasolofsson.se>2014-12-04 21:47:48 +0100
committerTim Graham <timograham@gmail.com>2014-12-24 14:54:30 -0500
commit3daa9d60be6672841ceed5bb812b6fb25950dc16 (patch)
tree1771ecd7ab15fd5795bb605c9d7e710ed0b86935 /tests/select_related
parentb27db97b236569d059fa824c3078e06adf8b4fae (diff)
downloaddjango-3daa9d60be6672841ceed5bb812b6fb25950dc16.tar.gz
Fixed #10414 -- Made select_related() fail on invalid field names.
Diffstat (limited to 'tests/select_related')
-rw-r--r--tests/select_related/models.py41
-rw-r--r--tests/select_related/tests.py56
2 files changed, 96 insertions, 1 deletions
diff --git a/tests/select_related/models.py b/tests/select_related/models.py
index 13170e7e69..96aace6a48 100644
--- a/tests/select_related/models.py
+++ b/tests/select_related/models.py
@@ -10,6 +10,9 @@ the select-related behavior will traverse.
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
+from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
+from django.contrib.contenttypes.models import ContentType
+
# Who remembers high school biology?
@@ -94,3 +97,41 @@ class HybridSpecies(models.Model):
def __str__(self):
return self.name
+
+
+@python_2_unicode_compatible
+class Topping(models.Model):
+ name = models.CharField(max_length=30)
+
+ def __str__(self):
+ return self.name
+
+
+@python_2_unicode_compatible
+class Pizza(models.Model):
+ name = models.CharField(max_length=100)
+ toppings = models.ManyToManyField(Topping)
+
+ def __str__(self):
+ return self.name
+
+
+@python_2_unicode_compatible
+class TaggedItem(models.Model):
+ tag = models.CharField(max_length=30)
+
+ content_type = models.ForeignKey(ContentType, related_name='select_related_tagged_items')
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey('content_type', 'object_id')
+
+ def __str__(self):
+ return self.tag
+
+
+@python_2_unicode_compatible
+class Bookmark(models.Model):
+ url = models.URLField()
+ tags = GenericRelation(TaggedItem)
+
+ def __str__(self):
+ return self.url
diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py
index 6b029fa64b..378c0bf992 100644
--- a/tests/select_related/tests.py
+++ b/tests/select_related/tests.py
@@ -1,8 +1,12 @@
from __future__ import unicode_literals
from django.test import TestCase
+from django.core.exceptions import FieldError
-from .models import Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species, HybridSpecies
+from .models import (
+ Domain, Kingdom, Phylum, Klass, Order, Family, Genus, Species, HybridSpecies,
+ Pizza, TaggedItem, Bookmark,
+)
class SelectRelatedTests(TestCase):
@@ -126,6 +130,12 @@ class SelectRelatedTests(TestCase):
orders = [o.genus.family.order.name for o in world]
self.assertEqual(orders, ['Agaricales'])
+ def test_single_related_field(self):
+ with self.assertNumQueries(1):
+ species = Species.objects.select_related('genus__name')
+ names = [s.genus.name for s in species]
+ self.assertEqual(sorted(names), ['Amanita', 'Drosophila', 'Homo', 'Pisum'])
+
def test_field_traversal(self):
with self.assertNumQueries(1):
s = (Species.objects.all()
@@ -152,3 +162,47 @@ class SelectRelatedTests(TestCase):
obj = queryset[0]
self.assertEqual(obj.parent_1, parent_1)
self.assertEqual(obj.parent_2, parent_2)
+
+
+class SelectRelatedValidationTests(TestCase):
+ """
+ select_related() should thrown an error on fields that do not exist and
+ non-relational fields.
+ """
+ non_relational_error = "Non-relational field given in select_related: '%s'. Choices are: %s"
+ invalid_error = "Invalid field name(s) given in select_related: '%s'. Choices are: %s"
+
+ def test_non_relational_field(self):
+ with self.assertRaisesMessage(FieldError, self.non_relational_error % ('name', 'genus')):
+ list(Species.objects.select_related('name__some_field'))
+
+ with self.assertRaisesMessage(FieldError, self.non_relational_error % ('name', 'genus')):
+ list(Species.objects.select_related('name'))
+
+ with self.assertRaisesMessage(FieldError, self.non_relational_error % ('name', '(none)')):
+ list(Domain.objects.select_related('name'))
+
+ def test_many_to_many_field(self):
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('toppings', '(none)')):
+ list(Pizza.objects.select_related('toppings'))
+
+ def test_reverse_relational_field(self):
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('child_1', 'genus')):
+ list(Species.objects.select_related('child_1'))
+
+ def test_invalid_field(self):
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('invalid_field', 'genus')):
+ list(Species.objects.select_related('invalid_field'))
+
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('related_invalid_field', 'family')):
+ list(Species.objects.select_related('genus__related_invalid_field'))
+
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('invalid_field', '(none)')):
+ list(Domain.objects.select_related('invalid_field'))
+
+ def test_generic_relations(self):
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('tags', '')):
+ list(Bookmark.objects.select_related('tags'))
+
+ with self.assertRaisesMessage(FieldError, self.invalid_error % ('content_object', 'content_type')):
+ list(TaggedItem.objects.select_related('content_object'))