Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Split GenericRelationsTests.test_generic_relations into several tests…

…; refs #18586.
  • Loading branch information...
commit 7b064e539009b4845ca31bd4a3dd5a9b913d1a0e 1 parent 2a5c750
@jose-lpa jose-lpa authored timgraham committed
Showing with 134 additions and 98 deletions.
  1. +134 −98 tests/generic_relations/tests.py
View
232 tests/generic_relations/tests.py
@@ -4,6 +4,7 @@
from django.contrib.contenttypes.forms import generic_inlineformset_factory
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldError
+from django.db.models import Q
from django.test import TestCase
from django.utils import six
@@ -14,154 +15,189 @@
class GenericRelationsTests(TestCase):
- def test_generic_relations(self):
- # Create the world in 7 lines of code...
- lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo")
- platypus = Animal.objects.create(
- common_name="Platypus", latin_name="Ornithorhynchus anatinus"
- )
+ def setUp(self):
+ self.lion = Animal.objects.create(
+ common_name="Lion", latin_name="Panthera leo")
+ self.platypus = Animal.objects.create(
+ common_name="Platypus", latin_name="Ornithorhynchus anatinus")
Vegetable.objects.create(name="Eggplant", is_yucky=True)
- bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
- quartz = Mineral.objects.create(name="Quartz", hardness=7)
+ self.bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
+ self.quartz = Mineral.objects.create(name="Quartz", hardness=7)
- # Objects with declared GenericRelations can be tagged directly -- the
- # API mimics the many-to-many API.
- bacon.tags.create(tag="fatty")
- bacon.tags.create(tag="salty")
- lion.tags.create(tag="yellow")
- lion.tags.create(tag="hairy")
- platypus.tags.create(tag="fatty")
- self.assertQuerysetEqual(lion.tags.all(), [
+ # Tagging stuff.
+ self.bacon.tags.create(tag="fatty")
+ self.bacon.tags.create(tag="salty")
+ self.lion.tags.create(tag="yellow")
+ self.lion.tags.create(tag="hairy")
+
+ # Original list of tags:
+ self.comp_func = lambda obj: (
+ obj.tag, obj.content_type.model_class(), obj.object_id
+ )
+
+ def test_generic_relations_m2m_mimic(self):
+ """
+ Objects with declared GenericRelations can be tagged directly -- the
+ API mimics the many-to-many API.
+ """
+ self.assertQuerysetEqual(self.lion.tags.all(), [
"<TaggedItem: hairy>",
"<TaggedItem: yellow>"
])
- self.assertQuerysetEqual(bacon.tags.all(), [
+ self.assertQuerysetEqual(self.bacon.tags.all(), [
"<TaggedItem: fatty>",
"<TaggedItem: salty>"
])
- # You can easily access the content object like a foreign key.
- t = TaggedItem.objects.get(tag="salty")
- self.assertEqual(t.content_object, bacon)
- qs = TaggedItem.objects.filter(animal__isnull=False).order_by('animal__common_name', 'tag')
+ def test_access_content_object(self):
+ """
+ Test accessing the content object like a foreign key.
+ """
+ tagged_item = TaggedItem.objects.get(tag="salty")
+ self.assertEqual(tagged_item.content_object, self.bacon)
+
+ def test_query_content_object(self):
+ qs = TaggedItem.objects.filter(
+ animal__isnull=False).order_by('animal__common_name', 'tag')
self.assertQuerysetEqual(
- qs, ["<TaggedItem: hairy>", "<TaggedItem: yellow>", "<TaggedItem: fatty>"]
+ qs, ["<TaggedItem: hairy>", "<TaggedItem: yellow>"]
)
+
mpk = ManualPK.objects.create(id=1)
mpk.tags.create(tag='mpk')
- from django.db.models import Q
- qs = TaggedItem.objects.filter(Q(animal__isnull=False) | Q(manualpk__id=1)).order_by('tag')
+ qs = TaggedItem.objects.filter(
+ Q(animal__isnull=False) | Q(manualpk__id=1)).order_by('tag')
self.assertQuerysetEqual(
- qs, ["fatty", "hairy", "mpk", "yellow"], lambda x: x.tag)
- mpk.delete()
+ qs, ["hairy", "mpk", "yellow"], lambda x: x.tag)
+ def test_exclude_generic_relations(self):
+ """
+ Test lookups over an object without GenericRelations.
+ """
# Recall that the Mineral class doesn't have an explicit GenericRelation
# defined. That's OK, because you can create TaggedItems explicitly.
- tag1 = TaggedItem.objects.create(content_object=quartz, tag="shiny")
- TaggedItem.objects.create(content_object=quartz, tag="clearish")
-
# However, excluding GenericRelations means your lookups have to be a
# bit more explicit.
- ctype = ContentType.objects.get_for_model(quartz)
+ TaggedItem.objects.create(content_object=self.quartz, tag="shiny")
+ TaggedItem.objects.create(content_object=self.quartz, tag="clearish")
+
+ ctype = ContentType.objects.get_for_model(self.quartz)
q = TaggedItem.objects.filter(
- content_type__pk=ctype.id, object_id=quartz.id
+ content_type__pk=ctype.id, object_id=self.quartz.id
)
self.assertQuerysetEqual(q, [
"<TaggedItem: clearish>",
"<TaggedItem: shiny>"
])
- # You can set a generic foreign key in the way you'd expect.
- tag1.content_object = platypus
+ def test_access_via_content_type(self):
+ """
+ Test lookups through content type.
+ """
+ self.lion.delete()
+ self.platypus.tags.create(tag="fatty")
+
+ ctype = ContentType.objects.get_for_model(self.platypus)
+
+ self.assertQuerysetEqual(
+ Animal.objects.filter(tags__content_type=ctype),
+ ["<Animal: Platypus>"])
+
+ def test_set_foreign_key(self):
+ """
+ You can set a generic foreign key in the way you'd expect.
+ """
+ tag1 = TaggedItem.objects.create(content_object=self.quartz, tag="shiny")
+ tag1.content_object = self.platypus
tag1.save()
- self.assertQuerysetEqual(platypus.tags.all(), [
- "<TaggedItem: fatty>",
- "<TaggedItem: shiny>"
- ])
- q = TaggedItem.objects.filter(
- content_type__pk=ctype.id, object_id=quartz.id
- )
- self.assertQuerysetEqual(q, ["<TaggedItem: clearish>"])
- # Queries across generic relations respect the content types. Even
- # though there are two TaggedItems with a tag of "fatty", this query
- # only pulls out the one with the content type related to Animals.
+ self.assertQuerysetEqual(
+ self.platypus.tags.all(),
+ ["<TaggedItem: shiny>"])
+
+ def test_queries_across_generic_relations(self):
+ """
+ Queries across generic relations respect the content types. Even though
+ there are two TaggedItems with a tag of "fatty", this query only pulls
+ out the one with the content type related to Animals.
+ """
self.assertQuerysetEqual(Animal.objects.order_by('common_name'), [
"<Animal: Lion>",
"<Animal: Platypus>"
])
- # Create another fatty tagged instance with different PK to ensure
- # there is a content type restriction in the generated queries below.
- mpk = ManualPK.objects.create(id=lion.pk)
+
+ def test_queries_content_type_restriction(self):
+ """
+ Create another fatty tagged instance with different PK to ensure there
+ is a content type restriction in the generated queries below.
+ """
+ mpk = ManualPK.objects.create(id=self.lion.pk)
mpk.tags.create(tag="fatty")
- self.assertQuerysetEqual(Animal.objects.filter(tags__tag='fatty'), [
- "<Animal: Platypus>"
- ])
- self.assertQuerysetEqual(Animal.objects.exclude(tags__tag='fatty'), [
- "<Animal: Lion>"
- ])
- mpk.delete()
+ self.platypus.tags.create(tag="fatty")
- # If you delete an object with an explicit Generic relation, the related
- # objects are deleted when the source object is deleted.
- # Original list of tags:
- comp_func = lambda obj: (
- obj.tag, obj.content_type.model_class(), obj.object_id
- )
+ self.assertQuerysetEqual(
+ Animal.objects.filter(tags__tag='fatty'), ["<Animal: Platypus>"])
+ self.assertQuerysetEqual(
+ Animal.objects.exclude(tags__tag='fatty'), ["<Animal: Lion>"])
+ def test_object_deletion_with_generic_relation(self):
+ """
+ If you delete an object with an explicit Generic relation, the related
+ objects are deleted when the source object is deleted.
+ """
self.assertQuerysetEqual(TaggedItem.objects.all(), [
- ('clearish', Mineral, quartz.pk),
- ('fatty', Animal, platypus.pk),
- ('fatty', Vegetable, bacon.pk),
- ('hairy', Animal, lion.pk),
- ('salty', Vegetable, bacon.pk),
- ('shiny', Animal, platypus.pk),
- ('yellow', Animal, lion.pk)
+ ('fatty', Vegetable, self.bacon.pk),
+ ('hairy', Animal, self.lion.pk),
+ ('salty', Vegetable, self.bacon.pk),
+ ('yellow', Animal, self.lion.pk)
],
- comp_func
+ self.comp_func
)
- lion.delete()
+ self.lion.delete()
+
self.assertQuerysetEqual(TaggedItem.objects.all(), [
- ('clearish', Mineral, quartz.pk),
- ('fatty', Animal, platypus.pk),
- ('fatty', Vegetable, bacon.pk),
- ('salty', Vegetable, bacon.pk),
- ('shiny', Animal, platypus.pk)
+ ('fatty', Vegetable, self.bacon.pk),
+ ('salty', Vegetable, self.bacon.pk),
],
- comp_func
+ self.comp_func
)
- # If Generic Relation is not explicitly defined, any related objects
- # remain after deletion of the source object.
- quartz_pk = quartz.pk
- quartz.delete()
+ def test_object_deletion_without_generic_relation(self):
+ """
+ If Generic Relation is not explicitly defined, any related objects
+ remain after deletion of the source object.
+ """
+ TaggedItem.objects.create(content_object=self.quartz, tag="clearish")
+ quartz_pk = self.quartz.pk
+ self.quartz.delete()
self.assertQuerysetEqual(TaggedItem.objects.all(), [
('clearish', Mineral, quartz_pk),
- ('fatty', Animal, platypus.pk),
- ('fatty', Vegetable, bacon.pk),
- ('salty', Vegetable, bacon.pk),
- ('shiny', Animal, platypus.pk)
+ ('fatty', Vegetable, self.bacon.pk),
+ ('hairy', Animal, self.lion.pk),
+ ('salty', Vegetable, self.bacon.pk),
+ ('yellow', Animal, self.lion.pk),
],
- comp_func
+ self.comp_func
)
- # If you delete a tag, the objects using the tag are unaffected
- # (other than losing a tag)
- tag = TaggedItem.objects.order_by("id")[0]
+
+ def test_tag_deletion_related_objects_unaffected(self):
+ """
+ If you delete a tag, the objects using the tag are unaffected (other
+ than losing a tag).
+ """
+ ctype = ContentType.objects.get_for_model(self.lion)
+ tag = TaggedItem.objects.get(
+ content_type__pk=ctype.id, object_id=self.lion.id, tag="hairy")
tag.delete()
- self.assertQuerysetEqual(bacon.tags.all(), ["<TaggedItem: salty>"])
+
+ self.assertQuerysetEqual(self.lion.tags.all(), ["<TaggedItem: yellow>"])
self.assertQuerysetEqual(TaggedItem.objects.all(), [
- ('clearish', Mineral, quartz_pk),
- ('fatty', Animal, platypus.pk),
- ('salty', Vegetable, bacon.pk),
- ('shiny', Animal, platypus.pk)
+ ('fatty', Vegetable, self.bacon.pk),
+ ('salty', Vegetable, self.bacon.pk),
+ ('yellow', Animal, self.lion.pk)
],
- comp_func
+ self.comp_func
)
- TaggedItem.objects.filter(tag='fatty').delete()
- ctype = ContentType.objects.get_for_model(lion)
- self.assertQuerysetEqual(Animal.objects.filter(tags__content_type=ctype), [
- "<Animal: Platypus>"
- ])
def test_assign_with_queryset(self):
# Ensure that querysets used in reverse GFK assignments are pre-evaluated
Please sign in to comment.
Something went wrong with that request. Please try again.