summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJoseph Kocherhans <joseph@jkocherhans.com>2006-11-06 21:11:49 +0000
committerJoseph Kocherhans <joseph@jkocherhans.com>2006-11-06 21:11:49 +0000
commitdc59c670b8cbe055ff3565f8d5a2f600c5ab1ba8 (patch)
tree84a2d1a3e729a813cf692ebbe7404ba8e5687d22 /tests
parentbf629e5a4d1a51f938c84d35d768830158ad5ebd (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.py5
-rw-r--r--tests/modeltests/invalid_models/models.py118
-rw-r--r--tests/modeltests/lookup/models.py4
-rw-r--r--tests/modeltests/m2m_and_m2o/models.py15
-rw-r--r--tests/modeltests/m2m_recursive/models.py2
-rw-r--r--tests/modeltests/many_to_many/models.py23
-rw-r--r--tests/modeltests/many_to_one/models.py36
-rw-r--r--tests/modeltests/one_to_one/models.py24
-rw-r--r--tests/modeltests/serializers/__init__.py0
-rw-r--r--tests/modeltests/serializers/models.py121
-rw-r--r--tests/othertests/defaultfilters.py30
-rw-r--r--tests/othertests/markup.py4
-rw-r--r--tests/othertests/templates.py39
-rw-r--r--tests/othertests/urlpatterns_reverse.py47
-rw-r--r--tests/regressiontests/many_to_one_regress/__init__.py0
-rw-r--r--tests/regressiontests/many_to_one_regress/models.py13
-rwxr-xr-xtests/runtests.py3
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