diff options
| author | Joseph Kocherhans <joseph@jkocherhans.com> | 2006-11-06 21:11:49 +0000 |
|---|---|---|
| committer | Joseph Kocherhans <joseph@jkocherhans.com> | 2006-11-06 21:11:49 +0000 |
| commit | dc59c670b8cbe055ff3565f8d5a2f600c5ab1ba8 (patch) | |
| tree | 84a2d1a3e729a813cf692ebbe7404ba8e5687d22 /tests | |
| parent | bf629e5a4d1a51f938c84d35d768830158ad5ebd (diff) | |
Merged to [3519]
git-svn-id: http://code.djangoproject.com/svn/django/branches/generic-auth@4024 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/modeltests/basic/models.py | 5 | ||||
| -rw-r--r-- | tests/modeltests/invalid_models/models.py | 118 | ||||
| -rw-r--r-- | tests/modeltests/lookup/models.py | 4 | ||||
| -rw-r--r-- | tests/modeltests/m2m_and_m2o/models.py | 15 | ||||
| -rw-r--r-- | tests/modeltests/m2m_recursive/models.py | 2 | ||||
| -rw-r--r-- | tests/modeltests/many_to_many/models.py | 23 | ||||
| -rw-r--r-- | tests/modeltests/many_to_one/models.py | 36 | ||||
| -rw-r--r-- | tests/modeltests/one_to_one/models.py | 24 | ||||
| -rw-r--r-- | tests/modeltests/serializers/__init__.py | 0 | ||||
| -rw-r--r-- | tests/modeltests/serializers/models.py | 121 | ||||
| -rw-r--r-- | tests/othertests/defaultfilters.py | 30 | ||||
| -rw-r--r-- | tests/othertests/markup.py | 4 | ||||
| -rw-r--r-- | tests/othertests/templates.py | 39 | ||||
| -rw-r--r-- | tests/othertests/urlpatterns_reverse.py | 47 | ||||
| -rw-r--r-- | tests/regressiontests/many_to_one_regress/__init__.py | 0 | ||||
| -rw-r--r-- | tests/regressiontests/many_to_one_regress/models.py | 13 | ||||
| -rwxr-xr-x | tests/runtests.py | 3 |
17 files changed, 414 insertions, 70 deletions
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py index a4de0f9a81..78d943eb97 100644 --- a/tests/modeltests/basic/models.py +++ b/tests/modeltests/basic/models.py @@ -347,4 +347,9 @@ API_TESTS += """ >>> a101 = Article.objects.get(pk=101) >>> a101.headline 'Article 101' + +# You can create saved objects in a single step +>>> a10 = Article.objects.create(headline="Article 10", pub_date=datetime(2005, 7, 31, 12, 30, 45)) +>>> Article.objects.get(headline="Article 10") +<Article: Article 10> """ diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py index 1720dd96d3..eb305b4e92 100644 --- a/tests/modeltests/invalid_models/models.py +++ b/tests/modeltests/invalid_models/models.py @@ -17,17 +17,19 @@ class FieldErrors(models.Model): class Target(models.Model): tgt_safe = models.CharField(maxlength=10) + clash1 = models.CharField(maxlength=10) + clash2 = models.CharField(maxlength=10) clash1_set = models.CharField(maxlength=10) class Clash1(models.Model): - src_safe = models.CharField(maxlength=10) + src_safe = models.CharField(maxlength=10, core=True) foreign = models.ForeignKey(Target) m2m = models.ManyToManyField(Target) class Clash2(models.Model): - src_safe = models.CharField(maxlength=10) + src_safe = models.CharField(maxlength=10, core=True) foreign_1 = models.ForeignKey(Target, related_name='id') foreign_2 = models.ForeignKey(Target, related_name='src_safe') @@ -36,6 +38,7 @@ class Clash2(models.Model): m2m_2 = models.ManyToManyField(Target, related_name='src_safe') class Target2(models.Model): + clash3 = models.CharField(maxlength=10) foreign_tgt = models.ForeignKey(Target) clashforeign_set = models.ForeignKey(Target) @@ -43,6 +46,8 @@ class Target2(models.Model): clashm2m_set = models.ManyToManyField(Target) class Clash3(models.Model): + src_safe = models.CharField(maxlength=10, core=True) + foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt') foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt') @@ -56,7 +61,8 @@ class ClashM2M(models.Model): m2m = models.ManyToManyField(Target2) class SelfClashForeign(models.Model): - src_safe = models.CharField(maxlength=10) + src_safe = models.CharField(maxlength=10, core=True) + selfclashforeign = models.CharField(maxlength=10) selfclashforeign_set = models.ForeignKey("SelfClashForeign") foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id') @@ -64,11 +70,14 @@ class SelfClashForeign(models.Model): class SelfClashM2M(models.Model): src_safe = models.CharField(maxlength=10) + selfclashm2m = models.CharField(maxlength=10) selfclashm2m_set = models.ManyToManyField("SelfClashM2M") m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id') m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe') + + error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute. @@ -78,42 +87,69 @@ invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tup invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. invalid_models.fielderrors: "index": "db_index" should be either None, True or False. -invalid_models.clash1: 'foreign' accessor name 'Target.clash1_set' clashes with another field. Add a related_name argument to the definition for 'foreign'. -invalid_models.clash1: 'foreign' accessor name 'Target.clash1_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign'. -invalid_models.clash1: 'm2m' m2m accessor name 'Target.clash1_set' clashes with another field. Add a related_name argument to the definition for 'm2m'. -invalid_models.clash1: 'm2m' m2m accessor name 'Target.clash1_set' clashes with another related field. Add a related_name argument to the definition for 'm2m'. -invalid_models.clash2: 'foreign_1' accessor name 'Target.id' clashes with another field. Add a related_name argument to the definition for 'foreign_1'. -invalid_models.clash2: 'foreign_1' accessor name 'Target.id' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_1'. -invalid_models.clash2: 'foreign_2' accessor name 'Target.src_safe' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_2'. -invalid_models.clash2: 'm2m_1' m2m accessor name 'Target.id' clashes with another field. Add a related_name argument to the definition for 'm2m_1'. -invalid_models.clash2: 'm2m_1' m2m accessor name 'Target.id' clashes with another related field. Add a related_name argument to the definition for 'm2m_1'. -invalid_models.clash2: 'm2m_2' m2m accessor name 'Target.src_safe' clashes with another related field. Add a related_name argument to the definition for 'm2m_2'. -invalid_models.clash3: 'foreign_1' accessor name 'Target2.foreign_tgt' clashes with another field. Add a related_name argument to the definition for 'foreign_1'. -invalid_models.clash3: 'foreign_1' accessor name 'Target2.foreign_tgt' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_1'. -invalid_models.clash3: 'foreign_2' accessor name 'Target2.m2m_tgt' clashes with a m2m field. Add a related_name argument to the definition for 'foreign_2'. -invalid_models.clash3: 'foreign_2' accessor name 'Target2.m2m_tgt' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_2'. -invalid_models.clash3: 'm2m_1' m2m accessor name 'Target2.foreign_tgt' clashes with another field. Add a related_name argument to the definition for 'm2m_1'. -invalid_models.clash3: 'm2m_1' m2m accessor name 'Target2.foreign_tgt' clashes with another related field. Add a related_name argument to the definition for 'm2m_1'. -invalid_models.clash3: 'm2m_2' m2m accessor name 'Target2.m2m_tgt' clashes with a m2m field. Add a related_name argument to the definition for 'm2m_2'. -invalid_models.clash3: 'm2m_2' m2m accessor name 'Target2.m2m_tgt' clashes with another related field. Add a related_name argument to the definition for 'm2m_2'. -invalid_models.clashforeign: 'foreign' accessor name 'Target2.clashforeign_set' clashes with another field. Add a related_name argument to the definition for 'foreign'. -invalid_models.clashm2m: 'm2m' m2m accessor name 'Target2.clashm2m_set' clashes with a m2m field. Add a related_name argument to the definition for 'm2m'. -invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_tgt'. -invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'foreign_tgt'. -invalid_models.target2: 'foreign_tgt' accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'foreign_tgt'. -invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashforeign_set'. -invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashforeign_set'. -invalid_models.target2: 'clashforeign_set' accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashforeign_set'. -invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'm2m_tgt'. -invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'm2m_tgt'. -invalid_models.target2: 'm2m_tgt' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'm2m_tgt'. -invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with a related m2m field. Add a related_name argument to the definition for 'clashm2m_set'. -invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashm2m_set'. -invalid_models.target2: 'clashm2m_set' m2m accessor name 'Target.target2_set' clashes with another related field. Add a related_name argument to the definition for 'clashm2m_set'. -invalid_models.selfclashforeign: 'selfclashforeign_set' accessor name 'SelfClashForeign.selfclashforeign_set' clashes with another field. Add a related_name argument to the definition for 'selfclashforeign_set'. -invalid_models.selfclashforeign: 'foreign_1' accessor name 'SelfClashForeign.id' clashes with another field. Add a related_name argument to the definition for 'foreign_1'. -invalid_models.selfclashforeign: 'foreign_2' accessor name 'SelfClashForeign.src_safe' clashes with another field. Add a related_name argument to the definition for 'foreign_2'. -invalid_models.selfclashm2m: 'selfclashm2m_set' m2m accessor name 'SelfClashM2M.selfclashm2m_set' clashes with a m2m field. Add a related_name argument to the definition for 'selfclashm2m_set'. -invalid_models.selfclashm2m: 'm2m_1' m2m accessor name 'SelfClashM2M.id' clashes with another field. Add a related_name argument to the definition for 'm2m_1'. -invalid_models.selfclashm2m: 'm2m_2' m2m accessor name 'SelfClashM2M.src_safe' clashes with another field. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'. +invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'. +invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'. +invalid_models.clash1: Accessor for m2m field 'm2m' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'. +invalid_models.clash1: Accessor for m2m field 'm2m' clashes with related field 'Target.clash1_set'. Add a related_name argument to the definition for 'm2m'. +invalid_models.clash1: Reverse query name for m2m field 'm2m' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'm2m'. +invalid_models.clash2: Accessor for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash2: Accessor for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash2: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash2: Accessor for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash2: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target.src_safe'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash2: Accessor for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash2: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash2: Accessor for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash2: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target.src_safe'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash3: Accessor for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash3: Accessor for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash3: Reverse query name for field 'foreign_1' clashes with related m2m field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.clash3: Accessor for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash3: Accessor for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash3: Reverse query name for field 'foreign_2' clashes with related m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash3: Accessor for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash3: Reverse query name for m2m field 'm2m_1' clashes with related field 'Target2.foreign_tgt'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash3: Accessor for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with m2m field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clash3: Reverse query name for m2m field 'm2m_2' clashes with related field 'Target2.m2m_tgt'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.clashforeign: Accessor for field 'foreign' clashes with field 'Target2.clashforeign_set'. Add a related_name argument to the definition for 'foreign'. +invalid_models.clashm2m: Accessor for m2m field 'm2m' clashes with m2m field 'Target2.clashm2m_set'. Add a related_name argument to the definition for 'm2m'. +invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. +invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. +invalid_models.target2: Accessor for field 'foreign_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'foreign_tgt'. +invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. +invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. +invalid_models.target2: Accessor for field 'clashforeign_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashforeign_set'. +invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. +invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. +invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. +invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. +invalid_models.target2: Accessor for m2m field 'm2m_tgt' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'm2m_tgt'. +invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. +invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. +invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. +invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. +invalid_models.target2: Accessor for m2m field 'clashm2m_set' clashes with related m2m field 'Target.target2_set'. Add a related_name argument to the definition for 'clashm2m_set'. +invalid_models.selfclashforeign: Accessor for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign_set'. Add a related_name argument to the definition for 'selfclashforeign_set'. +invalid_models.selfclashforeign: Reverse query name for field 'selfclashforeign_set' clashes with field 'SelfClashForeign.selfclashforeign'. Add a related_name argument to the definition for 'selfclashforeign_set'. +invalid_models.selfclashforeign: Accessor for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.selfclashforeign: Reverse query name for field 'foreign_1' clashes with field 'SelfClashForeign.id'. Add a related_name argument to the definition for 'foreign_1'. +invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. +invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. +invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. +invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. """ + diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index e0c4850ba2..a2c0a14158 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -58,6 +58,10 @@ Article 4 >>> Article.objects.filter(headline__startswith='Blah blah').count() 0L +# Date and date/time lookups can also be done with strings. +>>> Article.objects.filter(pub_date__exact='2005-07-27 00:00:00').count() +3L + # in_bulk() takes a list of IDs and returns a dictionary mapping IDs # to objects. >>> Article.objects.in_bulk([1, 2]) diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py index 7a685ecbd2..f43fb12d9e 100644 --- a/tests/modeltests/m2m_and_m2o/models.py +++ b/tests/modeltests/m2m_and_m2o/models.py @@ -28,24 +28,23 @@ API_TESTS = """ >>> r.save() >>> g = User(username='gustav') >>> g.save() + >>> i = Issue(num=1) >>> i.client = r ->>> i.validate() -{} >>> i.save() + >>> i2 = Issue(num=2) >>> i2.client = r ->>> i2.validate() -{} >>> i2.save() >>> i2.cc.add(r) + >>> i3 = Issue(num=3) >>> i3.client = g ->>> i3.validate() -{} >>> i3.save() >>> i3.cc.add(r) + >>> from django.db.models.query import Q + >>> Issue.objects.filter(client=r.id) [<Issue: 1>, <Issue: 2>] >>> Issue.objects.filter(client=g.id) @@ -55,8 +54,8 @@ API_TESTS = """ >>> Issue.objects.filter(cc__id__exact=r.id) [<Issue: 2>, <Issue: 3>] -# Queries that combine results from the m2m and the m2o relationship. -# 3 ways of saying the same thing: +# These queries combine results from the m2m and the m2o relationships. +# They're three ways of saying the same thing. >>> Issue.objects.filter(Q(cc__id__exact=r.id) | Q(client=r.id)) [<Issue: 1>, <Issue: 2>, <Issue: 3>] >>> Issue.objects.filter(cc__id__exact=r.id) | Issue.objects.filter(client=r.id) diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py index c109b9cc2c..dace32d565 100644 --- a/tests/modeltests/m2m_recursive/models.py +++ b/tests/modeltests/m2m_recursive/models.py @@ -2,7 +2,7 @@ 27. Many-to-many relationships between the same two tables In this example, A Person can have many friends, who are also people. Friendship is a -symmetrical relationshiup - if I am your friend, you are my friend. +symmetrical relationship - if I am your friend, you are my friend. A person can also have many idols - but while I may idolize you, you may not think the same of me. 'Idols' is an example of a non-symmetrical m2m field. Only recursive diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py index e80afece46..0e989a0fbe 100644 --- a/tests/modeltests/many_to_many/models.py +++ b/tests/modeltests/many_to_many/models.py @@ -75,6 +75,10 @@ API_TESTS = """ [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] >>> Article.objects.filter(publications__pk=1) [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] +>>> Article.objects.filter(publications=1) +[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] +>>> Article.objects.filter(publications=p1) +[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] >>> Article.objects.filter(publications__title__startswith="Science") [<Article: NASA uses Python>, <Article: NASA uses Python>] @@ -89,6 +93,13 @@ API_TESTS = """ >>> Article.objects.filter(publications__title__startswith="Science").distinct().count() 1 +>>> Article.objects.filter(publications__in=[1,2]).distinct() +[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] +>>> Article.objects.filter(publications__in=[1,p2]).distinct() +[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] +>>> Article.objects.filter(publications__in=[p1,p2]).distinct() +[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] + # Reverse m2m queries are supported (i.e., starting at the table that doesn't # have a ManyToManyField). >>> Publication.objects.filter(id__exact=1) @@ -101,9 +112,19 @@ API_TESTS = """ >>> Publication.objects.filter(article__id__exact=1) [<Publication: The Python Journal>] - >>> Publication.objects.filter(article__pk=1) [<Publication: The Python Journal>] +>>> Publication.objects.filter(article=1) +[<Publication: The Python Journal>] +>>> Publication.objects.filter(article=a1) +[<Publication: The Python Journal>] + +>>> Publication.objects.filter(article__in=[1,2]).distinct() +[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] +>>> Publication.objects.filter(article__in=[1,a2]).distinct() +[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] +>>> Publication.objects.filter(article__in=[a1,a2]).distinct() +[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] # If we delete a Publication, its Articles won't be able to access it. >>> p1.delete() diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py index a830ffbdc2..d202975128 100644 --- a/tests/modeltests/many_to_one/models.py +++ b/tests/modeltests/many_to_one/models.py @@ -136,6 +136,10 @@ False >>> Article.objects.filter(reporter__first_name__exact='John') [<Article: John's second story>, <Article: This is a test>] +# Check that implied __exact also works +>>> Article.objects.filter(reporter__first_name='John') +[<Article: John's second story>, <Article: This is a test>] + # Query twice over the related field. >>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith') [<Article: John's second story>, <Article: This is a test>] @@ -151,10 +155,20 @@ False [<Article: John's second story>, <Article: This is a test>] # Find all Articles for the Reporter whose ID is 1. +# Use direct ID check, pk check, and object comparison >>> Article.objects.filter(reporter__id__exact=1) [<Article: John's second story>, <Article: This is a test>] >>> Article.objects.filter(reporter__pk=1) [<Article: John's second story>, <Article: This is a test>] +>>> Article.objects.filter(reporter=1) +[<Article: John's second story>, <Article: This is a test>] +>>> Article.objects.filter(reporter=r) +[<Article: John's second story>, <Article: This is a test>] + +>>> Article.objects.filter(reporter__in=[1,2]).distinct() +[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] +>>> Article.objects.filter(reporter__in=[r,r2]).distinct() +[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] # You need two underscores between "reporter" and "id" -- not one. >>> Article.objects.filter(reporter_id__exact=1) @@ -168,10 +182,6 @@ Traceback (most recent call last): ... TypeError: Cannot resolve keyword 'reporter_id' into field -# "pk" shortcut syntax works in a related context, too. ->>> Article.objects.filter(reporter__pk=1) -[<Article: John's second story>, <Article: This is a test>] - # You can also instantiate an Article by passing # the Reporter's ID instead of a Reporter object. >>> a3 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id=r.id) @@ -200,6 +210,18 @@ TypeError: Cannot resolve keyword 'reporter_id' into field [<Reporter: John Smith>] >>> Reporter.objects.filter(article__pk=1) [<Reporter: John Smith>] +>>> Reporter.objects.filter(article=1) +[<Reporter: John Smith>] +>>> Reporter.objects.filter(article=a) +[<Reporter: John Smith>] + +>>> Reporter.objects.filter(article__in=[1,4]).distinct() +[<Reporter: John Smith>] +>>> Reporter.objects.filter(article__in=[1,a3]).distinct() +[<Reporter: John Smith>] +>>> Reporter.objects.filter(article__in=[a,a3]).distinct() +[<Reporter: John Smith>] + >>> Reporter.objects.filter(article__headline__startswith='This') [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] >>> Reporter.objects.filter(article__headline__startswith='This').distinct() @@ -216,6 +238,12 @@ TypeError: Cannot resolve keyword 'reporter_id' into field [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct() [<Reporter: John Smith>] +>>> Reporter.objects.filter(article__reporter__exact=r).distinct() +[<Reporter: John Smith>] + +# Check that implied __exact also works +>>> Reporter.objects.filter(article__reporter=r).distinct() +[<Reporter: John Smith>] # If you delete a reporter, his articles will be deleted. >>> Article.objects.all() diff --git a/tests/modeltests/one_to_one/models.py b/tests/modeltests/one_to_one/models.py index 27c16b5a34..f95556c08d 100644 --- a/tests/modeltests/one_to_one/models.py +++ b/tests/modeltests/one_to_one/models.py @@ -94,6 +94,12 @@ DoesNotExist: Restaurant matching query does not exist. <Restaurant: Demon Dogs the restaurant> >>> Restaurant.objects.get(place__exact=1) <Restaurant: Demon Dogs the restaurant> +>>> Restaurant.objects.get(place__exact=p1) +<Restaurant: Demon Dogs the restaurant> +>>> Restaurant.objects.get(place=1) +<Restaurant: Demon Dogs the restaurant> +>>> Restaurant.objects.get(place=p1) +<Restaurant: Demon Dogs the restaurant> >>> Restaurant.objects.get(place__pk=1) <Restaurant: Demon Dogs the restaurant> >>> Restaurant.objects.get(place__name__startswith="Demon") @@ -105,8 +111,18 @@ DoesNotExist: Restaurant matching query does not exist. <Place: Demon Dogs the place> >>> Place.objects.get(restaurant__place__exact=1) <Place: Demon Dogs the place> +>>> Place.objects.get(restaurant__place__exact=p1) +<Place: Demon Dogs the place> >>> Place.objects.get(restaurant__pk=1) <Place: Demon Dogs the place> +>>> Place.objects.get(restaurant=1) +<Place: Demon Dogs the place> +>>> Place.objects.get(restaurant=r) +<Place: Demon Dogs the place> +>>> Place.objects.get(restaurant__exact=1) +<Place: Demon Dogs the place> +>>> Place.objects.get(restaurant__exact=r) +<Place: Demon Dogs the place> # Add a Waiter to the Restaurant. >>> w = r.waiter_set.create(name='Joe') @@ -115,14 +131,22 @@ DoesNotExist: Restaurant matching query does not exist. <Waiter: Joe the waiter at Demon Dogs the restaurant> # Query the waiters +>>> Waiter.objects.filter(restaurant__place__pk=1) +[<Waiter: Joe the waiter at Demon Dogs the restaurant>] >>> Waiter.objects.filter(restaurant__place__exact=1) [<Waiter: Joe the waiter at Demon Dogs the restaurant>] +>>> Waiter.objects.filter(restaurant__place__exact=p1) +[<Waiter: Joe the waiter at Demon Dogs the restaurant>] >>> Waiter.objects.filter(restaurant__pk=1) [<Waiter: Joe the waiter at Demon Dogs the restaurant>] >>> Waiter.objects.filter(id__exact=1) [<Waiter: Joe the waiter at Demon Dogs the restaurant>] >>> Waiter.objects.filter(pk=1) [<Waiter: Joe the waiter at Demon Dogs the restaurant>] +>>> Waiter.objects.filter(restaurant=1) +[<Waiter: Joe the waiter at Demon Dogs the restaurant>] +>>> Waiter.objects.filter(restaurant=r) +[<Waiter: Joe the waiter at Demon Dogs the restaurant>] # Delete the restaurant; the waiter should also be removed >>> r = Restaurant.objects.get(pk=1) diff --git a/tests/modeltests/serializers/__init__.py b/tests/modeltests/serializers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/modeltests/serializers/__init__.py diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py new file mode 100644 index 0000000000..ccf565c365 --- /dev/null +++ b/tests/modeltests/serializers/models.py @@ -0,0 +1,121 @@ +""" +XXX. Serialization + +``django.core.serializers`` provides interfaces to converting Django querysets +to and from "flat" data (i.e. strings). +""" + +from django.db import models + +class Category(models.Model): + name = models.CharField(maxlength=20) + + class Meta: + ordering = ('name',) + + def __str__(self): + return self.name + +class Author(models.Model): + name = models.CharField(maxlength=20) + + class Meta: + ordering = ('name',) + + def __str__(self): + return self.name + +class Article(models.Model): + author = models.ForeignKey(Author) + headline = models.CharField(maxlength=50) + pub_date = models.DateTimeField() + categories = models.ManyToManyField(Category) + + class Meta: + ordering = ('pub_date',) + + def __str__(self): + return self.headline + +API_TESTS = """ +# Create some data: +>>> from datetime import datetime +>>> sports = Category(name="Sports") +>>> music = Category(name="Music") +>>> op_ed = Category(name="Op-Ed") +>>> sports.save(); music.save(); op_ed.save() + +>>> joe = Author(name="Joe") +>>> jane = Author(name="Jane") +>>> joe.save(); jane.save() + +>>> a1 = Article( +... author = jane, +... headline = "Poker has no place on ESPN", +... pub_date = datetime(2006, 6, 16, 11, 00)) +>>> a2 = Article( +... author = joe, +... headline = "Time to reform copyright", +... pub_date = datetime(2006, 6, 16, 13, 00)) +>>> a1.save(); a2.save() +>>> a1.categories = [sports, op_ed] +>>> a2.categories = [music, op_ed] + +# Serialize a queryset to XML +>>> from django.core import serializers +>>> xml = serializers.serialize("xml", Article.objects.all()) + +# The output is valid XML +>>> from xml.dom import minidom +>>> dom = minidom.parseString(xml) + +# Deserializing has a similar interface, except that special DeserializedObject +# instances are returned. This is because data might have changed in the +# database since the data was serialized (we'll simulate that below). +>>> for obj in serializers.deserialize("xml", xml): +... print obj +<DeserializedObject: Poker has no place on ESPN> +<DeserializedObject: Time to reform copyright> + +# Deserializing data with different field values doesn't change anything in the +# database until we call save(): +>>> xml = xml.replace("Poker has no place on ESPN", "Poker has no place on television") +>>> objs = list(serializers.deserialize("xml", xml)) + +# Even those I deserialized, the database hasn't been touched +>>> Article.objects.all() +[<Article: Poker has no place on ESPN>, <Article: Time to reform copyright>] + +# But when I save, the data changes as you might except. +>>> objs[0].save() +>>> Article.objects.all() +[<Article: Poker has no place on television>, <Article: Time to reform copyright>] + +# Django also ships with a built-in JSON serializers +>>> json = serializers.serialize("json", Category.objects.filter(pk=2)) +>>> json +'[{"pk": "2", "model": "serializers.category", "fields": {"name": "Music"}}]' + +# You can easily create new objects by deserializing data with an empty PK +# (It's easier to demo this with JSON...) +>>> new_author_json = '[{"pk": null, "model": "serializers.author", "fields": {"name": "Bill"}}]' +>>> for obj in serializers.deserialize("json", new_author_json): +... obj.save() +>>> Author.objects.all() +[<Author: Bill>, <Author: Jane>, <Author: Joe>] + +# All the serializers work the same +>>> json = serializers.serialize("json", Article.objects.all()) +>>> for obj in serializers.deserialize("json", json): +... print obj +<DeserializedObject: Poker has no place on television> +<DeserializedObject: Time to reform copyright> + +>>> json = json.replace("Poker has no place on television", "Just kidding; I love TV poker") +>>> for obj in serializers.deserialize("json", json): +... obj.save() + +>>> Article.objects.all() +[<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>] + +""" diff --git a/tests/othertests/defaultfilters.py b/tests/othertests/defaultfilters.py index 46f2519285..1636b948d0 100644 --- a/tests/othertests/defaultfilters.py +++ b/tests/othertests/defaultfilters.py @@ -313,6 +313,36 @@ False >>> pluralize(2) 's' +>>> pluralize([1]) +'' + +>>> pluralize([]) +'s' + +>>> pluralize([1,2,3]) +'s' + +>>> pluralize(1,'es') +'' + +>>> pluralize(0,'es') +'es' + +>>> pluralize(2,'es') +'es' + +>>> pluralize(1,'y,ies') +'y' + +>>> pluralize(0,'y,ies') +'ies' + +>>> pluralize(2,'y,ies') +'ies' + +>>> pluralize(0,'y,ies,error') +'' + >>> phone2numeric('0800 flowers') '0800 3569377' diff --git a/tests/othertests/markup.py b/tests/othertests/markup.py index 3fa5a3a883..2b00a8c7a5 100644 --- a/tests/othertests/markup.py +++ b/tests/othertests/markup.py @@ -1,6 +1,7 @@ # Quick tests for the markup templatetags (django.contrib.markup) from django.template import Template, Context, add_to_builtins +import re add_to_builtins('django.contrib.markup.templatetags.markup') @@ -47,7 +48,8 @@ markdown_content = """Paragraph 1 t = Template("{{ markdown_content|markdown }}") rendered = t.render(Context(locals())).strip() if markdown: - assert rendered == """<p>Paragraph 1</p><h2>An h2</h2>""" + pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""") + assert pattern.match(rendered) else: assert rendered == markdown_content diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py index c0333c90a6..9975f3b05c 100644 --- a/tests/othertests/templates.py +++ b/tests/othertests/templates.py @@ -1,5 +1,9 @@ from django.conf import settings +if __name__ == '__main__': + # When running this file in isolation, we need to set up the configuration + # before importing 'template'. + settings.configure() from django import template from django.template import loader @@ -78,7 +82,7 @@ TEMPLATE_TESTS = { 'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"), # Fail silently when a variable is not found in the current context - 'basic-syntax04': ("as{{ missing }}df", {}, "asdf"), + 'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"), # A variable may not contain more than one word 'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError), @@ -94,7 +98,7 @@ TEMPLATE_TESTS = { 'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"), # Fail silently when a variable's attribute isn't found - 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""), + 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"), # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore 'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError), @@ -110,10 +114,10 @@ TEMPLATE_TESTS = { 'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"), # Fail silently when a variable's dictionary key isn't found - 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""), + 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"), # Fail silently when accessing a non-simple method - 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""), + 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"), # Basic filter usage 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), @@ -152,7 +156,7 @@ TEMPLATE_TESTS = { 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute - 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "12"), + 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"), # In methods that raise an exception without a "silent_variable_attribute" set to True, # the exception propogates @@ -406,6 +410,12 @@ TEMPLATE_TESTS = { # Three-level inheritance with {{ block.super }} from parent and grandparent 'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'), + # Inheritance from local context without use of template loader + 'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'), + + # Inheritance from local context with variable parent template + 'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'), + ### I18N ################################################################## # {% spaceless %} tag @@ -495,7 +505,7 @@ TEMPLATE_TESTS = { '{{ item.foo }}' + \ '{% endfor %},' + \ '{% endfor %}', - {}, ''), + {}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'), ### TEMPLATETAG TAG ####################################################### 'templatetag01': ('{% templatetag openblock %}', {}, '{%'), @@ -538,10 +548,10 @@ TEMPLATE_TESTS = { ### TIMESINCE TAG ################################################## # Default compare with datetime.now() - 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1)}, '1 minute'), - 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1))}, '1 day'), + 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'), + 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'), 'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() - - timedelta(hours=1, minutes=25))}, '1 hour, 25 minutes'), + timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'), # Compare to a given parameter 'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'), @@ -552,9 +562,9 @@ TEMPLATE_TESTS = { ### TIMEUNTIL TAG ################################################## # Default compare with datetime.now() - 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2)}, '2 minutes'), - 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1))}, '1 day'), - 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10))}, '8 hours, 10 minutes'), + 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'), + 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'), + 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'), # Compare to a given parameter 'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'), @@ -579,6 +589,9 @@ def run_tests(verbosity=0, standalone=False): # Turn TEMPLATE_DEBUG off, because tests assume that. old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False + # Set TEMPLATE_STRING_IF_INVALID to a known string + old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID' + for name, vals in tests: install() if 'LANGUAGE_CODE' in vals[1]: @@ -609,6 +622,7 @@ def run_tests(verbosity=0, standalone=False): loader.template_source_loaders = old_template_loaders deactivate() settings.TEMPLATE_DEBUG = old_td + settings.TEMPLATE_STRING_IF_INVALID = old_invalid if failed_tests and not standalone: msg = "Template tests %s failed." % failed_tests @@ -617,5 +631,4 @@ def run_tests(verbosity=0, standalone=False): raise Exception, msg if __name__ == "__main__": - settings.configure() run_tests(1, True) diff --git a/tests/othertests/urlpatterns_reverse.py b/tests/othertests/urlpatterns_reverse.py new file mode 100644 index 0000000000..236944d49f --- /dev/null +++ b/tests/othertests/urlpatterns_reverse.py @@ -0,0 +1,47 @@ +"Unit tests for reverse URL lookup" + +from django.core.urlresolvers import reverse_helper, NoReverseMatch +import re + +test_data = ( + ('^places/(\d+)/$', 'places/3/', [3], {}), + ('^places/(\d+)/$', 'places/3/', ['3'], {}), + ('^places/(\d+)/$', NoReverseMatch, ['a'], {}), + ('^places/(\d+)/$', NoReverseMatch, [], {}), + ('^places/(?P<id>\d+)/$', 'places/3/', [], {'id': 3}), + ('^people/(?P<name>\w+)/$', 'people/adrian/', ['adrian'], {}), + ('^people/(?P<name>\w+)/$', 'people/adrian/', [], {'name': 'adrian'}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, ['name with spaces'], {}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'name with spaces'}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {}), + ('^hardcoded/$', 'hardcoded/', [], {}), + ('^hardcoded/$', 'hardcoded/', ['any arg'], {}), + ('^hardcoded/$', 'hardcoded/', [], {'kwarg': 'foo'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'people/il/adrian/', [], {'state': 'il', 'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(?P<name>\d)/$', NoReverseMatch, [], {'state': 'il', 'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'state': 'il'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(\w+)/$', NoReverseMatch, ['il'], {'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(\w+)/$', 'people/il/adrian/', ['adrian'], {'state': 'il'}), +) + +def run_tests(verbosity=0): + for regex, expected, args, kwargs in test_data: + passed = True + try: + got = reverse_helper(re.compile(regex), *args, **kwargs) + except NoReverseMatch, e: + if expected != NoReverseMatch: + passed, got = False, str(e) + else: + if got != expected: + passed, got = False, got + if passed and verbosity: + print "Passed: %s" % regex + elif not passed: + print "REVERSE LOOKUP FAILED: %s" % regex + print " Got: %s" % got + print " Expected: %r" % expected + +if __name__ == "__main__": + run_tests(1) diff --git a/tests/regressiontests/many_to_one_regress/__init__.py b/tests/regressiontests/many_to_one_regress/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/many_to_one_regress/__init__.py diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py new file mode 100644 index 0000000000..485e928777 --- /dev/null +++ b/tests/regressiontests/many_to_one_regress/models.py @@ -0,0 +1,13 @@ +from django.db import models + +class First(models.Model): + second = models.IntegerField() + +class Second(models.Model): + first = models.ForeignKey(First, related_name = 'the_first') + +# If ticket #1578 ever slips back in, these models will not be able to be +# created (the field names being lower-cased versions of their opposite +# classes is important here). + +API_TESTS = "" diff --git a/tests/runtests.py b/tests/runtests.py index e5e9c18fca..b98a739249 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -99,8 +99,9 @@ class TestRunner: # Manually set INSTALLED_APPS to point to the test models. settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + ['.'.join(a) for a in get_test_models()] - # Manually set DEBUG = False. + # Manually set DEBUG and USE_I18N. settings.DEBUG = False + settings.USE_I18N = True from django.db import connection from django.core import management |
