Migrated model_inheritance_regress doctests. Thanks to Gregor Müllegger for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14576 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b84838aef4
commit
35dc7d6033
|
@ -1,7 +1,3 @@
|
|||
"""
|
||||
Regression tests for Model inheritance behaviour.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from django.db import models
|
||||
|
@ -136,255 +132,3 @@ class BachelorParty(AbstractEvent):
|
|||
|
||||
class MessyBachelorParty(BachelorParty):
|
||||
pass
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Regression for #7350, #7202
|
||||
# Check that when you create a Parent object with a specific reference to an
|
||||
# existent child instance, saving the Parent doesn't duplicate the child. This
|
||||
# behaviour is only activated during a raw save - it is mostly relevant to
|
||||
# deserialization, but any sort of CORBA style 'narrow()' API would require a
|
||||
# similar approach.
|
||||
|
||||
# Create a child-parent-grandparent chain
|
||||
>>> place1 = Place(name="Guido's House of Pasta", address='944 W. Fullerton')
|
||||
>>> place1.save_base(raw=True)
|
||||
>>> restaurant = Restaurant(place_ptr=place1, serves_hot_dogs=True, serves_pizza=False)
|
||||
>>> restaurant.save_base(raw=True)
|
||||
>>> italian_restaurant = ItalianRestaurant(restaurant_ptr=restaurant, serves_gnocchi=True)
|
||||
>>> italian_restaurant.save_base(raw=True)
|
||||
|
||||
# Create a child-parent chain with an explicit parent link
|
||||
>>> place2 = Place(name='Main St', address='111 Main St')
|
||||
>>> place2.save_base(raw=True)
|
||||
>>> park = ParkingLot(parent=place2, capacity=100)
|
||||
>>> park.save_base(raw=True)
|
||||
|
||||
# Check that no extra parent objects have been created.
|
||||
>>> Place.objects.all()
|
||||
[<Place: Guido's House of Pasta the place>, <Place: Main St the place>]
|
||||
|
||||
>>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
|
||||
>>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_hot_dogs', True)]]
|
||||
True
|
||||
|
||||
>>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
|
||||
>>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_gnocchi', True), ('serves_hot_dogs', True)]]
|
||||
True
|
||||
|
||||
>>> dicts = ParkingLot.objects.values('name','capacity')
|
||||
>>> [sorted(d.items()) for d in dicts]
|
||||
[[('capacity', 100), ('name', u'Main St')]]
|
||||
|
||||
# You can also update objects when using a raw save.
|
||||
>>> place1.name = "Guido's All New House of Pasta"
|
||||
>>> place1.save_base(raw=True)
|
||||
|
||||
>>> restaurant.serves_hot_dogs = False
|
||||
>>> restaurant.save_base(raw=True)
|
||||
|
||||
>>> italian_restaurant.serves_gnocchi = False
|
||||
>>> italian_restaurant.save_base(raw=True)
|
||||
|
||||
>>> place2.name='Derelict lot'
|
||||
>>> place2.save_base(raw=True)
|
||||
|
||||
>>> park.capacity = 50
|
||||
>>> park.save_base(raw=True)
|
||||
|
||||
# No extra parent objects after an update, either.
|
||||
>>> Place.objects.all()
|
||||
[<Place: Derelict lot the place>, <Place: Guido's All New House of Pasta the place>]
|
||||
|
||||
>>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
|
||||
>>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_hot_dogs', False)]]
|
||||
True
|
||||
|
||||
>>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
|
||||
>>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
|
||||
True
|
||||
|
||||
>>> dicts = ParkingLot.objects.values('name','capacity')
|
||||
>>> [sorted(d.items()) for d in dicts]
|
||||
[[('capacity', 50), ('name', u'Derelict lot')]]
|
||||
|
||||
# If you try to raw_save a parent attribute onto a child object,
|
||||
# the attribute will be ignored.
|
||||
|
||||
>>> italian_restaurant.name = "Lorenzo's Pasta Hut"
|
||||
>>> italian_restaurant.save_base(raw=True)
|
||||
|
||||
# Note that the name has not changed
|
||||
# - name is an attribute of Place, not ItalianRestaurant
|
||||
>>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
|
||||
>>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
|
||||
True
|
||||
|
||||
# Regressions tests for #7105: dates() queries should be able to use fields
|
||||
# from the parent model as easily as the child.
|
||||
>>> obj = Child.objects.create(name='child', created=datetime.datetime(2008, 6, 26, 17, 0, 0))
|
||||
>>> Child.objects.dates('created', 'month')
|
||||
[datetime.datetime(2008, 6, 1, 0, 0)]
|
||||
|
||||
# Regression test for #7276: calling delete() on a model with multi-table
|
||||
# inheritance should delete the associated rows from any ancestor tables, as
|
||||
# well as any descendent objects.
|
||||
|
||||
>>> ident = ItalianRestaurant.objects.all()[0].id
|
||||
>>> Place.objects.get(pk=ident)
|
||||
<Place: Guido's All New House of Pasta the place>
|
||||
>>> xx = Restaurant.objects.create(name='a', address='xx', serves_hot_dogs=True, serves_pizza=False)
|
||||
|
||||
# This should delete both Restuarants, plus the related places, plus the ItalianRestaurant.
|
||||
>>> Restaurant.objects.all().delete()
|
||||
|
||||
>>> Place.objects.get(pk=ident)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: Place matching query does not exist.
|
||||
|
||||
>>> ItalianRestaurant.objects.get(pk=ident)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: ItalianRestaurant matching query does not exist.
|
||||
|
||||
# Regression test for #6755
|
||||
>>> r = Restaurant(serves_pizza=False)
|
||||
>>> r.save()
|
||||
>>> r.id == r.place_ptr_id
|
||||
True
|
||||
>>> orig_id = r.id
|
||||
>>> r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
|
||||
>>> r.save()
|
||||
>>> r.id == orig_id
|
||||
True
|
||||
>>> r.id == r.place_ptr_id
|
||||
True
|
||||
|
||||
# Regression test for #7488. This looks a little crazy, but it's the equivalent
|
||||
# of what the admin interface has to do for the edit-inline case.
|
||||
>>> Supplier.objects.filter(restaurant=Restaurant(name='xx', address='yy'))
|
||||
[]
|
||||
|
||||
# Regression test for #11764.
|
||||
>>> for w in Wholesaler.objects.all().select_related():
|
||||
... print w
|
||||
|
||||
# Regression test for #7853
|
||||
# If the parent class has a self-referential link, make sure that any updates
|
||||
# to that link via the child update the right table.
|
||||
|
||||
>>> obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
|
||||
>>> obj.delete()
|
||||
|
||||
# Regression tests for #8076 - get_(next/previous)_by_date should work.
|
||||
>>> c1 = ArticleWithAuthor(headline='ArticleWithAuthor 1', author="Person 1", pub_date=datetime.datetime(2005, 8, 1, 3, 0))
|
||||
>>> c1.save()
|
||||
>>> c2 = ArticleWithAuthor(headline='ArticleWithAuthor 2', author="Person 2", pub_date=datetime.datetime(2005, 8, 1, 10, 0))
|
||||
>>> c2.save()
|
||||
>>> c3 = ArticleWithAuthor(headline='ArticleWithAuthor 3', author="Person 3", pub_date=datetime.datetime(2005, 8, 2))
|
||||
>>> c3.save()
|
||||
|
||||
>>> c1.get_next_by_pub_date()
|
||||
<ArticleWithAuthor: ArticleWithAuthor 2>
|
||||
>>> c2.get_next_by_pub_date()
|
||||
<ArticleWithAuthor: ArticleWithAuthor 3>
|
||||
>>> c3.get_next_by_pub_date()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: ArticleWithAuthor matching query does not exist.
|
||||
>>> c3.get_previous_by_pub_date()
|
||||
<ArticleWithAuthor: ArticleWithAuthor 2>
|
||||
>>> c2.get_previous_by_pub_date()
|
||||
<ArticleWithAuthor: ArticleWithAuthor 1>
|
||||
>>> c1.get_previous_by_pub_date()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: ArticleWithAuthor matching query does not exist.
|
||||
|
||||
# Regression test for #8825: Make sure all inherited fields (esp. m2m fields, in
|
||||
# this case) appear on the child class.
|
||||
>>> M2MChild.objects.filter(articles__isnull=False)
|
||||
[]
|
||||
|
||||
# All fields from an ABC, including those inherited non-abstractly should be
|
||||
# available on child classes (#7588). Creating this instance should work
|
||||
# without error.
|
||||
>>> _ = QualityControl.objects.create(headline="Problems in Django", pub_date=datetime.datetime.now(), quality=10, assignee="adrian")
|
||||
|
||||
# Ordering should not include any database column more than once (this is most
|
||||
# likely to ocurr naturally with model inheritance, so we check it here).
|
||||
# Regression test for #9390. This necessarily pokes at the SQL string for the
|
||||
# query, since the duplicate problems are only apparent at that late stage.
|
||||
>>> qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
|
||||
>>> sql = qs.query.get_compiler(qs.db).as_sql()[0]
|
||||
>>> fragment = sql[sql.find('ORDER BY'):]
|
||||
>>> pos = fragment.find('pub_date')
|
||||
>>> fragment.find('pub_date', pos + 1) == -1
|
||||
True
|
||||
|
||||
# It is possible to call update() and only change a field in an ancestor model
|
||||
# (regression test for #10362).
|
||||
>>> article = ArticleWithAuthor.objects.create(author="fred", headline="Hey there!", pub_date = datetime.datetime(2009, 3, 1, 8, 0, 0))
|
||||
>>> ArticleWithAuthor.objects.filter(author="fred").update(headline="Oh, no!")
|
||||
1
|
||||
>>> ArticleWithAuthor.objects.filter(pk=article.pk).update(headline="Oh, no!")
|
||||
1
|
||||
|
||||
>>> DerivedM.objects.create(customPK=44, base_name="b1", derived_name="d1")
|
||||
<DerivedM: PK = 44, base_name = b1, derived_name = d1>
|
||||
>>> DerivedM.objects.all()
|
||||
[<DerivedM: PK = 44, base_name = b1, derived_name = d1>]
|
||||
|
||||
# Regression tests for #10406
|
||||
|
||||
# If there's a one-to-one link between a child model and the parent and no
|
||||
# explicit pk declared, we can use the one-to-one link as the pk on the child.
|
||||
# The ParkingLot2 model shows this behaviour.
|
||||
>>> ParkingLot2._meta.pk.name
|
||||
"parent"
|
||||
|
||||
# However, the connector from child to parent need not be the pk on the child
|
||||
# at all.
|
||||
>>> ParkingLot3._meta.pk.name
|
||||
"primary_key"
|
||||
>>> ParkingLot3._meta.get_ancestor_link(Place).name # the child->parent link
|
||||
"parent"
|
||||
|
||||
# Check that many-to-many relations defined on an abstract base class
|
||||
# are correctly inherited (and created) on the child class.
|
||||
>>> p1 = Person.objects.create(name='Alice')
|
||||
>>> p2 = Person.objects.create(name='Bob')
|
||||
>>> p3 = Person.objects.create(name='Carol')
|
||||
>>> p4 = Person.objects.create(name='Dave')
|
||||
|
||||
>>> birthday = BirthdayParty.objects.create(name='Birthday party for Alice')
|
||||
>>> birthday.attendees = [p1, p3]
|
||||
|
||||
>>> bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
|
||||
>>> bachelor.attendees = [p2, p4]
|
||||
|
||||
>>> print p1.birthdayparty_set.all()
|
||||
[<BirthdayParty: Birthday party for Alice>]
|
||||
|
||||
>>> print p1.bachelorparty_set.all()
|
||||
[]
|
||||
|
||||
>>> print p2.bachelorparty_set.all()
|
||||
[<BachelorParty: Bachelor party for Bob>]
|
||||
|
||||
# Check that a subclass of a subclass of an abstract model
|
||||
# doesn't get it's own accessor.
|
||||
>>> p2.messybachelorparty_set.all()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AttributeError: 'Person' object has no attribute 'messybachelorparty_set'
|
||||
|
||||
# ... but it does inherit the m2m from it's parent
|
||||
>>> messy = MessyBachelorParty.objects.create(name='Bachelor party for Dave')
|
||||
>>> messy.attendees = [p4]
|
||||
|
||||
>>> p4.bachelorparty_set.all()
|
||||
[<BachelorParty: Bachelor party for Bob>, <BachelorParty: Bachelor party for Dave>]
|
||||
|
||||
"""}
|
||||
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
"""
|
||||
Regression tests for Model inheritance behaviour.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from django.test import TestCase
|
||||
from regressiontests.model_inheritance_regress.models import (
|
||||
Place, Restaurant, ItalianRestaurant, ParkingLot, ParkingLot2,
|
||||
ParkingLot3, Supplier, Wholesaler, Child, SelfRefChild, ArticleWithAuthor,
|
||||
M2MChild, QualityControl, DerivedM, Person, BirthdayParty, BachelorParty,
|
||||
MessyBachelorParty)
|
||||
|
||||
class ModelInheritanceTest(TestCase):
|
||||
def test_model_inheritance(self):
|
||||
# Regression for #7350, #7202
|
||||
# Check that when you create a Parent object with a specific reference
|
||||
# to an existent child instance, saving the Parent doesn't duplicate
|
||||
# the child. This behaviour is only activated during a raw save - it
|
||||
# is mostly relevant to deserialization, but any sort of CORBA style
|
||||
# 'narrow()' API would require a similar approach.
|
||||
|
||||
# Create a child-parent-grandparent chain
|
||||
place1 = Place(
|
||||
name="Guido's House of Pasta",
|
||||
address='944 W. Fullerton')
|
||||
place1.save_base(raw=True)
|
||||
restaurant = Restaurant(
|
||||
place_ptr=place1,
|
||||
serves_hot_dogs=True,
|
||||
serves_pizza=False)
|
||||
restaurant.save_base(raw=True)
|
||||
italian_restaurant = ItalianRestaurant(
|
||||
restaurant_ptr=restaurant,
|
||||
serves_gnocchi=True)
|
||||
italian_restaurant.save_base(raw=True)
|
||||
|
||||
# Create a child-parent chain with an explicit parent link
|
||||
place2 = Place(name='Main St', address='111 Main St')
|
||||
place2.save_base(raw=True)
|
||||
park = ParkingLot(parent=place2, capacity=100)
|
||||
park.save_base(raw=True)
|
||||
|
||||
# Check that no extra parent objects have been created.
|
||||
places = list(Place.objects.all())
|
||||
self.assertEqual(places, [place1, place2])
|
||||
|
||||
dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
|
||||
self.assertEqual(dicts, [{
|
||||
'name': u"Guido's House of Pasta",
|
||||
'serves_hot_dogs': True
|
||||
}])
|
||||
|
||||
dicts = list(ItalianRestaurant.objects.values(
|
||||
'name','serves_hot_dogs','serves_gnocchi'))
|
||||
self.assertEqual(dicts, [{
|
||||
'name': u"Guido's House of Pasta",
|
||||
'serves_gnocchi': True,
|
||||
'serves_hot_dogs': True,
|
||||
}])
|
||||
|
||||
dicts = list(ParkingLot.objects.values('name','capacity'))
|
||||
self.assertEqual(dicts, [{
|
||||
'capacity': 100,
|
||||
'name': u'Main St',
|
||||
}])
|
||||
|
||||
# You can also update objects when using a raw save.
|
||||
place1.name = "Guido's All New House of Pasta"
|
||||
place1.save_base(raw=True)
|
||||
|
||||
restaurant.serves_hot_dogs = False
|
||||
restaurant.save_base(raw=True)
|
||||
|
||||
italian_restaurant.serves_gnocchi = False
|
||||
italian_restaurant.save_base(raw=True)
|
||||
|
||||
place2.name='Derelict lot'
|
||||
place2.save_base(raw=True)
|
||||
|
||||
park.capacity = 50
|
||||
park.save_base(raw=True)
|
||||
|
||||
# No extra parent objects after an update, either.
|
||||
places = list(Place.objects.all())
|
||||
self.assertEqual(places, [place2, place1])
|
||||
self.assertEqual(places[0].name, 'Derelict lot')
|
||||
self.assertEqual(places[1].name, "Guido's All New House of Pasta")
|
||||
|
||||
dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
|
||||
self.assertEqual(dicts, [{
|
||||
'name': u"Guido's All New House of Pasta",
|
||||
'serves_hot_dogs': False,
|
||||
}])
|
||||
|
||||
dicts = list(ItalianRestaurant.objects.values(
|
||||
'name', 'serves_hot_dogs', 'serves_gnocchi'))
|
||||
self.assertEqual(dicts, [{
|
||||
'name': u"Guido's All New House of Pasta",
|
||||
'serves_gnocchi': False,
|
||||
'serves_hot_dogs': False,
|
||||
}])
|
||||
|
||||
dicts = list(ParkingLot.objects.values('name','capacity'))
|
||||
self.assertEqual(dicts, [{
|
||||
'capacity': 50,
|
||||
'name': u'Derelict lot',
|
||||
}])
|
||||
|
||||
# If you try to raw_save a parent attribute onto a child object,
|
||||
# the attribute will be ignored.
|
||||
|
||||
italian_restaurant.name = "Lorenzo's Pasta Hut"
|
||||
italian_restaurant.save_base(raw=True)
|
||||
|
||||
# Note that the name has not changed
|
||||
# - name is an attribute of Place, not ItalianRestaurant
|
||||
dicts = list(ItalianRestaurant.objects.values(
|
||||
'name','serves_hot_dogs','serves_gnocchi'))
|
||||
self.assertEqual(dicts, [{
|
||||
'name': u"Guido's All New House of Pasta",
|
||||
'serves_gnocchi': False,
|
||||
'serves_hot_dogs': False,
|
||||
}])
|
||||
|
||||
def test_issue_7105(self):
|
||||
# Regressions tests for #7105: dates() queries should be able to use
|
||||
# fields from the parent model as easily as the child.
|
||||
obj = Child.objects.create(
|
||||
name='child',
|
||||
created=datetime.datetime(2008, 6, 26, 17, 0, 0))
|
||||
dates = list(Child.objects.dates('created', 'month'))
|
||||
self.assertEqual(dates, [datetime.datetime(2008, 6, 1, 0, 0)])
|
||||
|
||||
def test_issue_7276(self):
|
||||
# Regression test for #7276: calling delete() on a model with
|
||||
# multi-table inheritance should delete the associated rows from any
|
||||
# ancestor tables, as well as any descendent objects.
|
||||
place1 = Place(
|
||||
name="Guido's House of Pasta",
|
||||
address='944 W. Fullerton')
|
||||
place1.save_base(raw=True)
|
||||
restaurant = Restaurant(
|
||||
place_ptr=place1,
|
||||
serves_hot_dogs=True,
|
||||
serves_pizza=False)
|
||||
restaurant.save_base(raw=True)
|
||||
italian_restaurant = ItalianRestaurant(
|
||||
restaurant_ptr=restaurant,
|
||||
serves_gnocchi=True)
|
||||
italian_restaurant.save_base(raw=True)
|
||||
|
||||
ident = ItalianRestaurant.objects.all()[0].id
|
||||
self.assertEqual(Place.objects.get(pk=ident), place1)
|
||||
xx = Restaurant.objects.create(
|
||||
name='a',
|
||||
address='xx',
|
||||
serves_hot_dogs=True,
|
||||
serves_pizza=False)
|
||||
|
||||
# This should delete both Restuarants, plus the related places, plus
|
||||
# the ItalianRestaurant.
|
||||
Restaurant.objects.all().delete()
|
||||
|
||||
self.assertRaises(
|
||||
Place.DoesNotExist,
|
||||
Place.objects.get,
|
||||
pk=ident)
|
||||
self.assertRaises(
|
||||
ItalianRestaurant.DoesNotExist,
|
||||
ItalianRestaurant.objects.get,
|
||||
pk=ident)
|
||||
|
||||
def test_issue_6755(self):
|
||||
"""
|
||||
Regression test for #6755
|
||||
"""
|
||||
r = Restaurant(serves_pizza=False)
|
||||
r.save()
|
||||
self.assertEqual(r.id, r.place_ptr_id)
|
||||
orig_id = r.id
|
||||
r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
|
||||
r.save()
|
||||
self.assertEqual(r.id, orig_id)
|
||||
self.assertEqual(r.id, r.place_ptr_id)
|
||||
|
||||
def test_issue_7488(self):
|
||||
# Regression test for #7488. This looks a little crazy, but it's the
|
||||
# equivalent of what the admin interface has to do for the edit-inline
|
||||
# case.
|
||||
suppliers = Supplier.objects.filter(
|
||||
restaurant=Restaurant(name='xx', address='yy'))
|
||||
suppliers = list(suppliers)
|
||||
self.assertEqual(suppliers, [])
|
||||
|
||||
def test_issue_11764(self):
|
||||
"""
|
||||
Regression test for #11764
|
||||
"""
|
||||
wholesalers = list(Wholesaler.objects.all().select_related())
|
||||
self.assertEqual(wholesalers, [])
|
||||
|
||||
def test_issue_7853(self):
|
||||
"""
|
||||
Regression test for #7853
|
||||
If the parent class has a self-referential link, make sure that any
|
||||
updates to that link via the child update the right table.
|
||||
"""
|
||||
obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
|
||||
obj.delete()
|
||||
|
||||
def test_get_next_previous_by_date(self):
|
||||
"""
|
||||
Regression tests for #8076
|
||||
get_(next/previous)_by_date should work
|
||||
"""
|
||||
c1 = ArticleWithAuthor(
|
||||
headline='ArticleWithAuthor 1',
|
||||
author="Person 1",
|
||||
pub_date=datetime.datetime(2005, 8, 1, 3, 0))
|
||||
c1.save()
|
||||
c2 = ArticleWithAuthor(
|
||||
headline='ArticleWithAuthor 2',
|
||||
author="Person 2",
|
||||
pub_date=datetime.datetime(2005, 8, 1, 10, 0))
|
||||
c2.save()
|
||||
c3 = ArticleWithAuthor(
|
||||
headline='ArticleWithAuthor 3',
|
||||
author="Person 3",
|
||||
pub_date=datetime.datetime(2005, 8, 2))
|
||||
c3.save()
|
||||
|
||||
self.assertEqual(c1.get_next_by_pub_date(), c2)
|
||||
self.assertEqual(c2.get_next_by_pub_date(), c3)
|
||||
self.assertRaises(
|
||||
ArticleWithAuthor.DoesNotExist,
|
||||
c3.get_next_by_pub_date)
|
||||
self.assertEqual(c3.get_previous_by_pub_date(), c2)
|
||||
self.assertEqual(c2.get_previous_by_pub_date(), c1)
|
||||
self.assertRaises(
|
||||
ArticleWithAuthor.DoesNotExist,
|
||||
c1.get_previous_by_pub_date)
|
||||
|
||||
def test_inherited_fields(self):
|
||||
"""
|
||||
Regression test for #8825 and #9390
|
||||
Make sure all inherited fields (esp. m2m fields, in this case) appear
|
||||
on the child class.
|
||||
"""
|
||||
m2mchildren = list(M2MChild.objects.filter(articles__isnull=False))
|
||||
self.assertEqual(m2mchildren, [])
|
||||
|
||||
# Ordering should not include any database column more than once (this
|
||||
# is most likely to ocurr naturally with model inheritance, so we
|
||||
# check it here). Regression test for #9390. This necessarily pokes at
|
||||
# the SQL string for the query, since the duplicate problems are only
|
||||
# apparent at that late stage.
|
||||
qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
|
||||
sql = qs.query.get_compiler(qs.db).as_sql()[0]
|
||||
fragment = sql[sql.find('ORDER BY'):]
|
||||
pos = fragment.find('pub_date')
|
||||
self.assertEqual(fragment.find('pub_date', pos + 1), -1)
|
||||
|
||||
def test_queryset_update_on_parent_model(self):
|
||||
"""
|
||||
Regression test for #10362
|
||||
It is possible to call update() and only change a field in
|
||||
an ancestor model.
|
||||
"""
|
||||
article = ArticleWithAuthor.objects.create(
|
||||
author="fred",
|
||||
headline="Hey there!",
|
||||
pub_date=datetime.datetime(2009, 3, 1, 8, 0, 0))
|
||||
update = ArticleWithAuthor.objects.filter(
|
||||
author="fred").update(headline="Oh, no!")
|
||||
self.assertEqual(update, 1)
|
||||
update = ArticleWithAuthor.objects.filter(
|
||||
pk=article.pk).update(headline="Oh, no!")
|
||||
self.assertEqual(update, 1)
|
||||
|
||||
derivedm1 = DerivedM.objects.create(
|
||||
customPK=44,
|
||||
base_name="b1",
|
||||
derived_name="d1")
|
||||
self.assertEqual(derivedm1.customPK, 44)
|
||||
self.assertEqual(derivedm1.base_name, 'b1')
|
||||
self.assertEqual(derivedm1.derived_name, 'd1')
|
||||
derivedms = list(DerivedM.objects.all())
|
||||
self.assertEqual(derivedms, [derivedm1])
|
||||
|
||||
def test_use_explicit_o2o_to_parent_as_pk(self):
|
||||
"""
|
||||
Regression tests for #10406
|
||||
If there's a one-to-one link between a child model and the parent and
|
||||
no explicit pk declared, we can use the one-to-one link as the pk on
|
||||
the child.
|
||||
"""
|
||||
self.assertEqual(ParkingLot2._meta.pk.name, "parent")
|
||||
|
||||
# However, the connector from child to parent need not be the pk on
|
||||
# the child at all.
|
||||
self.assertEqual(ParkingLot3._meta.pk.name, "primary_key")
|
||||
# the child->parent link
|
||||
self.assertEqual(
|
||||
ParkingLot3._meta.get_ancestor_link(Place).name,
|
||||
"parent")
|
||||
|
||||
def test_all_fields_from_abstract_base_class(self):
|
||||
"""
|
||||
Regression tests for #7588
|
||||
"""
|
||||
# All fields from an ABC, including those inherited non-abstractly
|
||||
# should be available on child classes (#7588). Creating this instance
|
||||
# should work without error.
|
||||
QualityControl.objects.create(
|
||||
headline="Problems in Django",
|
||||
pub_date=datetime.datetime.now(),
|
||||
quality=10,
|
||||
assignee="adrian")
|
||||
|
||||
def test_abstract_base_class_m2m_relation_inheritance(self):
|
||||
# Check that many-to-many relations defined on an abstract base class
|
||||
# are correctly inherited (and created) on the child class.
|
||||
p1 = Person.objects.create(name='Alice')
|
||||
p2 = Person.objects.create(name='Bob')
|
||||
p3 = Person.objects.create(name='Carol')
|
||||
p4 = Person.objects.create(name='Dave')
|
||||
|
||||
birthday = BirthdayParty.objects.create(
|
||||
name='Birthday party for Alice')
|
||||
birthday.attendees = [p1, p3]
|
||||
|
||||
bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
|
||||
bachelor.attendees = [p2, p4]
|
||||
|
||||
parties = list(p1.birthdayparty_set.all())
|
||||
self.assertEqual(parties, [birthday])
|
||||
|
||||
parties = list(p1.bachelorparty_set.all())
|
||||
self.assertEqual(parties, [])
|
||||
|
||||
parties = list(p2.bachelorparty_set.all())
|
||||
self.assertEqual(parties, [bachelor])
|
||||
|
||||
# Check that a subclass of a subclass of an abstract model doesn't get
|
||||
# it's own accessor.
|
||||
self.assertFalse(hasattr(p2, 'messybachelorparty_set'))
|
||||
|
||||
# ... but it does inherit the m2m from it's parent
|
||||
messy = MessyBachelorParty.objects.create(
|
||||
name='Bachelor party for Dave')
|
||||
messy.attendees = [p4]
|
||||
messy_parent = messy.bachelorparty_ptr
|
||||
|
||||
parties = list(p4.bachelorparty_set.all())
|
||||
self.assertEqual(parties, [bachelor, messy_parent])
|
Loading…
Reference in New Issue