diff options
| author | Brian Rosner <brosner@gmail.com> | 2008-06-30 15:38:16 +0000 |
|---|---|---|
| committer | Brian Rosner <brosner@gmail.com> | 2008-06-30 15:38:16 +0000 |
| commit | 829fd5a9670a581309797f56bfc7e5140550e873 (patch) | |
| tree | 6efe30b93fd5fc6564392f1dbaaf04c95a4b6bc2 /tests | |
| parent | c349ba4cfc2d137da393bddbda6e78fdb98c9c81 (diff) | |
newforms-admin: Merged from trunk up to [7808]. Fixed #7519, #7573
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
17 files changed, 481 insertions, 68 deletions
diff --git a/tests/regressiontests/extra_regress/__init__.py b/tests/regressiontests/extra_regress/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/extra_regress/__init__.py diff --git a/tests/regressiontests/extra_regress/models.py b/tests/regressiontests/extra_regress/models.py new file mode 100644 index 0000000000..3bcc3075ec --- /dev/null +++ b/tests/regressiontests/extra_regress/models.py @@ -0,0 +1,55 @@ +import copy + +from django.db import models +from django.db.models.query import Q + + +class RevisionableModel(models.Model): + base = models.ForeignKey('self', null=True) + title = models.CharField(blank=True, max_length=255) + + def __unicode__(self): + return u"%s (%s, %s)" % (self.title, self.id, self.base.id) + + def save(self): + super(RevisionableModel, self).save() + if not self.base: + self.base = self + super(RevisionableModel, self).save() + + def new_revision(self): + new_revision = copy.copy(self) + new_revision.pk = None + return new_revision + +__test__ = {"API_TESTS": """ +### Regression tests for #7314 and #7372 + +>>> rm = RevisionableModel.objects.create(title='First Revision') +>>> rm.pk, rm.base.pk +(1, 1) + +>>> rm2 = rm.new_revision() +>>> rm2.title = "Second Revision" +>>> rm2.save() +>>> print u"%s of %s" % (rm2.title, rm2.base.title) +Second Revision of First Revision + +>>> rm2.pk, rm2.base.pk +(2, 1) + +Queryset to match most recent revision: +>>> qs = RevisionableModel.objects.extra(where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s AS rev GROUP BY rev.base_id)" % {'table': RevisionableModel._meta.db_table,}],) +>>> qs +[<RevisionableModel: Second Revision (2, 1)>] + +Queryset to search for string in title: +>>> qs2 = RevisionableModel.objects.filter(title__contains="Revision") +>>> qs2 +[<RevisionableModel: First Revision (1, 1)>, <RevisionableModel: Second Revision (2, 1)>] + +Following queryset should return the most recent revision: +>>> qs & qs2 +[<RevisionableModel: Second Revision (2, 1)>] + +"""} diff --git a/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json b/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json new file mode 100644 index 0000000000..e655fbbf3f --- /dev/null +++ b/tests/regressiontests/fixtures_regress/fixtures/big-fixture.json @@ -0,0 +1,83 @@ +[ + { + "pk": 6, + "model": "fixtures_regress.channel", + "fields": { + "name": "Business" + } + }, + + { + "pk": 1, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 1", + "channels": [6] + } + }, + { + "pk": 2, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 2", + "channels": [6] + } + }, + { + "pk": 3, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 3", + "channels": [6] + } + }, + { + "pk": 4, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 4", + "channels": [6] + } + }, + + { + "pk": 5, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 5", + "channels": [6] + } + }, + { + "pk": 6, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 6", + "channels": [6] + } + }, + { + "pk": 7, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 7", + "channels": [6] + } + }, + { + "pk": 8, + "model": "fixtures_regress.article", + "fields": { + "title": "Article Title 8", + "channels": [6] + } + }, + { + "pk": 9, + "model": "fixtures_regress.article", + "fields": { + "title": "Yet Another Article", + "channels": [6] + } + } +]
\ No newline at end of file diff --git a/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json b/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json new file mode 100644 index 0000000000..00c482b3dd --- /dev/null +++ b/tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json @@ -0,0 +1,4 @@ +[ + {"pk": 1, "model": "fixtures_regress.parent", "fields": {"name": "fred"}}, + {"pk": 1, "model": "fixtures_regress.child", "fields": {"data": "apple"}} +] diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index 59fc167d50..2c048dc0b8 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -20,7 +20,7 @@ class Plant(models.Model): class Stuff(models.Model): name = models.CharField(max_length=20, null=True) owner = models.ForeignKey(User, null=True) - + def __unicode__(self): # Oracle doesn't distinguish between None and the empty string. # This hack makes the test case pass using Oracle. @@ -38,13 +38,29 @@ class Absolute(models.Model): super(Absolute, self).__init__(*args, **kwargs) Absolute.load_count += 1 +class Parent(models.Model): + name = models.CharField(max_length=10) + +class Child(Parent): + data = models.CharField(max_length=10) + +# Models to regresison check #7572 +class Channel(models.Model): + name = models.CharField(max_length=255) + +class Article(models.Model): + title = models.CharField(max_length=255) + channels = models.ManyToManyField(Channel) + + class Meta: + ordering = ('id',) __test__ = {'API_TESTS':""" >>> from django.core import management # Load a fixture that uses PK=1 >>> management.call_command('loaddata', 'sequence', verbosity=0) - + # Create a new animal. Without a sequence reset, this new object # will take a PK of 1 (on Postgres), and the save will fail. # This is a regression test for ticket #3790. @@ -61,9 +77,9 @@ __test__ = {'API_TESTS':""" [<Stuff: None is owned by None>] ############################################### -# Regression test for ticket #6436 -- +# Regression test for ticket #6436 -- # os.path.join will throw away the initial parts of a path if it encounters -# an absolute path. This means that if a fixture is specified as an absolute path, +# an absolute path. This means that if a fixture is specified as an absolute path, # we need to make sure we don't discover the absolute path in every fixture directory. >>> load_absolute_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'absolute.json') @@ -94,4 +110,28 @@ No fixture data found for 'bad_fixture2'. (File format may be invalid.) >>> sys.stderr = savestderr +############################################### +# Test for ticket #7565 -- PostgreSQL sequence resetting checks shouldn't +# ascend to parent models when inheritance is used (since they are treated +# individually). + +>>> management.call_command('loaddata', 'model-inheritance.json', verbosity=0) + +############################################### +# Test for ticket #7572 -- MySQL has a problem if the same connection is +# used to create tables, load data, and then query over that data. +# To compensate, we close the connection after running loaddata. +# This ensures that a new connection is opened when test queries are issued. + +>>> management.call_command('loaddata', 'big-fixture.json', verbosity=0) + +>>> articles = Article.objects.exclude(id=9) +>>> articles.values_list('id', flat=True) +[1, 2, 3, 4, 5, 6, 7, 8] + +# Just for good measure, run the same query again. Under the influence of +# ticket #7572, this will give a different result to the previous call. +>>> articles.values_list('id', flat=True) +[1, 2, 3, 4, 5, 6, 7, 8] + """} diff --git a/tests/regressiontests/forms/error_messages.py b/tests/regressiontests/forms/error_messages.py index 9f972f5b90..381282f121 100644 --- a/tests/regressiontests/forms/error_messages.py +++ b/tests/regressiontests/forms/error_messages.py @@ -237,7 +237,7 @@ ValidationError: [u'REQUIRED'] Traceback (most recent call last): ... ValidationError: [u'INVALID'] ->>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') +>>> f.clean('http://www.broken.djangoproject.com') Traceback (most recent call last): ... ValidationError: [u'INVALID LINK'] diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index f3b6a96a1e..c9f3efdbda 100644 --- a/tests/regressiontests/forms/fields.py +++ b/tests/regressiontests/forms/fields.py @@ -887,7 +887,7 @@ u'http://www.google.com' Traceback (most recent call last): ... ValidationError: [u'Enter a valid URL.'] ->>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') # bad domain +>>> f.clean('http://www.broken.djangoproject.com') # bad domain Traceback (most recent call last): ... ValidationError: [u'This URL appears to be a broken link.'] @@ -937,18 +937,24 @@ ValidationError: [u'This field is required.'] >>> f.clean(True) True >>> f.clean(False) -False +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] >>> f.clean(1) True >>> f.clean(0) -False +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] >>> f.clean('Django rocks') True >>> f.clean('True') True >>> f.clean('False') -False +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] >>> f = BooleanField(required=False) >>> f.clean('') diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py index 4e49df1555..429bdd7558 100644 --- a/tests/regressiontests/many_to_one_regress/models.py +++ b/tests/regressiontests/many_to_one_regress/models.py @@ -28,6 +28,24 @@ class Child(models.Model): parent = models.ForeignKey(Parent) +# Multiple paths to the same model (#7110, #7125) +class Category(models.Model): + name = models.CharField(max_length=20) + + def __unicode__(self): + return self.name + +class Record(models.Model): + category = models.ForeignKey(Category) + +class Relation(models.Model): + left = models.ForeignKey(Record, related_name='left_set') + right = models.ForeignKey(Record, related_name='right_set') + + def __unicode__(self): + return u"%s - %s" % (self.left.category.name, self.right.category.name) + + __test__ = {'API_TESTS':""" >>> Third.objects.create(id='3', name='An example') <Third: Third object> @@ -73,4 +91,26 @@ Traceback (most recent call last): ... ValueError: Cannot assign "<First: First object>": "Child.parent" must be a "Parent" instance. +# Test of multiple ForeignKeys to the same model (bug #7125) + +>>> c1 = Category.objects.create(name='First') +>>> c2 = Category.objects.create(name='Second') +>>> c3 = Category.objects.create(name='Third') +>>> r1 = Record.objects.create(category=c1) +>>> r2 = Record.objects.create(category=c1) +>>> r3 = Record.objects.create(category=c2) +>>> r4 = Record.objects.create(category=c2) +>>> r5 = Record.objects.create(category=c3) +>>> r = Relation.objects.create(left=r1, right=r2) +>>> r = Relation.objects.create(left=r3, right=r4) +>>> r = Relation.objects.create(left=r1, right=r3) +>>> r = Relation.objects.create(left=r5, right=r2) +>>> r = Relation.objects.create(left=r3, right=r2) + +>>> Relation.objects.filter(left__category__name__in=['First'], right__category__name__in=['Second']) +[<Relation: First - Second>] + +>>> Category.objects.filter(record__left_set__right__category__name='Second').order_by('name') +[<Category: First>, <Category: Second>] + """} diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py index e279a0669f..c2ba9ee008 100644 --- a/tests/regressiontests/model_fields/tests.py +++ b/tests/regressiontests/model_fields/tests.py @@ -15,4 +15,21 @@ Decimal("3.14") Traceback (most recent call last): ... ValidationError: [u'This value must be a decimal number.'] + +>>> f = DecimalField(max_digits=5, decimal_places=1) +>>> x = f.to_python(2) +>>> y = f.to_python('2.6') + +>>> f.get_db_prep_save(x) +u'2.0' +>>> f.get_db_prep_save(y) +u'2.6' +>>> f.get_db_prep_save(None) +>>> f.get_db_prep_lookup('exact', x) +[u'2.0'] +>>> f.get_db_prep_lookup('exact', y) +[u'2.6'] +>>> f.get_db_prep_lookup('exact', None) +[None] + """ diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py index 33e2e0e4f6..24d6186150 100644 --- a/tests/regressiontests/model_inheritance_regress/models.py +++ b/tests/regressiontests/model_inheritance_regress/models.py @@ -131,4 +131,26 @@ __test__ = {'API_TESTS':""" >>> 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. + """} diff --git a/tests/regressiontests/model_inheritance_select_related/__init__.py b/tests/regressiontests/model_inheritance_select_related/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/model_inheritance_select_related/__init__.py diff --git a/tests/regressiontests/model_inheritance_select_related/models.py b/tests/regressiontests/model_inheritance_select_related/models.py new file mode 100644 index 0000000000..a97ecaadea --- /dev/null +++ b/tests/regressiontests/model_inheritance_select_related/models.py @@ -0,0 +1,47 @@ +""" +Regression tests for the interaction between model inheritance and +select_related(). +""" + +from django.db import models + +class Place(models.Model): + name = models.CharField(max_length=50) + + class Meta: + ordering = ('name',) + + def __unicode__(self): + return u"%s the place" % self.name + +class Restaurant(Place): + serves_sushi = models.BooleanField() + serves_steak = models.BooleanField() + + def __unicode__(self): + return u"%s the restaurant" % self.name + +class Person(models.Model): + name = models.CharField(max_length=50) + favorite_restaurant = models.ForeignKey(Restaurant) + + def __unicode__(self): + return self.name + +__test__ = {'API_TESTS':""" +Regression test for #7246 + +>>> r1 = Restaurant.objects.create(name="Nobu", serves_sushi=True, serves_steak=False) +>>> r2 = Restaurant.objects.create(name="Craft", serves_sushi=False, serves_steak=True) +>>> p1 = Person.objects.create(name="John", favorite_restaurant=r1) +>>> p2 = Person.objects.create(name="Jane", favorite_restaurant=r2) + +>>> Person.objects.order_by('name').select_related() +[<Person: Jane>, <Person: John>] + +>>> jane = Person.objects.order_by('name').select_related('favorite_restaurant')[0] +>>> jane.favorite_restaurant.name +u'Craft' + +"""} + diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index c02ad73998..566411e513 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -3,13 +3,15 @@ Various complex queries that have been problematic in the past. """ import datetime +import pickle from django.db import models from django.db.models.query import Q class Tag(models.Model): name = models.CharField(max_length=10) - parent = models.ForeignKey('self', blank=True, null=True) + parent = models.ForeignKey('self', blank=True, null=True, + related_name='children') def __unicode__(self): return self.name @@ -24,6 +26,14 @@ class Note(models.Model): def __unicode__(self): return self.note +class Annotation(models.Model): + name = models.CharField(max_length=10) + tag = models.ForeignKey(Tag) + notes = models.ManyToManyField(Note) + + def __unicode__(self): + return self.name + class ExtraInfo(models.Model): info = models.CharField(max_length=100) note = models.ForeignKey(Note) @@ -162,85 +172,67 @@ class Child(models.Model): person = models.OneToOneField(Member, primary_key=True) parent = models.ForeignKey(Member, related_name="children") +# Custom primary keys interfered with ordering in the past. +class CustomPk(models.Model): + name = models.CharField(max_length=10, primary_key=True) + extra = models.CharField(max_length=10) + + class Meta: + ordering = ['name', 'extra'] + +class Related(models.Model): + custom = models.ForeignKey(CustomPk) + __test__ = {'API_TESTS':""" ->>> t1 = Tag(name='t1') ->>> t1.save() ->>> t2 = Tag(name='t2', parent=t1) ->>> t2.save() ->>> t3 = Tag(name='t3', parent=t1) ->>> t3.save() ->>> t4 = Tag(name='t4', parent=t3) ->>> t4.save() ->>> t5 = Tag(name='t5', parent=t3) ->>> t5.save() +>>> t1 = Tag.objects.create(name='t1') +>>> t2 = Tag.objects.create(name='t2', parent=t1) +>>> t3 = Tag.objects.create(name='t3', parent=t1) +>>> t4 = Tag.objects.create(name='t4', parent=t3) +>>> t5 = Tag.objects.create(name='t5', parent=t3) ->>> n1 = Note(note='n1', misc='foo') ->>> n1.save() ->>> n2 = Note(note='n2', misc='bar') ->>> n2.save() ->>> n3 = Note(note='n3', misc='foo') ->>> n3.save() +>>> n1 = Note.objects.create(note='n1', misc='foo') +>>> n2 = Note.objects.create(note='n2', misc='bar') +>>> n3 = Note.objects.create(note='n3', misc='foo') Create these out of order so that sorting by 'id' will be different to sorting by 'info'. Helps detect some problems later. ->>> e2 = ExtraInfo(info='e2', note=n2) ->>> e2.save() ->>> e1 = ExtraInfo(info='e1', note=n1) ->>> e1.save() +>>> e2 = ExtraInfo.objects.create(info='e2', note=n2) +>>> e1 = ExtraInfo.objects.create(info='e1', note=n1) ->>> a1 = Author(name='a1', num=1001, extra=e1) ->>> a1.save() ->>> a2 = Author(name='a2', num=2002, extra=e1) ->>> a2.save() ->>> a3 = Author(name='a3', num=3003, extra=e2) ->>> a3.save() ->>> a4 = Author(name='a4', num=4004, extra=e2) ->>> a4.save() +>>> a1 = Author.objects.create(name='a1', num=1001, extra=e1) +>>> a2 = Author.objects.create(name='a2', num=2002, extra=e1) +>>> a3 = Author.objects.create(name='a3', num=3003, extra=e2) +>>> a4 = Author.objects.create(name='a4', num=4004, extra=e2) >>> time1 = datetime.datetime(2007, 12, 19, 22, 25, 0) >>> time2 = datetime.datetime(2007, 12, 19, 21, 0, 0) >>> time3 = datetime.datetime(2007, 12, 20, 22, 25, 0) >>> time4 = datetime.datetime(2007, 12, 20, 21, 0, 0) ->>> i1 = Item(name='one', created=time1, modified=time1, creator=a1, note=n3) ->>> i1.save() +>>> i1 = Item.objects.create(name='one', created=time1, modified=time1, creator=a1, note=n3) >>> i1.tags = [t1, t2] ->>> i2 = Item(name='two', created=time2, creator=a2, note=n2) ->>> i2.save() +>>> i2 = Item.objects.create(name='two', created=time2, creator=a2, note=n2) >>> i2.tags = [t1, t3] ->>> i3 = Item(name='three', created=time3, creator=a2, note=n3) ->>> i3.save() ->>> i4 = Item(name='four', created=time4, creator=a4, note=n3) ->>> i4.save() +>>> i3 = Item.objects.create(name='three', created=time3, creator=a2, note=n3) +>>> i4 = Item.objects.create(name='four', created=time4, creator=a4, note=n3) >>> i4.tags = [t4] ->>> r1 = Report(name='r1', creator=a1) ->>> r1.save() ->>> r2 = Report(name='r2', creator=a3) ->>> r2.save() ->>> r3 = Report(name='r3') ->>> r3.save() +>>> r1 = Report.objects.create(name='r1', creator=a1) +>>> r2 = Report.objects.create(name='r2', creator=a3) +>>> r3 = Report.objects.create(name='r3') Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering will be rank3, rank2, rank1. ->>> rank1 = Ranking(rank=2, author=a2) ->>> rank1.save() ->>> rank2 = Ranking(rank=1, author=a3) ->>> rank2.save() ->>> rank3 = Ranking(rank=3, author=a1) ->>> rank3.save() +>>> rank1 = Ranking.objects.create(rank=2, author=a2) +>>> rank2 = Ranking.objects.create(rank=1, author=a3) +>>> rank3 = Ranking.objects.create(rank=3, author=a1) ->>> c1 = Cover(title="first", item=i4) ->>> c1.save() ->>> c2 = Cover(title="second", item=i2) ->>> c2.save() +>>> c1 = Cover.objects.create(title="first", item=i4) +>>> c2 = Cover.objects.create(title="second", item=i2) ->>> n1 = Number(num=4) ->>> n1.save() ->>> n2 = Number(num=8) ->>> n2.save() ->>> n3 = Number(num=12) ->>> n3.save() +>>> num1 = Number.objects.create(num=4) +>>> num2 = Number.objects.create(num=8) +>>> num3 = Number.objects.create(num=12) Bug #1050 >>> Item.objects.filter(tags__isnull=True) @@ -346,6 +338,10 @@ Bug #1878, #2939 4 >>> xx.delete() +Bug #7323 +>>> Item.objects.values('creator', 'name').count() +4 + Bug #2253 >>> q1 = Item.objects.order_by('name') >>> q2 = Item.objects.filter(id=i1.id) @@ -387,6 +383,10 @@ Bug #4510 >>> Author.objects.filter(report__name='r1') [<Author: a1>] +Bug #7378 +>>> a1.report_set.all() +[<Report: r1>] + Bug #5324, #6704 >>> Item.objects.filter(tags__name='t4') [<Item: four>] @@ -791,5 +791,19 @@ Empty querysets can be merged with others. >>> Note.objects.all() & Note.objects.none() [] +Bug #7204, #7506 -- make sure querysets with related fields can be pickled. If +this doesn't crash, it's a Good Thing. +>>> out = pickle.dumps(Item.objects.all()) + +Bug #7277 +>>> ann1 = Annotation.objects.create(name='a1', tag=t1) +>>> ann1.notes.add(n1) +>>> n1.annotation_set.filter(Q(tag=t5) | Q(tag__children=t5) | Q(tag__children__children=t5)) +[<Annotation: a1>] + +Bug #7371 +>>> Related.objects.order_by('custom') +[] + """} diff --git a/tests/regressiontests/select_related_regress/__init__.py b/tests/regressiontests/select_related_regress/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/select_related_regress/__init__.py diff --git a/tests/regressiontests/select_related_regress/models.py b/tests/regressiontests/select_related_regress/models.py new file mode 100644 index 0000000000..1688053e2d --- /dev/null +++ b/tests/regressiontests/select_related_regress/models.py @@ -0,0 +1,60 @@ +from django.db import models + +class Building(models.Model): + name = models.CharField(max_length=10) + + def __unicode__(self): + return u"Building: %s" % self.name + +class Device(models.Model): + building = models.ForeignKey('Building') + name = models.CharField(max_length=10) + + def __unicode__(self): + return u"device '%s' in building %s" % (self.name, self.building) + +class Port(models.Model): + device = models.ForeignKey('Device') + number = models.CharField(max_length=10) + + def __unicode__(self): + return u"%s/%s" % (self.device.name, self.number) + +class Connection(models.Model): + start = models.ForeignKey(Port, related_name='connection_start', + unique=True) + end = models.ForeignKey(Port, related_name='connection_end', unique=True) + + def __unicode__(self): + return u"%s to %s" % (self.start, self.end) + +__test__ = {'API_TESTS': """ +Regression test for bug #7110. When using select_related(), we must query the +Device and Building tables using two different aliases (each) in order to +differentiate the start and end Connection fields. The net result is that both +the "connections = ..." queries here should give the same results. + +>>> b=Building.objects.create(name='101') +>>> dev1=Device.objects.create(name="router", building=b) +>>> dev2=Device.objects.create(name="switch", building=b) +>>> dev3=Device.objects.create(name="server", building=b) +>>> port1=Port.objects.create(number='4',device=dev1) +>>> port2=Port.objects.create(number='7',device=dev2) +>>> port3=Port.objects.create(number='1',device=dev3) +>>> c1=Connection.objects.create(start=port1, end=port2) +>>> c2=Connection.objects.create(start=port2, end=port3) + +>>> connections=Connection.objects.filter(start__device__building=b, end__device__building=b).order_by('id') +>>> [(c.id, unicode(c.start), unicode(c.end)) for c in connections] +[(1, u'router/4', u'switch/7'), (2, u'switch/7', u'server/1')] + +>>> connections=Connection.objects.filter(start__device__building=b, end__device__building=b).select_related().order_by('id') +>>> [(c.id, unicode(c.start), unicode(c.end)) for c in connections] +[(1, u'router/4', u'switch/7'), (2, u'switch/7', u'server/1')] + +# This final query should only join seven tables (port, device and building +# twice each, plus connection once). +>>> connections.query.count_active_tables() +7 + +"""} diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py index 1bdb2d4452..39e7955592 100644 --- a/tests/regressiontests/string_lookup/models.py +++ b/tests/regressiontests/string_lookup/models.py @@ -97,6 +97,12 @@ __test__ = {'API_TESTS': ur""" >>> Article.objects.get(text__exact='The quick brown fox jumps over the lazy dog.') <Article: Article Test> +# Regression tests for #2170: test case sensitiveness +>>> Article.objects.filter(text__exact='tHe qUick bRown fOx jUmps over tHe lazy dog.') +[] +>>> Article.objects.filter(text__iexact='tHe qUick bRown fOx jUmps over tHe lazy dog.') +[<Article: Article Test>] + >>> Article.objects.get(text__contains='quick brown fox') <Article: Article Test> diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py index a204ec3e72..37e81668b6 100644 --- a/tests/regressiontests/test_client_regress/models.py +++ b/tests/regressiontests/test_client_regress/models.py @@ -318,3 +318,22 @@ class ExceptionTests(TestCase): self.client.get("/test_client_regress/staff_only/") except SuspiciousOperation: self.fail("Staff should be able to visit this page") + +# We need two different tests to check URLconf subsitution - one to check +# it was changed, and another one (without self.urls) to check it was reverted on +# teardown. This pair of tests relies upon the alphabetical ordering of test execution. +class UrlconfSubstitutionTests(TestCase): + urls = 'regressiontests.test_client_regress.urls' + + def test_urlconf_was_changed(self): + "TestCase can enforce a custom URLConf on a per-test basis" + url = reverse('arg_view', args=['somename']) + self.assertEquals(url, '/arg_view/somename/') + +# This test needs to run *after* UrlconfSubstitutionTests; the zz prefix in the +# name is to ensure alphabetical ordering. +class zzUrlconfSubstitutionTests(TestCase): + def test_urlconf_was_reverted(self): + "URLconf is reverted to original value after modification in a TestCase" + url = reverse('arg_view', args=['somename']) + self.assertEquals(url, '/test_client_regress/arg_view/somename/') |
