summaryrefslogtreecommitdiff
path: root/tests/model_inheritance
diff options
context:
space:
mode:
authorAlexander Shchapov <alexanderad@gmail.com>2014-12-03 23:24:42 +0200
committerTim Graham <timograham@gmail.com>2014-12-03 18:54:47 -0500
commit2cd19f3738b9c4a6861c007bf22f72a386cba07f (patch)
tree1e9fd01c0b5fa3e7d8ba01da3c9f2e2592805998 /tests/model_inheritance
parent49d034fff21213b369c08b39772e0437c3cc723b (diff)
downloaddjango-2cd19f3738b9c4a6861c007bf22f72a386cba07f.tar.gz
Refs #18586 -- Split up model_inheritance.ModelInheritanceTest
Diffstat (limited to 'tests/model_inheritance')
-rw-r--r--tests/model_inheritance/tests.py268
1 files changed, 135 insertions, 133 deletions
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index bf76286391..10721a6b3f 100644
--- a/tests/model_inheritance/tests.py
+++ b/tests/model_inheritance/tests.py
@@ -49,9 +49,16 @@ class ModelInheritanceTests(TestCase):
# doesn't exist as a model).
self.assertRaises(AttributeError, lambda: CommonInfo.objects.all())
- def test_multiple_table(self):
- post = Post.objects.create(title="Lorem Ipsum")
+ def test_reverse_relation_for_different_hierarchy_tree(self):
+ # Even though p.supplier for a Place 'p' (a parent of a Supplier), a
+ # Restaurant object cannot access that reverse relation, since it's not
+ # part of the Place-Supplier Hierarchy.
+ self.assertQuerysetEqual(Place.objects.filter(supplier__name="foo"), [])
+ self.assertRaises(FieldError, Restaurant.objects.filter, supplier__name="foo")
+
+ def test_model_with_distinct_accessors(self):
# The Post model has distinct accessors for the Comment and Link models.
+ post = Post.objects.create(title="Lorem Ipsum")
post.attached_comment_set.create(content="Save $ on V1agr@", is_spam=True)
post.attached_link_set.create(
content="The Web framework for perfections with deadlines.",
@@ -64,40 +71,98 @@ class ModelInheritanceTests(TestCase):
AttributeError, getattr, post, "attached_%(class)s_set"
)
- # The Place/Restaurant/ItalianRestaurant models all exist as
- # independent models. However, the subclasses also have transparent
- # access to the fields of their ancestors.
- # Create a couple of Places.
- Place.objects.create(name="Master Shakes", address="666 W. Jersey")
- Place.objects.create(name="Ace Hardware", address="1013 N. Ashland")
+ def test_meta_fields_and_ordering(self):
+ # Make sure Restaurant and ItalianRestaurant have the right fields in
+ # the right order.
+ self.assertEqual(
+ [f.name for f in Restaurant._meta.fields],
+ ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
+ "serves_pizza", "chef"]
+ )
+ self.assertEqual(
+ [f.name for f in ItalianRestaurant._meta.fields],
+ ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
+ "serves_pizza", "chef", "restaurant_ptr", "serves_gnocchi"],
+ )
+ self.assertEqual(Restaurant._meta.ordering, ["-rating"])
+
+ def test_custompk_m2m(self):
+ b = Base.objects.create()
+ b.titles.add(Title.objects.create(title="foof"))
+ s = SubBase.objects.create(sub_id=b.id)
+ b = Base.objects.get(pk=s.id)
+ self.assertNotEqual(b.pk, s.pk)
+ # Low-level test for related_val
+ self.assertEqual(s.titles.related_val, (s.id,))
+ # Higher level test for correct query values (title foof not
+ # accidentally found).
+ self.assertQuerysetEqual(s.titles.all(), [])
+
+ def test_update_parent_filtering(self):
+ """
+ Test that updating a field of a model subclass doesn't issue an UPDATE
+ query constrained by an inner query.
+ Refs #10399
+ """
+ supplier = Supplier.objects.create(
+ name='Central market',
+ address='610 some street',
+ )
+ # Capture the expected query in a database agnostic way
+ with CaptureQueriesContext(connection) as captured_queries:
+ Place.objects.filter(pk=supplier.pk).update(name=supplier.name)
+ expected_sql = captured_queries[0]['sql']
+ # Capture the queries executed when a subclassed model instance is saved.
+ with CaptureQueriesContext(connection) as captured_queries:
+ supplier.save(update_fields=('name',))
+ for query in captured_queries:
+ sql = query['sql']
+ if 'UPDATE' in sql:
+ self.assertEqual(expected_sql, sql)
+
+ def test_eq(self):
+ # Equality doesn't transfer in multitable inheritance.
+ self.assertNotEqual(Place(id=1), Restaurant(id=1))
+ self.assertNotEqual(Restaurant(id=1), Place(id=1))
+
+ def test_mixin_init(self):
+ m = MixinModel()
+ self.assertEqual(m.other_attr, 1)
- # Test constructor for Restaurant.
- r = Restaurant.objects.create(
+
+class ModelInheritanceDataTests(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.restaurant = Restaurant.objects.create(
name="Demon Dogs",
address="944 W. Fullerton",
serves_hot_dogs=True,
serves_pizza=False,
- rating=2
+ rating=2,
)
- # Test the constructor for ItalianRestaurant.
- c = Chef.objects.create(name="Albert")
- ir = ItalianRestaurant.objects.create(
+
+ chef = Chef.objects.create(name="Albert")
+ cls.italian_restaurant = ItalianRestaurant.objects.create(
name="Ristorante Miron",
address="1234 W. Ash",
serves_hot_dogs=False,
serves_pizza=False,
serves_gnocchi=True,
rating=4,
- chef=c
+ chef=chef,
)
+
+ def test_filter_inherited_model(self):
self.assertQuerysetEqual(
ItalianRestaurant.objects.filter(address="1234 W. Ash"), [
"Ristorante Miron",
],
attrgetter("name")
)
- ir.address = "1234 W. Elm"
- ir.save()
+
+ def test_update_inherited_model(self):
+ self.italian_restaurant.address = "1234 W. Elm"
+ self.italian_restaurant.save()
self.assertQuerysetEqual(
ItalianRestaurant.objects.filter(address="1234 W. Elm"), [
"Ristorante Miron",
@@ -105,28 +170,7 @@ class ModelInheritanceTests(TestCase):
attrgetter("name")
)
- # Make sure Restaurant and ItalianRestaurant have the right fields in
- # the right order.
- self.assertEqual(
- [f.name for f in Restaurant._meta.fields],
- ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
- "serves_pizza", "chef"]
- )
- self.assertEqual(
- [f.name for f in ItalianRestaurant._meta.fields],
- ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
- "serves_pizza", "chef", "restaurant_ptr", "serves_gnocchi"],
- )
- self.assertEqual(Restaurant._meta.ordering, ["-rating"])
-
- # Even though p.supplier for a Place 'p' (a parent of a Supplier), a
- # Restaurant object cannot access that reverse relation, since it's not
- # part of the Place-Supplier Hierarchy.
- self.assertQuerysetEqual(Place.objects.filter(supplier__name="foo"), [])
- self.assertRaises(
- FieldError, Restaurant.objects.filter, supplier__name="foo"
- )
-
+ def test_parent_fields_available_for_filtering_in_child_model(self):
# Parent fields can be used directly in filters on the child model.
self.assertQuerysetEqual(
Restaurant.objects.filter(name="Demon Dogs"), [
@@ -135,21 +179,24 @@ class ModelInheritanceTests(TestCase):
attrgetter("name")
)
self.assertQuerysetEqual(
- ItalianRestaurant.objects.filter(address="1234 W. Elm"), [
+ ItalianRestaurant.objects.filter(address="1234 W. Ash"), [
"Ristorante Miron",
],
attrgetter("name")
)
+ def test_filter_on_parent_returns_object_of_parent_type(self):
# Filters against the parent model return objects of the parent's type.
p = Place.objects.get(name="Demon Dogs")
self.assertIs(type(p), Place)
+ def test_parent_child_one_to_one_link(self):
# Since the parent and child are linked by an automatically created
# OneToOneField, you can get from the parent to the child by using the
# child's name.
self.assertEqual(
- p.restaurant, Restaurant.objects.get(name="Demon Dogs")
+ Place.objects.get(name="Demon Dogs").restaurant,
+ Restaurant.objects.get(name="Demon Dogs")
)
self.assertEqual(
Place.objects.get(name="Ristorante Miron").restaurant.italianrestaurant,
@@ -160,29 +207,35 @@ class ModelInheritanceTests(TestCase):
ItalianRestaurant.objects.get(name="Ristorante Miron")
)
+ def test_parent_child_one_to_one_link_on_nonrelated_objects(self):
# This won't work because the Demon Dogs restaurant is not an Italian
# restaurant.
self.assertRaises(
ItalianRestaurant.DoesNotExist,
- lambda: p.restaurant.italianrestaurant
+ lambda: Place.objects.get(name="Demon Dogs").restaurant.italianrestaurant
)
+
+ def test_inherited_does_not_exist_exception(self):
# An ItalianRestaurant which does not exist is also a Place which does
# not exist.
self.assertRaises(
Place.DoesNotExist,
ItalianRestaurant.objects.get, name="The Noodle Void"
)
+
+ def test_inherited_multiple_objects_returned_exception(self):
# MultipleObjectsReturned is also inherited.
self.assertRaises(
Place.MultipleObjectsReturned,
Restaurant.objects.get, id__lt=12321
)
+ def test_related_objects_for_inherited_models(self):
# Related objects work just as they normally do.
s1 = Supplier.objects.create(name="Joe's Chickens", address="123 Sesame St")
- s1.customers = [r, ir]
+ s1.customers = [self.restaurant, self.italian_restaurant]
s2 = Supplier.objects.create(name="Luigi's Pasta", address="456 Sesame St")
- s2.customers = [ir]
+ s2.customers = [self.italian_restaurant]
# This won't work because the Place we select is not a Restaurant (it's
# a Supplier).
@@ -193,7 +246,7 @@ class ModelInheritanceTests(TestCase):
self.assertEqual(p.supplier, s1)
self.assertQuerysetEqual(
- ir.provider.order_by("-name"), [
+ self.italian_restaurant.provider.order_by("-name"), [
"Luigi's Pasta",
"Joe's Chickens"
],
@@ -217,7 +270,7 @@ class ModelInheritanceTests(TestCase):
name="Main St", address="111 Main St", main_site=s1
)
ParkingLot.objects.create(
- name="Well Lit", address="124 Sesame St", main_site=ir
+ name="Well Lit", address="124 Sesame St", main_site=self.italian_restaurant
)
self.assertEqual(
@@ -225,6 +278,7 @@ class ModelInheritanceTests(TestCase):
"Ristorante Miron"
)
+ def test_update_works_on_parent_and_child_models_at_once(self):
# The update() command can update fields in parent and child classes at
# once (although it executed multiple SQL queries to do so).
rows = Restaurant.objects.filter(
@@ -234,18 +288,20 @@ class ModelInheritanceTests(TestCase):
)
self.assertEqual(rows, 1)
- r1 = Restaurant.objects.get(pk=r.pk)
+ r1 = Restaurant.objects.get(pk=self.restaurant.pk)
self.assertFalse(r1.serves_hot_dogs)
self.assertEqual(r1.name, "Demon Puppies")
+ def test_values_works_on_parent_model_fields(self):
# The values() command also works on fields from parent models.
self.assertQuerysetEqual(
ItalianRestaurant.objects.values("name", "rating"), [
- {"rating": 4, "name": "Ristorante Miron"}
+ {"rating": 4, "name": "Ristorante Miron"},
],
lambda o: o
)
+ def test_select_related_works_on_parent_model_fields(self):
# select_related works with fields from the parent object as if they
# were a normal part of the model.
self.assertNumQueries(
@@ -260,22 +316,6 @@ class ModelInheritanceTests(TestCase):
#23370 - Should be able to defer child fields when using
select_related() from parent to child.
"""
- Restaurant.objects.create(
- name="Demon Dogs",
- address="944 W. Fullerton",
- serves_hot_dogs=True,
- serves_pizza=False,
- rating=2,
- )
- ItalianRestaurant.objects.create(
- name="Ristorante Miron",
- address="1234 W. Ash",
- serves_hot_dogs=False,
- serves_pizza=False,
- serves_gnocchi=True,
- rating=4,
- )
-
qs = (Restaurant.objects
.select_related("italianrestaurant")
.defer("italianrestaurant__serves_gnocchi")
@@ -292,91 +332,53 @@ class ModelInheritanceTests(TestCase):
self.assertEqual(qs[1].italianrestaurant.name, 'Ristorante Miron')
self.assertEqual(qs[1].italianrestaurant.rating, 4)
- def test_mixin_init(self):
- m = MixinModel()
- self.assertEqual(m.other_attr, 1)
-
def test_update_query_counts(self):
"""
Test that update queries do not generate non-necessary queries.
Refs #18304.
"""
- c = Chef.objects.create(name="Albert")
- ir = ItalianRestaurant.objects.create(
- name="Ristorante Miron",
- address="1234 W. Ash",
- serves_hot_dogs=False,
- serves_pizza=False,
- serves_gnocchi=True,
- rating=4,
- chef=c
- )
with self.assertNumQueries(3):
- ir.save()
+ self.italian_restaurant.save()
- def test_update_parent_filtering(self):
- """
- Test that updating a field of a model subclass doesn't issue an UPDATE
- query constrained by an inner query.
- Refs #10399
- """
- supplier = Supplier.objects.create(
- name='Central market',
- address='610 some street'
+ def test_filter_inherited_on_null(self):
+ # Refs #12567
+ Supplier.objects.create(
+ name="Central market",
+ address="610 some street",
)
- # Capture the expected query in a database agnostic way
- with CaptureQueriesContext(connection) as captured_queries:
- Place.objects.filter(pk=supplier.pk).update(name=supplier.name)
- expected_sql = captured_queries[0]['sql']
- # Capture the queries executed when a subclassed model instance is saved.
- with CaptureQueriesContext(connection) as captured_queries:
- supplier.save(update_fields=('name',))
- for query in captured_queries:
- sql = query['sql']
- if 'UPDATE' in sql:
- self.assertEqual(expected_sql, sql)
-
- def test_eq(self):
- # Equality doesn't transfer in multitable inheritance.
- self.assertNotEqual(Place(id=1), Restaurant(id=1))
- self.assertNotEqual(Restaurant(id=1), Place(id=1))
-
- def test_ticket_12567(self):
- r = Restaurant.objects.create(name='n1', address='a1')
- s = Supplier.objects.create(name='s1', address='a2')
self.assertQuerysetEqual(
- Place.objects.filter(supplier__isnull=False),
- [Place.objects.get(pk=s.pk)],
- lambda x: x
+ Place.objects.filter(supplier__isnull=False), [
+ "Central market",
+ ],
+ attrgetter("name")
)
self.assertQuerysetEqual(
- Place.objects.filter(supplier__isnull=True),
- [Place.objects.get(pk=r.pk)],
- lambda x: x
+ Place.objects.filter(supplier__isnull=True).order_by("name"), [
+ "Demon Dogs",
+ "Ristorante Miron",
+ ],
+ attrgetter("name")
)
- self.assertQuerysetEqual(
- Place.objects.exclude(supplier__isnull=False),
- [Place.objects.get(pk=r.pk)],
- lambda x: x
+
+ def test_exclude_inherited_on_null(self):
+ # Refs #12567
+ Supplier.objects.create(
+ name="Central market",
+ address="610 some street",
)
self.assertQuerysetEqual(
- Place.objects.exclude(supplier__isnull=True),
- [Place.objects.get(pk=s.pk)],
- lambda x: x
+ Place.objects.exclude(supplier__isnull=False).order_by("name"), [
+ "Demon Dogs",
+ "Ristorante Miron",
+ ],
+ attrgetter("name")
)
-
- def test_custompk_m2m(self):
- b = Base.objects.create()
- b.titles.add(Title.objects.create(title="foof"))
- s = SubBase.objects.create(sub_id=b.id)
- b = Base.objects.get(pk=s.id)
- self.assertNotEqual(b.pk, s.pk)
- # Low-level test for related_val
- self.assertEqual(s.titles.related_val, (s.id,))
- # Higher level test for correct query values (title foof not
- # accidentally found).
self.assertQuerysetEqual(
- s.titles.all(), [])
+ Place.objects.exclude(supplier__isnull=True), [
+ "Central market",
+ ],
+ attrgetter("name")
+ )
class InheritanceSameModelNameTests(TransactionTestCase):