summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
committerAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
commitb546e7eb633022ee1962570387f22fb2bcea46ed (patch)
treef87f4a2d68fb66afae39148fa35489930710b623 /tests
parentcd583d6dbd222ae61331a6965b0e1fc86c974c50 (diff)
parentcff911f4ba3b3e6393c58da5131ce8b188a68f0c (diff)
Merge branch 'master' into schema-alteration
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/aggregation/models.py13
-rw-r--r--tests/modeltests/basic/models.py4
-rw-r--r--tests/modeltests/choices/models.py4
-rw-r--r--tests/modeltests/custom_columns/models.py7
-rw-r--r--tests/modeltests/custom_managers/models.py10
-rw-r--r--tests/modeltests/custom_methods/models.py4
-rw-r--r--tests/modeltests/custom_pk/fields.py9
-rw-r--r--tests/modeltests/custom_pk/models.py10
-rw-r--r--tests/modeltests/defer/models.py4
-rw-r--r--tests/modeltests/delete/models.py4
-rw-r--r--tests/modeltests/distinct_on_fields/models.py13
-rw-r--r--tests/modeltests/expressions/models.py7
-rw-r--r--tests/modeltests/field_defaults/models.py4
-rw-r--r--tests/modeltests/field_subclassing/fields.py13
-rw-r--r--tests/modeltests/field_subclassing/models.py4
-rw-r--r--tests/modeltests/files/tests.py14
-rw-r--r--tests/modeltests/fixtures/models.py22
-rw-r--r--tests/modeltests/fixtures_model_package/models/__init__.py4
-rw-r--r--tests/modeltests/generic_relations/models.py16
-rw-r--r--tests/modeltests/get_latest/models.py7
-rw-r--r--tests/modeltests/get_object_or_404/models.py7
-rw-r--r--tests/modeltests/get_or_create/models.py4
-rw-r--r--tests/modeltests/invalid_models/tests.py4
-rw-r--r--tests/modeltests/lookup/models.py13
-rw-r--r--tests/modeltests/m2m_and_m2o/models.py4
-rw-r--r--tests/modeltests/m2m_intermediary/models.py10
-rw-r--r--tests/modeltests/m2m_multiple/models.py7
-rw-r--r--tests/modeltests/m2m_recursive/models.py4
-rw-r--r--tests/modeltests/m2m_signals/models.py10
-rw-r--r--tests/modeltests/m2m_through/models.py16
-rw-r--r--tests/modeltests/m2o_recursive/models.py7
-rw-r--r--tests/modeltests/many_to_many/models.py7
-rw-r--r--tests/modeltests/many_to_one/models.py7
-rw-r--r--tests/modeltests/many_to_one_null/models.py7
-rw-r--r--tests/modeltests/model_forms/models.py52
-rw-r--r--tests/modeltests/model_forms/tests.py69
-rw-r--r--tests/modeltests/model_formsets/models.py55
-rw-r--r--tests/modeltests/model_inheritance/models.py28
-rw-r--r--tests/modeltests/model_inheritance_same_model_name/models.py4
-rw-r--r--tests/modeltests/one_to_one/models.py13
-rw-r--r--tests/modeltests/or_lookups/models.py4
-rw-r--r--tests/modeltests/order_with_respect_to/models.py7
-rw-r--r--tests/modeltests/ordering/models.py7
-rw-r--r--tests/modeltests/pagination/models.py4
-rw-r--r--tests/modeltests/pagination/tests.py12
-rw-r--r--tests/modeltests/prefetch_related/models.py22
-rw-r--r--tests/modeltests/prefetch_related/tests.py2
-rw-r--r--tests/modeltests/proxy_model_inheritance/tests.py3
-rw-r--r--tests/modeltests/proxy_models/models.py13
-rw-r--r--tests/modeltests/reserved_names/models.py6
-rw-r--r--tests/modeltests/reverse_lookup/models.py10
-rw-r--r--tests/modeltests/save_delete_hooks/models.py4
-rw-r--r--tests/modeltests/select_related/models.py27
-rw-r--r--tests/modeltests/serializers/models.py29
-rw-r--r--tests/modeltests/serializers/tests.py18
-rw-r--r--tests/modeltests/signals/models.py7
-rw-r--r--tests/modeltests/str/models.py6
-rw-r--r--tests/modeltests/str/tests.py17
-rw-r--r--tests/modeltests/test_client/models.py2
-rw-r--r--tests/modeltests/timezones/tests.py1
-rw-r--r--tests/modeltests/transactions/models.py4
-rw-r--r--tests/modeltests/unmanaged_models/models.py19
-rw-r--r--tests/modeltests/update/models.py7
-rw-r--r--tests/modeltests/update_only_fields/models.py8
-rw-r--r--tests/modeltests/update_only_fields/tests.py101
-rw-r--r--tests/modeltests/validation/models.py6
-rw-r--r--tests/modeltests/validation/tests.py6
-rw-r--r--tests/regressiontests/admin_changelist/models.py7
-rw-r--r--tests/regressiontests/admin_changelist/tests.py4
-rw-r--r--tests/regressiontests/admin_custom_urls/fixtures/actions.json9
-rw-r--r--tests/regressiontests/admin_custom_urls/models.py6
-rw-r--r--tests/regressiontests/admin_custom_urls/tests.py43
-rw-r--r--tests/regressiontests/admin_filters/models.py10
-rw-r--r--tests/regressiontests/admin_inlines/models.py10
-rw-r--r--tests/regressiontests/admin_scripts/custom_templates/project_template/ticket-18091-non-ascii-template.txt2
-rw-r--r--tests/regressiontests/admin_scripts/models.py4
-rw-r--r--tests/regressiontests/admin_scripts/tests.py30
-rw-r--r--tests/regressiontests/admin_util/models.py4
-rw-r--r--tests/regressiontests/admin_util/tests.py2
-rw-r--r--tests/regressiontests/admin_validation/models.py4
-rw-r--r--tests/regressiontests/admin_views/models.py91
-rw-r--r--tests/regressiontests/admin_views/tests.py349
-rw-r--r--tests/regressiontests/admin_widgets/models.py24
-rw-r--r--tests/regressiontests/aggregation_regress/models.py16
-rw-r--r--tests/regressiontests/aggregation_regress/tests.py12
-rw-r--r--tests/regressiontests/backends/models.py13
-rw-r--r--tests/regressiontests/backends/tests.py8
-rw-r--r--tests/regressiontests/builtin_server/tests.py24
-rw-r--r--tests/regressiontests/cache/tests.py101
-rw-r--r--tests/regressiontests/comment_tests/models.py6
-rw-r--r--tests/regressiontests/conditional_processing/models.py6
-rw-r--r--tests/regressiontests/csrf_tests/tests.py2
-rw-r--r--tests/regressiontests/custom_columns_regress/models.py7
-rw-r--r--tests/regressiontests/custom_managers_regress/models.py10
-rw-r--r--tests/regressiontests/datatypes/models.py2
-rw-r--r--tests/regressiontests/dates/models.py7
-rw-r--r--tests/regressiontests/decorators/tests.py2
-rw-r--r--tests/regressiontests/defaultfilters/tests.py4
-rw-r--r--tests/regressiontests/defer_regress/models.py10
-rw-r--r--tests/regressiontests/dispatch/tests/test_saferef.py2
-rw-r--r--tests/regressiontests/expressions_regress/models.py4
-rw-r--r--tests/regressiontests/extra_regress/models.py7
-rw-r--r--tests/regressiontests/file_storage/tests.py81
-rw-r--r--tests/regressiontests/file_uploads/tests.py29
-rw-r--r--tests/regressiontests/file_uploads/views.py5
-rw-r--r--tests/regressiontests/fixtures_regress/models.py25
-rw-r--r--tests/regressiontests/fixtures_regress/tests.py27
-rw-r--r--tests/regressiontests/forms/models.py7
-rw-r--r--tests/regressiontests/forms/tests/error_messages.py4
-rw-r--r--tests/regressiontests/forms/tests/extra.py28
-rw-r--r--tests/regressiontests/forms/tests/fields.py12
-rw-r--r--tests/regressiontests/forms/tests/models.py4
-rw-r--r--tests/regressiontests/forms/tests/util.py4
-rw-r--r--tests/regressiontests/forms/tests/widgets.py7
-rw-r--r--tests/regressiontests/generic_inline_admin/models.py4
-rw-r--r--tests/regressiontests/generic_inline_admin/tests.py6
-rw-r--r--tests/regressiontests/generic_relations_regress/models.py16
-rw-r--r--tests/regressiontests/generic_views/base.py17
-rw-r--r--tests/regressiontests/generic_views/dates.py24
-rw-r--r--tests/regressiontests/generic_views/detail.py2
-rw-r--r--tests/regressiontests/generic_views/edit.py5
-rw-r--r--tests/regressiontests/generic_views/list.py2
-rw-r--r--tests/regressiontests/generic_views/models.py10
-rw-r--r--tests/regressiontests/generic_views/urls.py2
-rw-r--r--tests/regressiontests/httpwrappers/tests.py178
-rw-r--r--tests/regressiontests/i18n/tests.py18
-rw-r--r--tests/regressiontests/inline_formsets/models.py7
-rw-r--r--tests/regressiontests/inspectdb/models.py9
-rw-r--r--tests/regressiontests/inspectdb/tests.py40
-rw-r--r--tests/regressiontests/introspection/models.py7
-rw-r--r--tests/regressiontests/introspection/tests.py9
-rw-r--r--tests/regressiontests/m2m_regress/models.py13
-rw-r--r--tests/regressiontests/m2m_through_regress/models.py22
-rw-r--r--tests/regressiontests/m2m_through_regress/tests.py9
-rw-r--r--tests/regressiontests/mail/tests.py2
-rw-r--r--tests/regressiontests/managers_regress/models.py19
-rw-r--r--tests/regressiontests/many_to_one_regress/models.py7
-rw-r--r--tests/regressiontests/middleware/tests.py14
-rw-r--r--tests/regressiontests/model_fields/models.py27
-rw-r--r--tests/regressiontests/model_fields/tests.py10
-rw-r--r--tests/regressiontests/model_forms_regress/models.py7
-rw-r--r--tests/regressiontests/model_forms_regress/tests.py5
-rw-r--r--tests/regressiontests/model_formsets_regress/models.py4
-rw-r--r--tests/regressiontests/model_inheritance_regress/models.py28
-rw-r--r--tests/regressiontests/model_inheritance_select_related/models.py10
-rw-r--r--tests/regressiontests/model_regress/models.py18
-rw-r--r--tests/regressiontests/modeladmin/models.py4
-rw-r--r--tests/regressiontests/modeladmin/tests.py58
-rw-r--r--tests/regressiontests/multiple_database/models.py13
-rw-r--r--tests/regressiontests/multiple_database/tests.py15
-rw-r--r--tests/regressiontests/nested_foreign_keys/__init__.py0
-rw-r--r--tests/regressiontests/nested_foreign_keys/models.py28
-rw-r--r--tests/regressiontests/nested_foreign_keys/tests.py166
-rw-r--r--tests/regressiontests/null_fk/models.py7
-rw-r--r--tests/regressiontests/null_fk_ordering/models.py10
-rw-r--r--tests/regressiontests/null_queries/models.py7
-rw-r--r--tests/regressiontests/one_to_one_regress/models.py13
-rw-r--r--tests/regressiontests/pagination_regress/tests.py6
-rw-r--r--tests/regressiontests/queries/models.py94
-rw-r--r--tests/regressiontests/queries/tests.py69
-rw-r--r--tests/regressiontests/requests/tests.py56
-rw-r--r--tests/regressiontests/select_related_onetoone/models.py16
-rw-r--r--tests/regressiontests/select_related_regress/models.py19
-rw-r--r--tests/regressiontests/serializers_regress/tests.py8
-rw-r--r--tests/regressiontests/servers/tests.py2
-rw-r--r--tests/regressiontests/settings_tests/tests.py10
-rw-r--r--tests/regressiontests/signals_regress/models.py7
-rw-r--r--tests/regressiontests/signing/tests.py30
-rw-r--r--tests/regressiontests/sites_framework/models.py4
-rw-r--r--tests/regressiontests/staticfiles_tests/tests.py18
-rw-r--r--tests/regressiontests/string_lookup/models.py19
-rw-r--r--tests/regressiontests/syndication/models.py7
-rw-r--r--tests/regressiontests/templates/filters.py19
-rw-r--r--tests/regressiontests/templates/response.py34
-rw-r--r--tests/regressiontests/templates/tests.py26
-rw-r--r--tests/regressiontests/test_client_regress/tests.py4
-rw-r--r--tests/regressiontests/test_client_regress/views.py4
-rw-r--r--tests/regressiontests/test_utils/tests.py33
-rw-r--r--tests/regressiontests/urlpatterns_reverse/tests.py36
-rw-r--r--tests/regressiontests/urlpatterns_reverse/views_broken.py2
-rw-r--r--tests/regressiontests/utils/archive.py6
-rw-r--r--tests/regressiontests/utils/crypto.py12
-rw-r--r--tests/regressiontests/utils/dateparse.py44
-rw-r--r--tests/regressiontests/utils/encoding.py17
-rw-r--r--tests/regressiontests/utils/html.py9
-rw-r--r--tests/regressiontests/utils/module_loading.py13
-rw-r--r--tests/regressiontests/utils/tests.py34
-rw-r--r--tests/regressiontests/utils/text.py8
-rw-r--r--tests/regressiontests/views/models.py7
-rw-r--r--tests/regressiontests/views/tests/debug.py2
-rw-r--r--tests/regressiontests/views/tests/i18n.py30
-rw-r--r--tests/regressiontests/views/tests/shortcuts.py14
-rw-r--r--tests/regressiontests/wsgi/tests.py4
193 files changed, 2381 insertions, 1142 deletions
diff --git a/tests/modeltests/aggregation/models.py b/tests/modeltests/aggregation/models.py
index ccc12898b7..b4f797ee03 100644
--- a/tests/modeltests/aggregation/models.py
+++ b/tests/modeltests/aggregation/models.py
@@ -1,22 +1,26 @@
# coding: utf-8
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
friends = models.ManyToManyField('self', blank=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Publisher(models.Model):
name = models.CharField(max_length=255)
num_awards = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Book(models.Model):
isbn = models.CharField(max_length=9)
name = models.CharField(max_length=255)
@@ -28,15 +32,16 @@ class Book(models.Model):
publisher = models.ForeignKey(Publisher)
pubdate = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Store(models.Model):
name = models.CharField(max_length=255)
books = models.ManyToManyField(Book)
original_opening = models.DateTimeField()
friday_night_closing = models.TimeField()
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index 06aa9cf3c3..660beddf49 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -5,8 +5,10 @@
This is a basic model with only two non-primary-key fields.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
@@ -14,5 +16,5 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date','headline')
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/choices/models.py b/tests/modeltests/choices/models.py
index ee01911573..2fa33a9680 100644
--- a/tests/modeltests/choices/models.py
+++ b/tests/modeltests/choices/models.py
@@ -10,6 +10,7 @@ field. This method returns the "human-readable" value of the field.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
GENDER_CHOICES = (
@@ -17,9 +18,10 @@ GENDER_CHOICES = (
('F', 'Female'),
)
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py
index 39f1274a8f..16f0563d6b 100644
--- a/tests/modeltests/custom_columns/models.py
+++ b/tests/modeltests/custom_columns/models.py
@@ -18,24 +18,27 @@ from the default generated name, use the ``db_table`` parameter on the
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
first_name = models.CharField(max_length=30, db_column='firstname')
last_name = models.CharField(max_length=30, db_column='last')
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
class Meta:
db_table = 'my_author_table'
ordering = ('last_name','first_name')
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, db_table='my_m2m_table')
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py
index a9845ad414..de7c1772ed 100644
--- a/tests/modeltests/custom_managers/models.py
+++ b/tests/modeltests/custom_managers/models.py
@@ -12,6 +12,7 @@ returns.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# An example of a custom manager called "objects".
@@ -19,13 +20,14 @@ class PersonManager(models.Manager):
def get_fun_people(self):
return self.filter(fun=True)
+@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
fun = models.BooleanField()
objects = PersonManager()
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
# An example of a custom manager that sets get_query_set().
@@ -34,6 +36,7 @@ class PublishedBookManager(models.Manager):
def get_query_set(self):
return super(PublishedBookManager, self).get_query_set().filter(is_published=True)
+@python_2_unicode_compatible
class Book(models.Model):
title = models.CharField(max_length=50)
author = models.CharField(max_length=30)
@@ -41,7 +44,7 @@ class Book(models.Model):
published_objects = PublishedBookManager()
authors = models.ManyToManyField(Person, related_name='books')
- def __unicode__(self):
+ def __str__(self):
return self.title
# An example of providing multiple custom managers.
@@ -50,6 +53,7 @@ class FastCarManager(models.Manager):
def get_query_set(self):
return super(FastCarManager, self).get_query_set().filter(top_speed__gt=150)
+@python_2_unicode_compatible
class Car(models.Model):
name = models.CharField(max_length=10)
mileage = models.IntegerField()
@@ -57,5 +61,5 @@ class Car(models.Model):
cars = models.Manager()
fast_cars = FastCarManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py
index 4e3da58851..cef3fd722b 100644
--- a/tests/modeltests/custom_methods/models.py
+++ b/tests/modeltests/custom_methods/models.py
@@ -7,13 +7,15 @@ Any method you add to a model will be available to instances.
import datetime
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
def was_published_today(self):
diff --git a/tests/modeltests/custom_pk/fields.py b/tests/modeltests/custom_pk/fields.py
index 68fb9dcd16..92096a0ff7 100644
--- a/tests/modeltests/custom_pk/fields.py
+++ b/tests/modeltests/custom_pk/fields.py
@@ -3,8 +3,10 @@ import string
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class MyWrapper(object):
def __init__(self, value):
self.value = value
@@ -12,7 +14,7 @@ class MyWrapper(object):
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.value)
- def __unicode__(self):
+ def __str__(self):
return self.value
def __eq__(self, other):
@@ -20,8 +22,7 @@ class MyWrapper(object):
return self.value == other.value
return self.value == other
-class MyAutoField(models.CharField):
- __metaclass__ = models.SubfieldBase
+class MyAutoField(six.with_metaclass(models.SubfieldBase, models.CharField)):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 10
@@ -30,7 +31,7 @@ class MyAutoField(models.CharField):
def pre_save(self, instance, add):
value = getattr(instance, self.attname, None)
if not value:
- value = MyWrapper(''.join(random.sample(string.lowercase, 10)))
+ value = MyWrapper(''.join(random.sample(string.ascii_lowercase, 10)))
setattr(instance, self.attname, value)
return value
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py
index 8199b05a1a..5ef9b69f0c 100644
--- a/tests/modeltests/custom_pk/models.py
+++ b/tests/modeltests/custom_pk/models.py
@@ -11,8 +11,10 @@ from __future__ import absolute_import, unicode_literals
from django.db import models
from .fields import MyAutoField
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Employee(models.Model):
employee_code = models.IntegerField(primary_key=True, db_column = 'code')
first_name = models.CharField(max_length=20)
@@ -20,22 +22,24 @@ class Employee(models.Model):
class Meta:
ordering = ('last_name', 'first_name')
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Business(models.Model):
name = models.CharField(max_length=20, primary_key=True)
employees = models.ManyToManyField(Employee)
class Meta:
verbose_name_plural = 'businesses'
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Bar(models.Model):
id = MyAutoField(primary_key=True, db_index=True)
- def __unicode__(self):
+ def __str__(self):
return repr(self.pk)
diff --git a/tests/modeltests/defer/models.py b/tests/modeltests/defer/models.py
index c64becf972..0688cbc984 100644
--- a/tests/modeltests/defer/models.py
+++ b/tests/modeltests/defer/models.py
@@ -3,18 +3,20 @@ Tests for defer() and only().
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Secondary(models.Model):
first = models.CharField(max_length=50)
second = models.CharField(max_length=50)
+@python_2_unicode_compatible
class Primary(models.Model):
name = models.CharField(max_length=50)
value = models.CharField(max_length=50)
related = models.ForeignKey(Secondary)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Child(Primary):
diff --git a/tests/modeltests/delete/models.py b/tests/modeltests/delete/models.py
index f8b78eb7b7..e0cec426ea 100644
--- a/tests/modeltests/delete/models.py
+++ b/tests/modeltests/delete/models.py
@@ -1,6 +1,10 @@
+from __future__ import unicode_literals
+
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class R(models.Model):
is_default = models.BooleanField(default=False)
diff --git a/tests/modeltests/distinct_on_fields/models.py b/tests/modeltests/distinct_on_fields/models.py
index 33665e9624..7982f435d0 100644
--- a/tests/modeltests/distinct_on_fields/models.py
+++ b/tests/modeltests/distinct_on_fields/models.py
@@ -1,7 +1,9 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=10)
parent = models.ForeignKey('self', blank=True, null=True,
@@ -10,19 +12,21 @@ class Tag(models.Model):
class Meta:
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Celebrity(models.Model):
name = models.CharField("Name", max_length=20)
greatest_fan = models.ForeignKey("Fan", null=True, unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Fan(models.Model):
fan_of = models.ForeignKey(Celebrity)
+@python_2_unicode_compatible
class Staff(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50)
@@ -30,12 +34,13 @@ class Staff(models.Model):
tags = models.ManyToManyField(Tag, through='StaffTag')
coworkers = models.ManyToManyField('self')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class StaffTag(models.Model):
staff = models.ForeignKey(Staff)
tag = models.ForeignKey(Tag)
- def __unicode__(self):
+ def __str__(self):
return "%s -> %s" % (self.tag, self.staff)
diff --git a/tests/modeltests/expressions/models.py b/tests/modeltests/expressions/models.py
index 018a0cf795..f592a0eb13 100644
--- a/tests/modeltests/expressions/models.py
+++ b/tests/modeltests/expressions/models.py
@@ -4,15 +4,18 @@ Tests for F() query expression syntax.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Employee(models.Model):
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.firstname, self.lastname)
+@python_2_unicode_compatible
class Company(models.Model):
name = models.CharField(max_length=100)
num_employees = models.PositiveIntegerField()
@@ -25,5 +28,5 @@ class Company(models.Model):
related_name='company_point_of_contact_set',
null=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/field_defaults/models.py b/tests/modeltests/field_defaults/models.py
index 18840c8b4b..c99d4871cd 100644
--- a/tests/modeltests/field_defaults/models.py
+++ b/tests/modeltests/field_defaults/models.py
@@ -13,11 +13,13 @@ field.
from datetime import datetime
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField(default=datetime.now)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/field_subclassing/fields.py b/tests/modeltests/field_subclassing/fields.py
index 0d4ff98aa7..a3867e3671 100644
--- a/tests/modeltests/field_subclassing/fields.py
+++ b/tests/modeltests/field_subclassing/fields.py
@@ -5,8 +5,10 @@ import json
from django.db import models
from django.utils.encoding import force_text
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Small(object):
"""
A simple class to show that non-trivial Python objects can be used as
@@ -15,19 +17,15 @@ class Small(object):
def __init__(self, first, second):
self.first, self.second = first, second
- def __unicode__(self):
- return '%s%s' % (force_text(self.first), force_text(self.second))
-
def __str__(self):
- return six.text_type(self).encode('utf-8')
+ return '%s%s' % (force_text(self.first), force_text(self.second))
-class SmallField(models.Field):
+class SmallField(six.with_metaclass(models.SubfieldBase, models.Field)):
"""
Turns the "Small" class into a Django field. Because of the similarities
with normal character fields and the fact that Small.__unicode__ does
something sensible, we don't need to implement a lot here.
"""
- __metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 2
@@ -57,8 +55,7 @@ class SmallerField(SmallField):
pass
-class JSONField(models.TextField):
- __metaclass__ = models.SubfieldBase
+class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)):
description = ("JSONField automatically serializes and desializes values to "
"and from JSON.")
diff --git a/tests/modeltests/field_subclassing/models.py b/tests/modeltests/field_subclassing/models.py
index 2df9664cdc..642573cc83 100644
--- a/tests/modeltests/field_subclassing/models.py
+++ b/tests/modeltests/field_subclassing/models.py
@@ -8,13 +8,15 @@ from django.db import models
from django.utils.encoding import force_text
from .fields import SmallField, SmallerField, JSONField
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class MyModel(models.Model):
name = models.CharField(max_length=10)
data = SmallField('small field')
- def __unicode__(self):
+ def __str__(self):
return force_text(self.name)
class OtherModel(models.Model):
diff --git a/tests/modeltests/files/tests.py b/tests/modeltests/files/tests.py
index 565d4c8942..71ca103205 100644
--- a/tests/modeltests/files/tests.py
+++ b/tests/modeltests/files/tests.py
@@ -20,7 +20,7 @@ class FileStorageTests(TestCase):
shutil.rmtree(temp_storage_location)
def test_files(self):
- temp_storage.save('tests/default.txt', ContentFile(b'default content'))
+ temp_storage.save('tests/default.txt', ContentFile('default content'))
# Attempting to access a FileField from the class raises a descriptive
# error
self.assertRaises(AttributeError, lambda: Storage.normal)
@@ -31,7 +31,7 @@ class FileStorageTests(TestCase):
self.assertRaises(ValueError, lambda: obj1.normal.size)
# Saving a file enables full functionality.
- obj1.normal.save("django_test.txt", ContentFile(b"content"))
+ obj1.normal.save("django_test.txt", ContentFile("content"))
self.assertEqual(obj1.normal.name, "tests/django_test.txt")
self.assertEqual(obj1.normal.size, 7)
self.assertEqual(obj1.normal.read(), b"content")
@@ -59,7 +59,7 @@ class FileStorageTests(TestCase):
# Save another file with the same name.
obj2 = Storage()
- obj2.normal.save("django_test.txt", ContentFile(b"more content"))
+ obj2.normal.save("django_test.txt", ContentFile("more content"))
self.assertEqual(obj2.normal.name, "tests/django_test_1.txt")
self.assertEqual(obj2.normal.size, 12)
@@ -70,13 +70,13 @@ class FileStorageTests(TestCase):
# Deleting an object does not delete the file it uses.
obj2.delete()
- obj2.normal.save("django_test.txt", ContentFile(b"more content"))
+ obj2.normal.save("django_test.txt", ContentFile("more content"))
self.assertEqual(obj2.normal.name, "tests/django_test_2.txt")
# Multiple files with the same name get _N appended to them.
objs = [Storage() for i in range(3)]
for o in objs:
- o.normal.save("multiple_files.txt", ContentFile(b"Same Content"))
+ o.normal.save("multiple_files.txt", ContentFile("Same Content"))
self.assertEqual(
[o.normal.name for o in objs],
["tests/multiple_files.txt", "tests/multiple_files_1.txt", "tests/multiple_files_2.txt"]
@@ -100,7 +100,7 @@ class FileStorageTests(TestCase):
# Verify the fix for #5655, making sure the directory is only
# determined once.
obj4 = Storage()
- obj4.random.save("random_file", ContentFile(b"random content"))
+ obj4.random.save("random_file", ContentFile("random content"))
self.assertTrue(obj4.random.name.endswith("/random_file"))
def test_max_length(self):
@@ -135,6 +135,6 @@ class FileTests(unittest.TestCase):
def test_file_mode(self):
# Should not set mode to None if it is not present.
# See #14681, stdlib gzip module crashes if mode is set to None
- file = SimpleUploadedFile("mode_test.txt", "content")
+ file = SimpleUploadedFile("mode_test.txt", b"content")
self.assertFalse(hasattr(file, 'mode'))
g = gzip.GzipFile(fileobj=file)
diff --git a/tests/modeltests/fixtures/models.py b/tests/modeltests/fixtures/models.py
index 586f65e60f..8bd3501926 100644
--- a/tests/modeltests/fixtures/models.py
+++ b/tests/modeltests/fixtures/models.py
@@ -12,38 +12,43 @@ from django.contrib.auth.models import Permission
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Category(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
- def __unicode__(self):
+ def __str__(self):
return self.title
class Meta:
ordering = ('title',)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
ordering = ('-pub_date', 'headline')
+@python_2_unicode_compatible
class Blog(models.Model):
name = models.CharField(max_length=100)
featured = models.ForeignKey(Article, related_name='fixtures_featured_set')
articles = models.ManyToManyField(Article, blank=True,
related_name='fixtures_articles_set')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=100)
tagged_type = models.ForeignKey(ContentType, related_name="fixtures_tag_set")
@@ -51,7 +56,7 @@ class Tag(models.Model):
tagged = generic.GenericForeignKey(ct_field='tagged_type',
fk_field='tagged_id')
- def __unicode__(self):
+ def __str__(self):
return '<%s: %s> tagged "%s"' % (self.tagged.__class__.__name__,
self.tagged, self.name)
@@ -59,10 +64,11 @@ class PersonManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)
+@python_2_unicode_compatible
class Person(models.Model):
objects = PersonManager()
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
@@ -79,19 +85,21 @@ class Spy(Person):
objects = SpyManager()
cover_blown = models.BooleanField(default=False)
+@python_2_unicode_compatible
class Visa(models.Model):
person = models.ForeignKey(Person)
permissions = models.ManyToManyField(Permission, blank=True)
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.person.name,
', '.join(p.name for p in self.permissions.all()))
+@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Person)
- def __unicode__(self):
+ def __str__(self):
authors = ' and '.join(a.name for a in self.authors.all())
return '%s by %s' % (self.name, authors) if authors else self.name
diff --git a/tests/modeltests/fixtures_model_package/models/__init__.py b/tests/modeltests/fixtures_model_package/models/__init__.py
index d309165e9c..deeba48aa9 100644
--- a/tests/modeltests/fixtures_model_package/models/__init__.py
+++ b/tests/modeltests/fixtures_model_package/models/__init__.py
@@ -1,11 +1,13 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py
index f2dcf7db24..2f025e660b 100644
--- a/tests/modeltests/generic_relations/models.py
+++ b/tests/modeltests/generic_relations/models.py
@@ -14,8 +14,10 @@ from __future__ import unicode_literals
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class TaggedItem(models.Model):
"""A tag on an item."""
tag = models.SlugField()
@@ -27,12 +29,13 @@ class TaggedItem(models.Model):
class Meta:
ordering = ["tag", "content_type__name"]
- def __unicode__(self):
+ def __str__(self):
return self.tag
class ValuableTaggedItem(TaggedItem):
value = models.PositiveIntegerField()
+@python_2_unicode_compatible
class Comparison(models.Model):
"""
A model that tests having multiple GenericForeignKeys
@@ -48,9 +51,10 @@ class Comparison(models.Model):
first_obj = generic.GenericForeignKey(ct_field="content_type1", fk_field="object_id1")
other_obj = generic.GenericForeignKey(ct_field="content_type2", fk_field="object_id2")
- def __unicode__(self):
+ def __str__(self):
return "%s is %s than %s" % (self.first_obj, self.comparative, self.other_obj)
+@python_2_unicode_compatible
class Animal(models.Model):
common_name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
@@ -60,25 +64,27 @@ class Animal(models.Model):
object_id_field="object_id1",
content_type_field="content_type1")
- def __unicode__(self):
+ def __str__(self):
return self.common_name
+@python_2_unicode_compatible
class Vegetable(models.Model):
name = models.CharField(max_length=150)
is_yucky = models.BooleanField(default=True)
tags = generic.GenericRelation(TaggedItem)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Mineral(models.Model):
name = models.CharField(max_length=150)
hardness = models.PositiveSmallIntegerField()
# note the lack of an explicit GenericRelation here...
- def __unicode__(self):
+ def __str__(self):
return self.name
class GeckoManager(models.Manager):
diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py
index d8a690f48c..fe594dd802 100644
--- a/tests/modeltests/get_latest/models.py
+++ b/tests/modeltests/get_latest/models.py
@@ -9,8 +9,10 @@ farthest into the future."
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
@@ -18,14 +20,15 @@ class Article(models.Model):
class Meta:
get_latest_by = 'pub_date'
- def __unicode__(self):
+ def __str__(self):
return self.headline
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=30)
birthday = models.DateField()
# Note that this model doesn't have "get_latest_by" set.
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/get_object_or_404/models.py b/tests/modeltests/get_object_or_404/models.py
index f0c73ed94a..bda060569e 100644
--- a/tests/modeltests/get_object_or_404/models.py
+++ b/tests/modeltests/get_object_or_404/models.py
@@ -11,23 +11,26 @@ performing a ``filter()`` lookup and raising a ``Http404`` exception if a
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
class ArticleManager(models.Manager):
def get_query_set(self):
return super(ArticleManager, self).get_query_set().filter(authors__name__icontains='sir')
+@python_2_unicode_compatible
class Article(models.Model):
authors = models.ManyToManyField(Author)
title = models.CharField(max_length=50)
objects = models.Manager()
by_a_sir = ArticleManager()
- def __unicode__(self):
+ def __str__(self):
return self.title
diff --git a/tests/modeltests/get_or_create/models.py b/tests/modeltests/get_or_create/models.py
index 78b92f09df..678f5a401c 100644
--- a/tests/modeltests/get_or_create/models.py
+++ b/tests/modeltests/get_or_create/models.py
@@ -9,14 +9,16 @@ parameters.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
birthday = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
class ManualPrimaryKeyTest(models.Model):
diff --git a/tests/modeltests/invalid_models/tests.py b/tests/modeltests/invalid_models/tests.py
index 9d7adb045c..e1fc68743e 100644
--- a/tests/modeltests/invalid_models/tests.py
+++ b/tests/modeltests/invalid_models/tests.py
@@ -1,11 +1,11 @@
import copy
import sys
-from io import BytesIO
from django.core.management.validation import get_validation_errors
from django.db.models.loading import cache, load_app
from django.utils import unittest
+from django.utils.six import StringIO
class InvalidModelTestCase(unittest.TestCase):
@@ -16,7 +16,7 @@ class InvalidModelTestCase(unittest.TestCase):
# coloring attached (makes matching the results easier). We restore
# sys.stderr afterwards.
self.old_stdout = sys.stdout
- self.stdout = BytesIO()
+ self.stdout = StringIO()
sys.stdout = self.stdout
# This test adds dummy applications to the app cache. These
diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py
index b685750347..f388ddf403 100644
--- a/tests/modeltests/lookup/models.py
+++ b/tests/modeltests/lookup/models.py
@@ -8,6 +8,7 @@ from __future__ import unicode_literals
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class Author(models.Model):
@@ -15,6 +16,7 @@ class Author(models.Model):
class Meta:
ordering = ('name', )
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
@@ -22,7 +24,7 @@ class Article(models.Model):
class Meta:
ordering = ('-pub_date', 'headline')
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Tag(models.Model):
@@ -31,24 +33,27 @@ class Tag(models.Model):
class Meta:
ordering = ('name', )
+@python_2_unicode_compatible
class Season(models.Model):
year = models.PositiveSmallIntegerField()
gt = models.IntegerField(null=True, blank=True)
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.year)
+@python_2_unicode_compatible
class Game(models.Model):
season = models.ForeignKey(Season, related_name='games')
home = models.CharField(max_length=100)
away = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return "%s at %s" % (self.away, self.home)
+@python_2_unicode_compatible
class Player(models.Model):
name = models.CharField(max_length=100)
games = models.ManyToManyField(Game, related_name='players')
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py
index 92ed3fbcd9..99c7b01017 100644
--- a/tests/modeltests/m2m_and_m2o/models.py
+++ b/tests/modeltests/m2m_and_m2o/models.py
@@ -7,17 +7,19 @@ from __future__ import unicode_literals
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class User(models.Model):
username = models.CharField(max_length=20)
+@python_2_unicode_compatible
class Issue(models.Model):
num = models.IntegerField()
cc = models.ManyToManyField(User, blank=True, related_name='test_issue_cc')
client = models.ForeignKey(User, related_name='test_issue_client')
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.num)
class Meta:
diff --git a/tests/modeltests/m2m_intermediary/models.py b/tests/modeltests/m2m_intermediary/models.py
index 85786e8458..e9ae422afb 100644
--- a/tests/modeltests/m2m_intermediary/models.py
+++ b/tests/modeltests/m2m_intermediary/models.py
@@ -12,27 +12,31 @@ field, which specifies the ``Reporter``'s position for the given article
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
+@python_2_unicode_compatible
class Writer(models.Model):
reporter = models.ForeignKey(Reporter)
article = models.ForeignKey(Article)
position = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return '%s (%s)' % (self.reporter, self.position)
diff --git a/tests/modeltests/m2m_multiple/models.py b/tests/modeltests/m2m_multiple/models.py
index 3efe7108b9..c2e3b030a4 100644
--- a/tests/modeltests/m2m_multiple/models.py
+++ b/tests/modeltests/m2m_multiple/models.py
@@ -8,16 +8,19 @@ Set ``related_name`` to designate what the reverse relationship is called.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
@@ -26,6 +29,6 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date',)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py
index 83c943ae60..b69930208c 100644
--- a/tests/modeltests/m2m_recursive/models.py
+++ b/tests/modeltests/m2m_recursive/models.py
@@ -17,12 +17,14 @@ appropriate.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=20)
friends = models.ManyToManyField('self')
idols = models.ManyToManyField('self', symmetrical=False, related_name='stalkers')
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/m2m_signals/models.py b/tests/modeltests/m2m_signals/models.py
index 526c4a782e..e997d87f21 100644
--- a/tests/modeltests/m2m_signals/models.py
+++ b/tests/modeltests/m2m_signals/models.py
@@ -1,15 +1,18 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Part(models.Model):
name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Car(models.Model):
name = models.CharField(max_length=20)
default_parts = models.ManyToManyField(Part)
@@ -18,12 +21,13 @@ class Car(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
class SportsCar(Car):
price = models.IntegerField()
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=20)
fans = models.ManyToManyField('self', related_name='idols', symmetrical=False)
@@ -32,5 +36,5 @@ class Person(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/m2m_through/models.py b/tests/modeltests/m2m_through/models.py
index aa71a049cb..a896f6d9ff 100644
--- a/tests/modeltests/m2m_through/models.py
+++ b/tests/modeltests/m2m_through/models.py
@@ -1,18 +1,21 @@
from datetime import datetime
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# M2M described on one of the models
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=128)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
@@ -22,9 +25,10 @@ class Group(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
@@ -34,16 +38,17 @@ class Membership(models.Model):
class Meta:
ordering = ('date_joined', 'invite_reason', 'group')
- def __unicode__(self):
+ def __str__(self):
return "%s is a member of %s" % (self.person.name, self.group.name)
+@python_2_unicode_compatible
class CustomMembership(models.Model):
person = models.ForeignKey(Person, db_column="custom_person_column", related_name="custom_person_related_name")
group = models.ForeignKey(Group)
weird_fk = models.ForeignKey(Membership, null=True)
date_joined = models.DateTimeField(default=datetime.now)
- def __unicode__(self):
+ def __str__(self):
return "%s is a member of %s" % (self.person.name, self.group.name)
class Meta:
@@ -54,11 +59,12 @@ class TestNoDefaultsOrNulls(models.Model):
group = models.ForeignKey(Group)
nodefaultnonull = models.CharField(max_length=5)
+@python_2_unicode_compatible
class PersonSelfRefM2M(models.Model):
name = models.CharField(max_length=5)
friends = models.ManyToManyField('self', through="Friendship", symmetrical=False)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Friendship(models.Model):
diff --git a/tests/modeltests/m2o_recursive/models.py b/tests/modeltests/m2o_recursive/models.py
index c0a4bdeec2..2775d713dd 100644
--- a/tests/modeltests/m2o_recursive/models.py
+++ b/tests/modeltests/m2o_recursive/models.py
@@ -11,19 +11,22 @@ Set ``related_name`` to designate what the reverse relationship is called.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=20)
parent = models.ForeignKey('self', blank=True, null=True, related_name='child_set')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Person(models.Model):
full_name = models.CharField(max_length=20)
mother = models.ForeignKey('self', null=True, related_name='mothers_child_set')
father = models.ForeignKey('self', null=True, related_name='fathers_child_set')
- def __unicode__(self):
+ def __str__(self):
return self.full_name
diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py
index 5076e35653..a196c85092 100644
--- a/tests/modeltests/many_to_many/models.py
+++ b/tests/modeltests/many_to_many/models.py
@@ -8,22 +8,25 @@ objects, and a ``Publication`` has multiple ``Article`` objects.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Publication(models.Model):
title = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return self.title
class Meta:
ordering = ('title',)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py
index 0d2688e8a4..4e2ed67eea 100644
--- a/tests/modeltests/many_to_one/models.py
+++ b/tests/modeltests/many_to_one/models.py
@@ -6,22 +6,25 @@ To define a many-to-one relationship, use ``ForeignKey()``.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/modeltests/many_to_one_null/models.py b/tests/modeltests/many_to_one_null/models.py
index be7e650c65..e00ca85928 100644
--- a/tests/modeltests/many_to_one_null/models.py
+++ b/tests/modeltests/many_to_one_null/models.py
@@ -6,14 +6,17 @@ To define a many-to-one relationship that can have a null foreign key, use
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Reporter(models.Model):
name = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
reporter = models.ForeignKey(Reporter, null=True)
@@ -21,5 +24,5 @@ class Article(models.Model):
class Meta:
ordering = ('headline',)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 8942b21f73..90b019b611 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -14,6 +14,7 @@ import tempfile
from django.core.files.storage import FileSystemStorage
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
temp_storage_dir = tempfile.mkdtemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
@@ -31,23 +32,29 @@ ARTICLE_STATUS_CHAR = (
('l', 'Live'),
)
+@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=20)
url = models.CharField('The URL', max_length=40)
- def __unicode__(self):
+ def __str__(self):
return self.name
+ def __repr__(self):
+ return self.__str__()
+
+@python_2_unicode_compatible
class Writer(models.Model):
name = models.CharField(max_length=50, help_text='Use both first and last names.')
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=50)
slug = models.SlugField()
@@ -64,7 +71,7 @@ class Article(models.Model):
self.created = datetime.date.today()
return super(Article, self).save()
- def __unicode__(self):
+ def __str__(self):
return self.headline
class ImprovedArticle(models.Model):
@@ -76,26 +83,29 @@ class ImprovedArticleWithParentLink(models.Model):
class BetterWriter(Writer):
score = models.IntegerField()
+@python_2_unicode_compatible
class WriterProfile(models.Model):
writer = models.OneToOneField(Writer, primary_key=True)
age = models.PositiveIntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s is %s" % (self.writer, self.age)
from django.contrib.localflavor.us.models import PhoneNumberField
+@python_2_unicode_compatible
class PhoneNumber(models.Model):
phone = PhoneNumberField()
description = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return self.phone
+@python_2_unicode_compatible
class TextFile(models.Model):
description = models.CharField(max_length=20)
file = models.FileField(storage=temp_storage, upload_to='tests', max_length=15)
- def __unicode__(self):
+ def __str__(self):
return self.description
try:
@@ -110,6 +120,7 @@ try:
test_images = True
+ @python_2_unicode_compatible
class ImageFile(models.Model):
def custom_upload_path(self, filename):
path = self.path or 'tests'
@@ -125,9 +136,10 @@ try:
width_field='width', height_field='height')
path = models.CharField(max_length=16, blank=True, default='')
- def __unicode__(self):
+ def __str__(self):
return self.description
+ @python_2_unicode_compatible
class OptionalImageFile(models.Model):
def custom_upload_path(self, filename):
path = self.path or 'tests'
@@ -141,28 +153,31 @@ try:
height = models.IntegerField(editable=False, null=True)
path = models.CharField(max_length=16, blank=True, default='')
- def __unicode__(self):
+ def __str__(self):
return self.description
except ImportError:
test_images = False
+@python_2_unicode_compatible
class CommaSeparatedInteger(models.Model):
field = models.CommaSeparatedIntegerField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return self.field
+@python_2_unicode_compatible
class Product(models.Model):
slug = models.SlugField(unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.slug
+@python_2_unicode_compatible
class Price(models.Model):
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.PositiveIntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s for %s" % (self.quantity, self.price)
class Meta:
@@ -171,6 +186,7 @@ class Price(models.Model):
class ArticleStatus(models.Model):
status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True)
+@python_2_unicode_compatible
class Inventory(models.Model):
barcode = models.PositiveIntegerField(unique=True)
parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True)
@@ -179,9 +195,12 @@ class Inventory(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+ def __repr__(self):
+ return self.__str__()
+
class Book(models.Model):
title = models.CharField(max_length=40)
author = models.ForeignKey(Writer, blank=True, null=True)
@@ -202,31 +221,34 @@ class BookXtra(models.Model):
class DerivedBook(Book, BookXtra):
pass
+@python_2_unicode_compatible
class ExplicitPK(models.Model):
key = models.CharField(max_length=20, primary_key=True)
desc = models.CharField(max_length=20, blank=True, unique=True)
class Meta:
unique_together = ('key', 'desc')
- def __unicode__(self):
+ def __str__(self):
return self.key
+@python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
posted = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.name
class DerivedPost(Post):
pass
+@python_2_unicode_compatible
class BigInt(models.Model):
biggie = models.BigIntegerField()
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.biggie)
class MarkupField(models.CharField):
diff --git a/tests/modeltests/model_forms/tests.py b/tests/modeltests/model_forms/tests.py
index 1da7f583be..038ce32287 100644
--- a/tests/modeltests/model_forms/tests.py
+++ b/tests/modeltests/model_forms/tests.py
@@ -179,14 +179,14 @@ class PriceFormWithoutQuantity(forms.ModelForm):
class ModelFormBaseTest(TestCase):
def test_base_form(self):
- self.assertEqual(BaseCategoryForm.base_fields.keys(),
+ self.assertEqual(list(BaseCategoryForm.base_fields),
['name', 'slug', 'url'])
def test_extra_fields(self):
class ExtraFields(BaseCategoryForm):
some_extra_field = forms.BooleanField()
- self.assertEqual(ExtraFields.base_fields.keys(),
+ self.assertEqual(list(ExtraFields.base_fields),
['name', 'slug', 'url', 'some_extra_field'])
def test_replace_field(self):
@@ -215,7 +215,7 @@ class ModelFormBaseTest(TestCase):
model = Category
fields = ['url']
- self.assertEqual(LimitFields.base_fields.keys(),
+ self.assertEqual(list(LimitFields.base_fields),
['url'])
def test_exclude_fields(self):
@@ -224,7 +224,7 @@ class ModelFormBaseTest(TestCase):
model = Category
exclude = ['url']
- self.assertEqual(ExcludeFields.base_fields.keys(),
+ self.assertEqual(list(ExcludeFields.base_fields),
['name', 'slug'])
def test_confused_form(self):
@@ -237,7 +237,7 @@ class ModelFormBaseTest(TestCase):
fields = ['name', 'url']
exclude = ['url']
- self.assertEqual(ConfusedForm.base_fields.keys(),
+ self.assertEqual(list(ConfusedForm.base_fields),
['name'])
def test_mixmodel_form(self):
@@ -254,13 +254,13 @@ class ModelFormBaseTest(TestCase):
# overrides BaseCategoryForm.Meta.
self.assertEqual(
- MixModelForm.base_fields.keys(),
+ list(MixModelForm.base_fields),
['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status']
)
def test_article_form(self):
self.assertEqual(
- ArticleForm.base_fields.keys(),
+ list(ArticleForm.base_fields),
['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status']
)
@@ -270,7 +270,7 @@ class ModelFormBaseTest(TestCase):
pass
self.assertEqual(
- BadForm.base_fields.keys(),
+ list(BadForm.base_fields),
['headline', 'slug', 'pub_date', 'writer', 'article', 'categories', 'status']
)
@@ -282,7 +282,7 @@ class ModelFormBaseTest(TestCase):
"""
pass
- self.assertEqual(SubCategoryForm.base_fields.keys(),
+ self.assertEqual(list(SubCategoryForm.base_fields),
['name', 'slug', 'url'])
def test_subclassmeta_form(self):
@@ -312,7 +312,7 @@ class ModelFormBaseTest(TestCase):
model = Category
fields = ['url', 'name']
- self.assertEqual(OrderFields.base_fields.keys(),
+ self.assertEqual(list(OrderFields.base_fields),
['url', 'name'])
self.assertHTMLEqual(
str(OrderFields()),
@@ -327,7 +327,7 @@ class ModelFormBaseTest(TestCase):
fields = ['slug', 'url', 'name']
exclude = ['url']
- self.assertEqual(OrderFields2.base_fields.keys(),
+ self.assertEqual(list(OrderFields2.base_fields),
['slug', 'name'])
@@ -751,9 +751,9 @@ class OldFormForXTests(TestCase):
self.assertEqual(new_art.headline, 'New headline')
# Add some categories and test the many-to-many form output.
- self.assertEqual(map(lambda o: o.name, new_art.categories.all()), [])
+ self.assertQuerysetEqual(new_art.categories.all(), [])
new_art.categories.add(Category.objects.get(name='Entertainment'))
- self.assertEqual(map(lambda o: o.name, new_art.categories.all()), ["Entertainment"])
+ self.assertQuerysetEqual(new_art.categories.all(), ["Entertainment"])
f = TestArticleForm(auto_id=False, instance=new_art)
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
@@ -815,7 +815,7 @@ class OldFormForXTests(TestCase):
new_art = f.save()
self.assertEqual(new_art.id == art_id_1, True)
new_art = Article.objects.get(id=art_id_1)
- self.assertEqual(map(lambda o: o.name, new_art.categories.order_by('name')),
+ self.assertQuerysetEqual(new_art.categories.order_by('name'),
["Entertainment", "It's a test"])
# Now, submit form data with no categories. This deletes the existing categories.
@@ -824,7 +824,7 @@ class OldFormForXTests(TestCase):
new_art = f.save()
self.assertEqual(new_art.id == art_id_1, True)
new_art = Article.objects.get(id=art_id_1)
- self.assertEqual(map(lambda o: o.name, new_art.categories.all()), [])
+ self.assertQuerysetEqual(new_art.categories.all(), [])
# Create a new article, with categories, via the form.
f = ArticleForm({'headline': 'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': '1967-11-01',
@@ -833,7 +833,7 @@ class OldFormForXTests(TestCase):
art_id_2 = new_art.id
self.assertEqual(art_id_2 not in (None, art_id_1), True)
new_art = Article.objects.get(id=art_id_2)
- self.assertEqual(map(lambda o: o.name, new_art.categories.order_by('name')), ["Entertainment", "It's a test"])
+ self.assertQuerysetEqual(new_art.categories.order_by('name'), ["Entertainment", "It's a test"])
# Create a new article, with no categories, via the form.
f = ArticleForm({'headline': 'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': '1967-11-01',
@@ -842,7 +842,7 @@ class OldFormForXTests(TestCase):
art_id_3 = new_art.id
self.assertEqual(art_id_3 not in (None, art_id_1, art_id_2), True)
new_art = Article.objects.get(id=art_id_3)
- self.assertEqual(map(lambda o: o.name, new_art.categories.all()), [])
+ self.assertQuerysetEqual(new_art.categories.all(), [])
# Create a new article, with categories, via the form, but use commit=False.
# The m2m data won't be saved until save_m2m() is invoked on the form.
@@ -857,11 +857,11 @@ class OldFormForXTests(TestCase):
# The instance doesn't have m2m data yet
new_art = Article.objects.get(id=art_id_4)
- self.assertEqual(map(lambda o: o.name, new_art.categories.all()), [])
+ self.assertQuerysetEqual(new_art.categories.all(), [])
# Save the m2m data on the form
f.save_m2m()
- self.assertEqual(map(lambda o: o.name, new_art.categories.order_by('name')), ["Entertainment", "It's a test"])
+ self.assertQuerysetEqual(new_art.categories.order_by('name'), ["Entertainment", "It's a test"])
# Here, we define a custom ModelForm. Because it happens to have the same fields as
# the Category model, we can just call the form's save() to apply its changes to an
@@ -1007,12 +1007,12 @@ class OldFormForXTests(TestCase):
f.clean(None)
with self.assertRaises(ValidationError):
f.clean([])
- self.assertEqual(map(lambda o: o.name, f.clean([c1.id])), ["Entertainment"])
- self.assertEqual(map(lambda o: o.name, f.clean([c2.id])), ["It's a test"])
- self.assertEqual(map(lambda o: o.name, f.clean([str(c1.id)])), ["Entertainment"])
- self.assertEqual(map(lambda o: o.name, f.clean([str(c1.id), str(c2.id)])), ["Entertainment", "It's a test"])
- self.assertEqual(map(lambda o: o.name, f.clean([c1.id, str(c2.id)])), ["Entertainment", "It's a test"])
- self.assertEqual(map(lambda o: o.name, f.clean((c1.id, str(c2.id)))), ["Entertainment", "It's a test"])
+ self.assertQuerysetEqual(f.clean([c1.id]), ["Entertainment"])
+ self.assertQuerysetEqual(f.clean([c2.id]), ["It's a test"])
+ self.assertQuerysetEqual(f.clean([str(c1.id)]), ["Entertainment"])
+ self.assertQuerysetEqual(f.clean([str(c1.id), str(c2.id)]), ["Entertainment", "It's a test"])
+ self.assertQuerysetEqual(f.clean([c1.id, str(c2.id)]), ["Entertainment", "It's a test"])
+ self.assertQuerysetEqual(f.clean((c1.id, str(c2.id))), ["Entertainment", "It's a test"])
with self.assertRaises(ValidationError):
f.clean(['100'])
with self.assertRaises(ValidationError):
@@ -1025,7 +1025,7 @@ class OldFormForXTests(TestCase):
# than caching it at time of instantiation.
c6 = Category.objects.create(id=6, name='Sixth', url='6th')
self.assertEqual(c6.name, 'Sixth')
- self.assertEqual(map(lambda o: o.name, f.clean([c6.id])), ["Sixth"])
+ self.assertQuerysetEqual(f.clean([c6.id]), ["Sixth"])
# Delete a Category object *after* the ModelMultipleChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
@@ -1050,7 +1050,7 @@ class OldFormForXTests(TestCase):
(c1.pk, 'Entertainment'),
(c2.pk, "It's a test"),
(c3.pk, 'Third')])
- self.assertEqual(map(lambda o: o.name, f.clean([c3.id])), ["Third"])
+ self.assertQuerysetEqual(f.clean([c3.id]), ["Third"])
with self.assertRaises(ValidationError):
f.clean([c4.id])
with self.assertRaises(ValidationError):
@@ -1066,13 +1066,13 @@ class OldFormForXTests(TestCase):
# OneToOneField ###############################################################
- self.assertEqual(ImprovedArticleForm.base_fields.keys(), ['article'])
+ self.assertEqual(list(ImprovedArticleForm.base_fields), ['article'])
- self.assertEqual(ImprovedArticleWithParentLinkForm.base_fields.keys(), [])
+ self.assertEqual(list(ImprovedArticleWithParentLinkForm.base_fields), [])
bw = BetterWriter(name='Joe Better', score=10)
bw.save()
- self.assertEqual(sorted(model_to_dict(bw).keys()),
+ self.assertEqual(sorted(model_to_dict(bw)),
['id', 'name', 'score', 'writer_ptr'])
form = BetterWriterForm({'name': 'Some Name', 'score': 12})
@@ -1463,7 +1463,7 @@ class OldFormForXTests(TestCase):
model = Category
fields = ['description', 'url']
- self.assertEqual(CategoryForm.base_fields.keys(),
+ self.assertEqual(list(CategoryForm.base_fields),
['description', 'url'])
self.assertHTMLEqual(six.text_type(CategoryForm()), '''<tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr>
@@ -1472,14 +1472,15 @@ class OldFormForXTests(TestCase):
field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode')
self.assertEqual(tuple(field.choices), ((86, 'Apple'), (87, 'Core'), (22, 'Pear')))
- self.assertEqual(map(lambda o: o.name, field.clean([86])), ['Apple'])
+ self.assertQuerysetEqual(field.clean([86]), ['Apple'])
form = SelectInventoryForm({'items': [87, 22]})
self.assertEqual(form.is_valid(), True)
self.assertEqual(len(form.cleaned_data), 1)
- self.assertEqual(map(lambda o: o.name, form.cleaned_data['items']), ['Core', 'Pear'])
+ self.assertQuerysetEqual(form.cleaned_data['items'], ['Core', 'Pear'])
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self):
- self.assertEqual(CustomFieldForExclusionForm.base_fields.keys(), ['name'])
+ self.assertEqual(list(CustomFieldForExclusionForm.base_fields),
+ ['name'])
self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()),
'''<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>''')
diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
index a01a2da0fa..ae152448ab 100644
--- a/tests/modeltests/model_formsets/models.py
+++ b/tests/modeltests/model_formsets/models.py
@@ -4,20 +4,23 @@ import datetime
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
class BetterAuthor(Author):
write_speed = models.IntegerField()
+@python_2_unicode_compatible
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
@@ -28,20 +31,22 @@ class Book(models.Model):
)
ordering = ['id']
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class BookWithCustomPK(models.Model):
my_pk = models.DecimalField(max_digits=5, decimal_places=0, primary_key=True)
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return '%s: %s' % (self.my_pk, self.title)
class Editor(models.Model):
name = models.CharField(max_length=100)
+@python_2_unicode_compatible
class BookWithOptionalAltEditor(models.Model):
author = models.ForeignKey(Author)
# Optional secondary author
@@ -53,21 +58,23 @@ class BookWithOptionalAltEditor(models.Model):
('author', 'title', 'alt_editor'),
)
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class AlternateBook(Book):
notes = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return '%s - %s' % (self.title, self.notes)
+@python_2_unicode_compatible
class AuthorMeeting(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
created = models.DateField(editable=False)
- def __unicode__(self):
+ def __str__(self):
return self.name
class CustomPrimaryKey(models.Model):
@@ -77,19 +84,21 @@ class CustomPrimaryKey(models.Model):
# models for inheritance tests.
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
city = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Owner(models.Model):
auto_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
place = models.ForeignKey(Place)
- def __unicode__(self):
+ def __str__(self):
return "%s at %s" % (self.name, self.place)
class Location(models.Model):
@@ -98,30 +107,34 @@ class Location(models.Model):
lat = models.CharField(max_length=100)
lon = models.CharField(max_length=100)
+@python_2_unicode_compatible
class OwnerProfile(models.Model):
owner = models.OneToOneField(Owner, primary_key=True)
age = models.PositiveIntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s is %d" % (self.owner.name, self.age)
+@python_2_unicode_compatible
class Restaurant(Place):
serves_pizza = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Product(models.Model):
slug = models.SlugField(unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.slug
+@python_2_unicode_compatible
class Price(models.Model):
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.PositiveIntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s for %s" % (self.quantity, self.price)
class Meta:
@@ -136,12 +149,14 @@ class ClassyMexicanRestaurant(MexicanRestaurant):
# models for testing unique_together validation when a fk is involved and
# using inlineformset_factory.
+@python_2_unicode_compatible
class Repository(models.Model):
name = models.CharField(max_length=25)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Revision(models.Model):
repository = models.ForeignKey(Repository)
revision = models.CharField(max_length=40)
@@ -149,7 +164,7 @@ class Revision(models.Model):
class Meta:
unique_together = (("repository", "revision"),)
- def __unicode__(self):
+ def __str__(self):
return "%s (%s)" % (self.revision, six.text_type(self.repository))
# models for testing callable defaults (see bug #7975). If you define a model
@@ -167,32 +182,36 @@ class Membership(models.Model):
class Team(models.Model):
name = models.CharField(max_length=100)
+@python_2_unicode_compatible
class Player(models.Model):
team = models.ForeignKey(Team, null=True)
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
# Models for testing custom ModelForm save methods in formsets and inline formsets
+@python_2_unicode_compatible
class Poet(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Poem(models.Model):
poet = models.ForeignKey(Poet)
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
posted = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py
index 37ca603021..2101f394f7 100644
--- a/tests/modeltests/model_inheritance/models.py
+++ b/tests/modeltests/model_inheritance/models.py
@@ -14,11 +14,13 @@ Both styles are demonstrated here.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
#
# Abstract base classes
#
+@python_2_unicode_compatible
class CommonInfo(models.Model):
name = models.CharField(max_length=50)
age = models.PositiveIntegerField()
@@ -27,7 +29,7 @@ class CommonInfo(models.Model):
abstract = True
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.__class__.__name__, self.name)
class Worker(CommonInfo):
@@ -49,6 +51,7 @@ class StudentWorker(Student, Worker):
class Post(models.Model):
title = models.CharField(max_length=50)
+@python_2_unicode_compatible
class Attachment(models.Model):
post = models.ForeignKey(Post, related_name='attached_%(class)s_set')
content = models.TextField()
@@ -56,7 +59,7 @@ class Attachment(models.Model):
class Meta:
abstract = True
- def __unicode__(self):
+ def __str__(self):
return self.content
class Comment(Attachment):
@@ -69,17 +72,19 @@ class Link(Attachment):
# Multi-table inheritance
#
+@python_2_unicode_compatible
class Chef(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "%s the chef" % self.name
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
- def __unicode__(self):
+ def __str__(self):
return "%s the place" % self.name
class Rating(models.Model):
@@ -89,6 +94,7 @@ class Rating(models.Model):
abstract = True
ordering = ['-rating']
+@python_2_unicode_compatible
class Restaurant(Place, Rating):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
@@ -97,27 +103,30 @@ class Restaurant(Place, Rating):
class Meta(Rating.Meta):
db_table = 'my_restaurant'
- def __unicode__(self):
+ def __str__(self):
return "%s the restaurant" % self.name
+@python_2_unicode_compatible
class ItalianRestaurant(Restaurant):
serves_gnocchi = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the italian restaurant" % self.name
+@python_2_unicode_compatible
class Supplier(Place):
customers = models.ManyToManyField(Restaurant, related_name='provider')
- def __unicode__(self):
+ def __str__(self):
return "%s the supplier" % self.name
+@python_2_unicode_compatible
class ParkingLot(Place):
# An explicit link to the parent (we can control the attribute name).
parent = models.OneToOneField(Place, primary_key=True, parent_link=True)
main_site = models.ForeignKey(Place, related_name='lot')
- def __unicode__(self):
+ def __str__(self):
return "%s the parking lot" % self.name
#
@@ -139,10 +148,11 @@ class NamedURL(models.Model):
class Meta:
abstract = True
+@python_2_unicode_compatible
class Copy(NamedURL):
content = models.TextField()
- def __unicode__(self):
+ def __str__(self):
return self.content
class Mixin(object):
diff --git a/tests/modeltests/model_inheritance_same_model_name/models.py b/tests/modeltests/model_inheritance_same_model_name/models.py
index de7541694a..801724df18 100644
--- a/tests/modeltests/model_inheritance_same_model_name/models.py
+++ b/tests/modeltests/model_inheritance_same_model_name/models.py
@@ -11,12 +11,14 @@ from __future__ import absolute_import
from django.db import models
from ..model_inheritance.models import NamedURL
+from django.utils.encoding import python_2_unicode_compatible
#
# Abstract base classes with related models
#
+@python_2_unicode_compatible
class Copy(NamedURL):
content = models.TextField()
- def __unicode__(self):
+ def __str__(self):
return self.content
diff --git a/tests/modeltests/one_to_one/models.py b/tests/modeltests/one_to_one/models.py
index 8c6d56a795..9599496cb7 100644
--- a/tests/modeltests/one_to_one/models.py
+++ b/tests/modeltests/one_to_one/models.py
@@ -8,28 +8,32 @@ In this example, a ``Place`` optionally can be a ``Restaurant``.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
- def __unicode__(self):
+ def __str__(self):
return "%s the place" % self.name
+@python_2_unicode_compatible
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the restaurant" % self.place.name
+@python_2_unicode_compatible
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "%s the waiter at %s" % (self.name, self.restaurant)
class ManualPrimaryKey(models.Model):
@@ -40,10 +44,11 @@ class RelatedModel(models.Model):
link = models.OneToOneField(ManualPrimaryKey)
name = models.CharField(max_length = 50)
+@python_2_unicode_compatible
class MultiModel(models.Model):
link1 = models.OneToOneField(Place)
link2 = models.OneToOneField(ManualPrimaryKey)
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "Multimodel %s" % self.name
diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py
index 0037b41afb..f146b2e72d 100644
--- a/tests/modeltests/or_lookups/models.py
+++ b/tests/modeltests/or_lookups/models.py
@@ -10,8 +10,10 @@ clauses using the variable ``django.db.models.Q`` (or any object with an
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=50)
pub_date = models.DateTimeField()
@@ -19,5 +21,5 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date',)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/order_with_respect_to/models.py b/tests/modeltests/order_with_respect_to/models.py
index a4e20c2fe0..06bb56b141 100644
--- a/tests/modeltests/order_with_respect_to/models.py
+++ b/tests/modeltests/order_with_respect_to/models.py
@@ -4,11 +4,13 @@ Tests for the order_with_respect_to Meta attribute.
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class Question(models.Model):
text = models.CharField(max_length=200)
+@python_2_unicode_compatible
class Answer(models.Model):
text = models.CharField(max_length=200)
question = models.ForeignKey(Question)
@@ -16,9 +18,10 @@ class Answer(models.Model):
class Meta:
order_with_respect_to = 'question'
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.text)
+@python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=200)
parent = models.ForeignKey("self", related_name="children", null=True)
@@ -26,5 +29,5 @@ class Post(models.Model):
class Meta:
order_with_respect_to = "parent"
- def __unicode__(self):
+ def __str__(self):
return self.title
diff --git a/tests/modeltests/ordering/models.py b/tests/modeltests/ordering/models.py
index bfb4b97107..67126e1bda 100644
--- a/tests/modeltests/ordering/models.py
+++ b/tests/modeltests/ordering/models.py
@@ -14,22 +14,25 @@ undefined -- not random, just undefined.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
class Meta:
ordering = ('-pub_date', 'headline')
- def __unicode__(self):
+ def __str__(self):
return self.headline
+@python_2_unicode_compatible
class ArticlePKOrdering(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
class Meta:
ordering = ('-pk',)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py
index 48484dd59b..779d3029ba 100644
--- a/tests/modeltests/pagination/models.py
+++ b/tests/modeltests/pagination/models.py
@@ -7,11 +7,13 @@ objects into easily readable pages.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/modeltests/pagination/tests.py b/tests/modeltests/pagination/tests.py
index cba8825ec4..12ce0e3ecb 100644
--- a/tests/modeltests/pagination/tests.py
+++ b/tests/modeltests/pagination/tests.py
@@ -28,7 +28,7 @@ class PaginationTests(TestCase):
paginator = Paginator(Article.objects.all(), 5)
self.assertEqual(9, paginator.count)
self.assertEqual(2, paginator.num_pages)
- self.assertEqual([1, 2], paginator.page_range)
+ self.assertEqual([1, 2], list(paginator.page_range))
def test_first_page(self):
paginator = Paginator(Article.objects.all(), 5)
@@ -78,13 +78,13 @@ class PaginationTests(TestCase):
paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=True)
self.assertEqual(0, paginator.count)
self.assertEqual(1, paginator.num_pages)
- self.assertEqual([1], paginator.page_range)
+ self.assertEqual([1], list(paginator.page_range))
# Empty paginators with allow_empty_first_page=False.
paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=False)
self.assertEqual(0, paginator.count)
self.assertEqual(0, paginator.num_pages)
- self.assertEqual([], paginator.page_range)
+ self.assertEqual([], list(paginator.page_range))
def test_invalid_page(self):
paginator = Paginator(Article.objects.all(), 5)
@@ -108,7 +108,7 @@ class PaginationTests(TestCase):
paginator = Paginator([1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
self.assertEqual(9, paginator.count)
self.assertEqual(3, paginator.num_pages)
- self.assertEqual([1, 2, 3], paginator.page_range)
+ self.assertEqual([1, 2, 3], list(paginator.page_range))
p = paginator.page(2)
self.assertEqual("<Page 2 of 3>", six.text_type(p))
self.assertEqual([4, 5, 6], p.object_list)
@@ -125,10 +125,10 @@ class PaginationTests(TestCase):
paginator = Paginator(CountContainer(), 10)
self.assertEqual(42, paginator.count)
self.assertEqual(5, paginator.num_pages)
- self.assertEqual([1, 2, 3, 4, 5], paginator.page_range)
+ self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range))
# Paginator can be passed other objects that implement __len__.
paginator = Paginator(LenContainer(), 10)
self.assertEqual(42, paginator.count)
self.assertEqual(5, paginator.num_pages)
- self.assertEqual([1, 2, 3, 4, 5], paginator.page_range)
+ self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range))
diff --git a/tests/modeltests/prefetch_related/models.py b/tests/modeltests/prefetch_related/models.py
index 589f78c7d3..85488f0879 100644
--- a/tests/modeltests/prefetch_related/models.py
+++ b/tests/modeltests/prefetch_related/models.py
@@ -1,16 +1,18 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
## Basic tests
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=50, unique=True)
first_book = models.ForeignKey('Book', related_name='first_time_authors')
favorite_authors = models.ManyToManyField(
'self', through='FavoriteAuthors', symmetrical=False, related_name='favors_me')
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
@@ -30,6 +32,7 @@ class FavoriteAuthors(models.Model):
ordering = ['id']
+@python_2_unicode_compatible
class AuthorAddress(models.Model):
author = models.ForeignKey(Author, to_field='name', related_name='addresses')
address = models.TextField()
@@ -37,15 +40,16 @@ class AuthorAddress(models.Model):
class Meta:
ordering = ['id']
- def __unicode__(self):
+ def __str__(self):
return self.address
+@python_2_unicode_compatible
class Book(models.Model):
title = models.CharField(max_length=255)
authors = models.ManyToManyField(Author, related_name='books')
- def __unicode__(self):
+ def __str__(self):
return self.title
class Meta:
@@ -58,11 +62,12 @@ class BookWithYear(Book):
AuthorWithAge, related_name='books_with_year')
+@python_2_unicode_compatible
class Reader(models.Model):
name = models.CharField(max_length=50)
books_read = models.ManyToManyField(Book, related_name='read_by')
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
@@ -86,13 +91,14 @@ class TeacherManager(models.Manager):
return super(TeacherManager, self).get_query_set().prefetch_related('qualifications')
+@python_2_unicode_compatible
class Teacher(models.Model):
name = models.CharField(max_length=50)
qualifications = models.ManyToManyField(Qualification)
objects = TeacherManager()
- def __unicode__(self):
+ def __str__(self):
return "%s (%s)" % (self.name, ", ".join(q.name for q in self.qualifications.all()))
class Meta:
@@ -109,6 +115,7 @@ class Department(models.Model):
## GenericRelation/GenericForeignKey tests
+@python_2_unicode_compatible
class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType, related_name="taggeditem_set2")
@@ -119,7 +126,7 @@ class TaggedItem(models.Model):
created_by_fkey = models.PositiveIntegerField(null=True)
created_by = generic.GenericForeignKey('created_by_ct', 'created_by_fkey',)
- def __unicode__(self):
+ def __str__(self):
return self.tag
@@ -169,12 +176,13 @@ class Person(models.Model):
## Models for nullable FK tests
+@python_2_unicode_compatible
class Employee(models.Model):
name = models.CharField(max_length=50)
boss = models.ForeignKey('self', null=True,
related_name='serfs')
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py
index 8ae0a1e298..614a5fc1d6 100644
--- a/tests/modeltests/prefetch_related/tests.py
+++ b/tests/modeltests/prefetch_related/tests.py
@@ -352,7 +352,7 @@ class MultiTableInheritanceTest(TestCase):
with self.assertNumQueries(2):
qs = BookReview.objects.prefetch_related('book')
titles = [obj.book.title for obj in qs]
- self.assertEquals(titles, ["Poems", "More poems"])
+ self.assertEqual(titles, ["Poems", "More poems"])
def test_m2m_to_inheriting_model(self):
qs = AuthorWithAge.objects.prefetch_related('books_with_year')
diff --git a/tests/modeltests/proxy_model_inheritance/tests.py b/tests/modeltests/proxy_model_inheritance/tests.py
index 061cdc7e91..39fee7ee6d 100644
--- a/tests/modeltests/proxy_model_inheritance/tests.py
+++ b/tests/modeltests/proxy_model_inheritance/tests.py
@@ -24,7 +24,8 @@ class ProxyModelInheritanceTests(TransactionTestCase):
def setUp(self):
self.old_sys_path = sys.path[:]
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
- map(load_app, settings.INSTALLED_APPS)
+ for app in settings.INSTALLED_APPS:
+ load_app(app)
def tearDown(self):
sys.path = self.old_sys_path
diff --git a/tests/modeltests/proxy_models/models.py b/tests/modeltests/proxy_models/models.py
index 49fd87deff..6c962aadc8 100644
--- a/tests/modeltests/proxy_models/models.py
+++ b/tests/modeltests/proxy_models/models.py
@@ -5,6 +5,7 @@ than using a new table of their own. This allows them to act as simple proxies,
providing a modified interface to the data from the base class.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# A couple of managers for testing managing overriding in proxy model cases.
@@ -16,6 +17,7 @@ class SubManager(models.Manager):
def get_query_set(self):
return super(SubManager, self).get_query_set().exclude(name="wilma")
+@python_2_unicode_compatible
class Person(models.Model):
"""
A simple concrete base class.
@@ -24,7 +26,7 @@ class Person(models.Model):
objects = PersonManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
class Abstract(models.Model):
@@ -82,10 +84,11 @@ class MyPersonProxy(MyPerson):
class LowerStatusPerson(MyPersonProxy):
status = models.CharField(max_length=80)
+@python_2_unicode_compatible
class User(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
class UserProxy(User):
@@ -100,11 +103,12 @@ class UserProxyProxy(UserProxy):
class Country(models.Model):
name = models.CharField(max_length=50)
+@python_2_unicode_compatible
class State(models.Model):
name = models.CharField(max_length=50)
country = models.ForeignKey(Country)
- def __unicode__(self):
+ def __str__(self):
return self.name
class StateProxy(State):
@@ -124,11 +128,12 @@ class ProxyTrackerUser(TrackerUser):
proxy = True
+@python_2_unicode_compatible
class Issue(models.Model):
summary = models.CharField(max_length=255)
assignee = models.ForeignKey(TrackerUser)
- def __unicode__(self):
+ def __str__(self):
return ':'.join((self.__class__.__name__,self.summary,))
class Bug(Issue):
diff --git a/tests/modeltests/reserved_names/models.py b/tests/modeltests/reserved_names/models.py
index 010649e681..8e942b20e8 100644
--- a/tests/modeltests/reserved_names/models.py
+++ b/tests/modeltests/reserved_names/models.py
@@ -8,8 +8,10 @@ reserved-name usage.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Thing(models.Model):
when = models.CharField(max_length=1, primary_key=True)
join = models.CharField(max_length=1)
@@ -22,5 +24,5 @@ class Thing(models.Model):
class Meta:
db_table = 'select'
- def __unicode__(self):
- return self.when \ No newline at end of file
+ def __str__(self):
+ return self.when
diff --git a/tests/modeltests/reverse_lookup/models.py b/tests/modeltests/reverse_lookup/models.py
index bb7a163327..ed58177770 100644
--- a/tests/modeltests/reverse_lookup/models.py
+++ b/tests/modeltests/reverse_lookup/models.py
@@ -5,25 +5,29 @@ This demonstrates the reverse lookup features of the database API.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class User(models.Model):
name = models.CharField(max_length=200)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Poll(models.Model):
question = models.CharField(max_length=200)
creator = models.ForeignKey(User)
- def __unicode__(self):
+ def __str__(self):
return self.question
+@python_2_unicode_compatible
class Choice(models.Model):
name = models.CharField(max_length=100)
poll = models.ForeignKey(Poll, related_name="poll_choice")
related_poll = models.ForeignKey(Poll, related_name="related_choice")
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/save_delete_hooks/models.py b/tests/modeltests/save_delete_hooks/models.py
index bae60e4b86..a6e1abfb77 100644
--- a/tests/modeltests/save_delete_hooks/models.py
+++ b/tests/modeltests/save_delete_hooks/models.py
@@ -7,8 +7,10 @@ the methods.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
@@ -17,7 +19,7 @@ class Person(models.Model):
super(Person, self).__init__(*args, **kwargs)
self.data = []
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
def save(self, *args, **kwargs):
diff --git a/tests/modeltests/select_related/models.py b/tests/modeltests/select_related/models.py
index 3c2e7721fd..ec41957adf 100644
--- a/tests/modeltests/select_related/models.py
+++ b/tests/modeltests/select_related/models.py
@@ -8,52 +8,61 @@ the select-related behavior will traverse.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# Who remembers high school biology?
+@python_2_unicode_compatible
class Domain(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Kingdom(models.Model):
name = models.CharField(max_length=50)
domain = models.ForeignKey(Domain)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Phylum(models.Model):
name = models.CharField(max_length=50)
kingdom = models.ForeignKey(Kingdom)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Klass(models.Model):
name = models.CharField(max_length=50)
phylum = models.ForeignKey(Phylum)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Order(models.Model):
name = models.CharField(max_length=50)
klass = models.ForeignKey(Klass)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Family(models.Model):
name = models.CharField(max_length=50)
order = models.ForeignKey(Order)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Genus(models.Model):
name = models.CharField(max_length=50)
family = models.ForeignKey(Family)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Species(models.Model):
name = models.CharField(max_length=50)
genus = models.ForeignKey(Genus)
- def __unicode__(self):
- return self.name \ No newline at end of file
+ def __str__(self):
+ return self.name
diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py
index 9da099c027..569f2cec49 100644
--- a/tests/modeltests/serializers/models.py
+++ b/tests/modeltests/serializers/models.py
@@ -11,28 +11,32 @@ from decimal import Decimal
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=20)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Article(models.Model):
author = models.ForeignKey(Author)
headline = models.CharField(max_length=50)
@@ -42,28 +46,31 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date',)
- def __unicode__(self):
+ def __str__(self):
return self.headline
+@python_2_unicode_compatible
class AuthorProfile(models.Model):
author = models.OneToOneField(Author, primary_key=True)
date_of_birth = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return "Profile of %s" % self.author
+@python_2_unicode_compatible
class Actor(models.Model):
name = models.CharField(max_length=20, primary_key=True)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Movie(models.Model):
actor = models.ForeignKey(Actor)
title = models.CharField(max_length=50)
@@ -72,7 +79,7 @@ class Movie(models.Model):
class Meta:
ordering = ('title',)
- def __unicode__(self):
+ def __str__(self):
return self.title
@@ -80,13 +87,11 @@ class Score(models.Model):
score = models.FloatField()
+@python_2_unicode_compatible
class Team(object):
def __init__(self, title):
self.title = title
- def __unicode__(self):
- raise NotImplementedError("Not so simple")
-
def __str__(self):
raise NotImplementedError("Not so simple")
@@ -94,8 +99,7 @@ class Team(object):
return "%s" % self.title
-class TeamField(models.CharField):
- __metaclass__ = models.SubfieldBase
+class TeamField(six.with_metaclass(models.SubfieldBase, models.CharField)):
def __init__(self):
super(TeamField, self).__init__(max_length=100)
@@ -112,10 +116,11 @@ class TeamField(models.CharField):
return self._get_val_from_obj(obj).to_string()
+@python_2_unicode_compatible
class Player(models.Model):
name = models.CharField(max_length=50)
rank = models.IntegerField()
team = TeamField()
- def __unicode__(self):
+ def __str__(self):
return '%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string())
diff --git a/tests/modeltests/serializers/tests.py b/tests/modeltests/serializers/tests.py
index ec3cc132db..e39f17b68a 100644
--- a/tests/modeltests/serializers/tests.py
+++ b/tests/modeltests/serializers/tests.py
@@ -114,8 +114,8 @@ class SerializersTestBase(object):
Tests the ability to create new objects by
modifying serialized content.
"""
- old_headline = b"Poker has no place on ESPN"
- new_headline = b"Poker has no place on television"
+ old_headline = "Poker has no place on ESPN"
+ new_headline = "Poker has no place on television"
serial_str = serializers.serialize(self.serializer_name,
Article.objects.all())
serial_str = serial_str.replace(old_headline, new_headline)
@@ -285,7 +285,7 @@ class SerializersTransactionTestBase(object):
class XmlSerializerTestCase(SerializersTestBase, TestCase):
serializer_name = "xml"
- pkless_str = b"""<?xml version="1.0" encoding="utf-8"?>
+ pkless_str = """<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object model="serializers.category">
<field type="CharField" name="name">Reference</field>
@@ -331,7 +331,7 @@ class XmlSerializerTestCase(SerializersTestBase, TestCase):
class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
serializer_name = "xml"
- fwd_ref_str = b"""<?xml version="1.0" encoding="utf-8"?>
+ fwd_ref_str = """<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="1" model="serializers.article">
<field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
@@ -351,7 +351,7 @@ class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, Transacti
class JsonSerializerTestCase(SerializersTestBase, TestCase):
serializer_name = "json"
- pkless_str = b"""[{"pk": null, "model": "serializers.category", "fields": {"name": "Reference"}}]"""
+ pkless_str = """[{"pk": null, "model": "serializers.category", "fields": {"name": "Reference"}}]"""
@staticmethod
def _validate_output(serial_str):
@@ -381,7 +381,7 @@ class JsonSerializerTestCase(SerializersTestBase, TestCase):
class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
serializer_name = "json"
- fwd_ref_str = b"""[
+ fwd_ref_str = """[
{
"pk": 1,
"model": "serializers.article",
@@ -414,7 +414,7 @@ except ImportError:
else:
class YamlSerializerTestCase(SerializersTestBase, TestCase):
serializer_name = "yaml"
- fwd_ref_str = b"""- fields:
+ fwd_ref_str = """- fields:
headline: Forward references pose no problem
pub_date: 2006-06-16 15:00:00
categories: [1]
@@ -430,7 +430,7 @@ else:
pk: 1
model: serializers.author"""
- pkless_str = b"""- fields:
+ pkless_str = """- fields:
name: Reference
pk: null
model: serializers.category"""
@@ -470,7 +470,7 @@ else:
class YamlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
serializer_name = "yaml"
- fwd_ref_str = b"""- fields:
+ fwd_ref_str = """- fields:
headline: Forward references pose no problem
pub_date: 2006-06-16 15:00:00
categories: [1]
diff --git a/tests/modeltests/signals/models.py b/tests/modeltests/signals/models.py
index 18ca467655..e54a22fce9 100644
--- a/tests/modeltests/signals/models.py
+++ b/tests/modeltests/signals/models.py
@@ -4,18 +4,21 @@ Testing signals before/after saving and deleting.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Car(models.Model):
make = models.CharField(max_length=20)
model = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.make, self.model)
diff --git a/tests/modeltests/str/models.py b/tests/modeltests/str/models.py
index 6f6b877c88..488012e861 100644
--- a/tests/modeltests/str/models.py
+++ b/tests/modeltests/str/models.py
@@ -15,6 +15,7 @@ if you prefer. You must be careful to encode the results correctly, though.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Article(models.Model):
@@ -26,9 +27,10 @@ class Article(models.Model):
# in ASCII.
return self.headline
+@python_2_unicode_compatible
class InternationalArticle(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
- def __unicode__(self):
- return self.headline \ No newline at end of file
+ def __str__(self):
+ return self.headline
diff --git a/tests/modeltests/str/tests.py b/tests/modeltests/str/tests.py
index bed9ea719b..2c11ac8c78 100644
--- a/tests/modeltests/str/tests.py
+++ b/tests/modeltests/str/tests.py
@@ -4,23 +4,32 @@ from __future__ import absolute_import, unicode_literals
import datetime
from django.test import TestCase
+from django.utils import six
+from django.utils.unittest import skipIf
from .models import Article, InternationalArticle
class SimpleTests(TestCase):
+
+ @skipIf(six.PY3, "tests a __str__ method returning unicode under Python 2")
def test_basic(self):
a = Article.objects.create(
headline=b'Area man programs in Python',
pub_date=datetime.datetime(2005, 7, 28)
)
- self.assertEqual(str(a), b'Area man programs in Python')
- self.assertEqual(repr(a), b'<Article: Area man programs in Python>')
+ self.assertEqual(str(a), str('Area man programs in Python'))
+ self.assertEqual(repr(a), str('<Article: Area man programs in Python>'))
def test_international(self):
a = InternationalArticle.objects.create(
headline='Girl wins €12.500 in lottery',
pub_date=datetime.datetime(2005, 7, 28)
)
- # The default str() output will be the UTF-8 encoded output of __unicode__().
- self.assertEqual(str(a), b'Girl wins \xe2\x82\xac12.500 in lottery')
+ if six.PY3:
+ self.assertEqual(str(a), 'Girl wins €12.500 in lottery')
+ else:
+ # On Python 2, the default str() output will be the UTF-8 encoded
+ # output of __unicode__() -- or __str__() when the
+ # python_2_unicode_compatible decorator is used.
+ self.assertEqual(str(a), b'Girl wins \xe2\x82\xac12.500 in lottery')
diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py
index 399d2906a8..1d9c999f21 100644
--- a/tests/modeltests/test_client/models.py
+++ b/tests/modeltests/test_client/models.py
@@ -91,7 +91,7 @@ class ClientTest(TestCase):
content_type="text/xml")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.templates[0].name, "Book template")
- self.assertEqual(response.content, "Blink - Malcolm Gladwell")
+ self.assertEqual(response.content, b"Blink - Malcolm Gladwell")
def test_redirect(self):
"GET a URL that redirects elsewhere"
diff --git a/tests/modeltests/timezones/tests.py b/tests/modeltests/timezones/tests.py
index a38e4b3f75..4621f0a60c 100644
--- a/tests/modeltests/timezones/tests.py
+++ b/tests/modeltests/timezones/tests.py
@@ -467,6 +467,7 @@ class NewDatabaseTests(TestCase):
[event],
transform=lambda d: d)
+ @requires_tz_support
def test_filter_date_field_with_aware_datetime(self):
# Regression test for #17742
day = datetime.date(2011, 9, 1)
diff --git a/tests/modeltests/transactions/models.py b/tests/modeltests/transactions/models.py
index 7a51b9ac1c..0f8d6b16ec 100644
--- a/tests/modeltests/transactions/models.py
+++ b/tests/modeltests/transactions/models.py
@@ -9,8 +9,10 @@ manually.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
@@ -19,5 +21,5 @@ class Reporter(models.Model):
class Meta:
ordering = ('first_name', 'last_name')
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
diff --git a/tests/modeltests/unmanaged_models/models.py b/tests/modeltests/unmanaged_models/models.py
index 00303cf17a..0eef69977c 100644
--- a/tests/modeltests/unmanaged_models/models.py
+++ b/tests/modeltests/unmanaged_models/models.py
@@ -4,9 +4,11 @@ is generated for the table on various manage.py operations.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# All of these models are created in the database by Django.
+@python_2_unicode_compatible
class A01(models.Model):
f_a = models.CharField(max_length=10, db_index=True)
f_b = models.IntegerField()
@@ -14,9 +16,10 @@ class A01(models.Model):
class Meta:
db_table = 'a01'
- def __unicode__(self):
+ def __str__(self):
return self.f_a
+@python_2_unicode_compatible
class B01(models.Model):
fk_a = models.ForeignKey(A01)
f_a = models.CharField(max_length=10, db_index=True)
@@ -27,9 +30,10 @@ class B01(models.Model):
# 'managed' is True by default. This tests we can set it explicitly.
managed = True
- def __unicode__(self):
+ def __str__(self):
return self.f_a
+@python_2_unicode_compatible
class C01(models.Model):
mm_a = models.ManyToManyField(A01, db_table='d01')
f_a = models.CharField(max_length=10, db_index=True)
@@ -38,13 +42,14 @@ class C01(models.Model):
class Meta:
db_table = 'c01'
- def __unicode__(self):
+ def __str__(self):
return self.f_a
# All of these models use the same tables as the previous set (they are shadows
# of possibly a subset of the columns). There should be no creation errors,
# since we have told Django they aren't managed by Django.
+@python_2_unicode_compatible
class A02(models.Model):
f_a = models.CharField(max_length=10, db_index=True)
@@ -52,9 +57,10 @@ class A02(models.Model):
db_table = 'a01'
managed = False
- def __unicode__(self):
+ def __str__(self):
return self.f_a
+@python_2_unicode_compatible
class B02(models.Model):
class Meta:
db_table = 'b01'
@@ -64,11 +70,12 @@ class B02(models.Model):
f_a = models.CharField(max_length=10, db_index=True)
f_b = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.f_a
# To re-use the many-to-many intermediate table, we need to manually set up
# things up.
+@python_2_unicode_compatible
class C02(models.Model):
mm_a = models.ManyToManyField(A02, through="Intermediate")
f_a = models.CharField(max_length=10, db_index=True)
@@ -78,7 +85,7 @@ class C02(models.Model):
db_table = 'c01'
managed = False
- def __unicode__(self):
+ def __str__(self):
return self.f_a
class Intermediate(models.Model):
diff --git a/tests/modeltests/update/models.py b/tests/modeltests/update/models.py
index b93e4a7aae..08472d98b1 100644
--- a/tests/modeltests/update/models.py
+++ b/tests/modeltests/update/models.py
@@ -5,21 +5,24 @@ updates.
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class DataPoint(models.Model):
name = models.CharField(max_length=20)
value = models.CharField(max_length=20)
another_value = models.CharField(max_length=20, blank=True)
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.name)
+@python_2_unicode_compatible
class RelatedPoint(models.Model):
name = models.CharField(max_length=20)
data = models.ForeignKey(DataPoint)
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.name)
diff --git a/tests/modeltests/update_only_fields/models.py b/tests/modeltests/update_only_fields/models.py
index 968dba9916..bf5dd99166 100644
--- a/tests/modeltests/update_only_fields/models.py
+++ b/tests/modeltests/update_only_fields/models.py
@@ -1,5 +1,6 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
GENDER_CHOICES = (
('M', 'Male'),
@@ -10,11 +11,13 @@ class Account(models.Model):
num = models.IntegerField()
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
+ pid = models.IntegerField(null=True, default=None)
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -24,11 +27,12 @@ class Employee(Person):
accounts = models.ManyToManyField('Account', related_name='employees', blank=True, null=True)
+@python_2_unicode_compatible
class Profile(models.Model):
name = models.CharField(max_length=200)
salary = models.FloatField(default=1000.0)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/modeltests/update_only_fields/tests.py b/tests/modeltests/update_only_fields/tests.py
index bce53ca621..c904c97236 100644
--- a/tests/modeltests/update_only_fields/tests.py
+++ b/tests/modeltests/update_only_fields/tests.py
@@ -18,6 +18,107 @@ class UpdateOnlyFieldsTests(TestCase):
self.assertEqual(s.gender, 'F')
self.assertEqual(s.name, 'Ian')
+ def test_update_fields_deferred(self):
+ s = Person.objects.create(name='Sara', gender='F', pid=22)
+ self.assertEqual(s.gender, 'F')
+
+ s1 = Person.objects.defer("gender", "pid").get(pk=s.pk)
+ s1.name = "Emily"
+ s1.gender = "M"
+
+ with self.assertNumQueries(1):
+ s1.save()
+
+ s2 = Person.objects.get(pk=s1.pk)
+ self.assertEqual(s2.name, "Emily")
+ self.assertEqual(s2.gender, "M")
+
+ def test_update_fields_only_1(self):
+ s = Person.objects.create(name='Sara', gender='F')
+ self.assertEqual(s.gender, 'F')
+
+ s1 = Person.objects.only('name').get(pk=s.pk)
+ s1.name = "Emily"
+ s1.gender = "M"
+
+ with self.assertNumQueries(1):
+ s1.save()
+
+ s2 = Person.objects.get(pk=s1.pk)
+ self.assertEqual(s2.name, "Emily")
+ self.assertEqual(s2.gender, "M")
+
+ def test_update_fields_only_2(self):
+ s = Person.objects.create(name='Sara', gender='F', pid=22)
+ self.assertEqual(s.gender, 'F')
+
+ s1 = Person.objects.only('name').get(pk=s.pk)
+ s1.name = "Emily"
+ s1.gender = "M"
+
+ with self.assertNumQueries(2):
+ s1.save(update_fields=['pid'])
+
+ s2 = Person.objects.get(pk=s1.pk)
+ self.assertEqual(s2.name, "Sara")
+ self.assertEqual(s2.gender, "F")
+
+ def test_update_fields_only_repeated(self):
+ s = Person.objects.create(name='Sara', gender='F')
+ self.assertEqual(s.gender, 'F')
+
+ s1 = Person.objects.only('name').get(pk=s.pk)
+ s1.gender = 'M'
+ with self.assertNumQueries(1):
+ s1.save()
+ # Test that the deferred class does not remember that gender was
+ # set, instead the instace should remember this.
+ s1 = Person.objects.only('name').get(pk=s.pk)
+ with self.assertNumQueries(1):
+ s1.save()
+
+ def test_update_fields_inheritance_defer(self):
+ profile_boss = Profile.objects.create(name='Boss', salary=3000)
+ e1 = Employee.objects.create(name='Sara', gender='F',
+ employee_num=1, profile=profile_boss)
+ e1 = Employee.objects.only('name').get(pk=e1.pk)
+ e1.name = 'Linda'
+ with self.assertNumQueries(1):
+ e1.save()
+ self.assertEqual(Employee.objects.get(pk=e1.pk).name,
+ 'Linda')
+
+ def test_update_fields_fk_defer(self):
+ profile_boss = Profile.objects.create(name='Boss', salary=3000)
+ profile_receptionist = Profile.objects.create(name='Receptionist', salary=1000)
+ e1 = Employee.objects.create(name='Sara', gender='F',
+ employee_num=1, profile=profile_boss)
+ e1 = Employee.objects.only('profile').get(pk=e1.pk)
+ e1.profile = profile_receptionist
+ with self.assertNumQueries(1):
+ e1.save()
+ self.assertEqual(Employee.objects.get(pk=e1.pk).profile, profile_receptionist)
+ e1.profile_id = profile_boss.pk
+ with self.assertNumQueries(1):
+ e1.save()
+ self.assertEqual(Employee.objects.get(pk=e1.pk).profile, profile_boss)
+
+ def test_select_related_only_interaction(self):
+ profile_boss = Profile.objects.create(name='Boss', salary=3000)
+ e1 = Employee.objects.create(name='Sara', gender='F',
+ employee_num=1, profile=profile_boss)
+ e1 = Employee.objects.only('profile__salary').select_related('profile').get(pk=e1.pk)
+ profile_boss.name = 'Clerk'
+ profile_boss.salary = 1000
+ profile_boss.save()
+ # The loaded salary of 3000 gets saved, the name of 'Clerk' isn't
+ # overwritten.
+ with self.assertNumQueries(1):
+ e1.profile.save()
+ reloaded_profile = Profile.objects.get(pk=profile_boss.pk)
+ self.assertEqual(reloaded_profile.name, profile_boss.name)
+ self.assertEqual(reloaded_profile.salary, 3000)
+
def test_update_fields_m2m(self):
profile_boss = Profile.objects.create(name='Boss', salary=3000)
e1 = Employee.objects.create(name='Sara', gender='F',
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py
index 26fff4b863..db083290fb 100644
--- a/tests/modeltests/validation/models.py
+++ b/tests/modeltests/validation/models.py
@@ -4,6 +4,7 @@ from datetime import datetime
from django.core.exceptions import ValidationError
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
def validate_answer_to_universe(value):
@@ -66,13 +67,14 @@ class Article(models.Model):
if self.pub_date is None:
self.pub_date = datetime.now()
+@python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
posted = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.name
class FlexibleDatePost(models.Model):
@@ -89,6 +91,8 @@ class GenericIPAddressTestModel(models.Model):
generic_ip = models.GenericIPAddressField(blank=True, null=True, unique=True)
v4_ip = models.GenericIPAddressField(blank=True, null=True, protocol="ipv4")
v6_ip = models.GenericIPAddressField(blank=True, null=True, protocol="ipv6")
+ ip_verbose_name = models.GenericIPAddressField("IP Address Verbose",
+ blank=True, null=True)
class GenericIPAddrUnpackUniqueTest(models.Model):
generic_v4unpack_ip = models.GenericIPAddressField(blank=True, unique=True, unpack_ipv4=True)
diff --git a/tests/modeltests/validation/tests.py b/tests/modeltests/validation/tests.py
index 4f658203df..58b7b94e7f 100644
--- a/tests/modeltests/validation/tests.py
+++ b/tests/modeltests/validation/tests.py
@@ -79,7 +79,7 @@ class ModelFormsTests(TestCase):
'pub_date': '2010-1-10 14:49:00'
}
form = ArticleForm(data)
- self.assertEqual(form.errors.keys(), [])
+ self.assertEqual(list(form.errors), [])
article = form.save(commit=False)
article.author = self.author
article.save()
@@ -95,7 +95,7 @@ class ModelFormsTests(TestCase):
}
article = Article(author_id=self.author.id)
form = ArticleForm(data, instance=article)
- self.assertEqual(form.errors.keys(), [])
+ self.assertEqual(list(form.errors), [])
self.assertNotEqual(form.instance.pub_date, None)
article = form.save()
@@ -108,7 +108,7 @@ class ModelFormsTests(TestCase):
}
article = Article(author_id=self.author.id)
form = ArticleForm(data, instance=article)
- self.assertEqual(form.errors.keys(), ['pub_date'])
+ self.assertEqual(list(form.errors), ['pub_date'])
class GenericIPAddressFieldTests(ValidationTestCase):
diff --git a/tests/regressiontests/admin_changelist/models.py b/tests/regressiontests/admin_changelist/models.py
index 487db50689..4ba2f9c503 100644
--- a/tests/regressiontests/admin_changelist/models.py
+++ b/tests/regressiontests/admin_changelist/models.py
@@ -1,4 +1,5 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Event(models.Model):
# Oracle can have problems with a column named "date"
@@ -20,17 +21,19 @@ class Band(models.Model):
nr_of_members = models.PositiveIntegerField()
genres = models.ManyToManyField(Genre)
+@python_2_unicode_compatible
class Musician(models.Model):
name = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Group(models.Model):
name = models.CharField(max_length=30)
members = models.ManyToManyField(Musician, through='Membership')
- def __unicode__(self):
+ def __str__(self):
return self.name
class Membership(models.Model):
diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py
index 1ed963aaf2..be88c9a161 100644
--- a/tests/regressiontests/admin_changelist/tests.py
+++ b/tests/regressiontests/admin_changelist/tests.py
@@ -317,7 +317,7 @@ class ChangeListTests(TestCase):
m.list_editable, m)
self.assertEqual(cl.query_set.count(), 60)
self.assertEqual(cl.paginator.count, 60)
- self.assertEqual(cl.paginator.page_range, [1, 2, 3, 4, 5, 6])
+ self.assertEqual(list(cl.paginator.page_range), [1, 2, 3, 4, 5, 6])
# Test custom queryset
m = FilteredChildAdmin(Child, admin.site)
@@ -327,7 +327,7 @@ class ChangeListTests(TestCase):
m.list_editable, m)
self.assertEqual(cl.query_set.count(), 30)
self.assertEqual(cl.paginator.count, 30)
- self.assertEqual(cl.paginator.page_range, [1, 2, 3])
+ self.assertEqual(list(cl.paginator.page_range), [1, 2, 3])
def test_computed_list_display_localization(self):
"""
diff --git a/tests/regressiontests/admin_custom_urls/fixtures/actions.json b/tests/regressiontests/admin_custom_urls/fixtures/actions.json
index d803393a12..a63cf8135c 100644
--- a/tests/regressiontests/admin_custom_urls/fixtures/actions.json
+++ b/tests/regressiontests/admin_custom_urls/fixtures/actions.json
@@ -40,5 +40,12 @@
"fields": {
"description": "An action with a name suspected of being a XSS attempt"
}
+ },
+ {
+ "pk": "The name of an action",
+ "model": "admin_custom_urls.action",
+ "fields": {
+ "description": "A generic action"
+ }
}
-] \ No newline at end of file
+]
diff --git a/tests/regressiontests/admin_custom_urls/models.py b/tests/regressiontests/admin_custom_urls/models.py
index facb4b52e7..a5b4983b09 100644
--- a/tests/regressiontests/admin_custom_urls/models.py
+++ b/tests/regressiontests/admin_custom_urls/models.py
@@ -2,13 +2,15 @@ from functools import update_wrapper
from django.contrib import admin
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Action(models.Model):
name = models.CharField(max_length=50, primary_key=True)
description = models.CharField(max_length=70)
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -26,7 +28,7 @@ class ActionAdmin(admin.ModelAdmin):
Remove all entries named 'name' from the ModelAdmin instance URL
patterns list
"""
- return filter(lambda e: e.name != name, super(ActionAdmin, self).get_urls())
+ return [url for url in super(ActionAdmin, self).get_urls() if url.name != name]
def get_urls(self):
# Add the URL of our custom 'add_view' view to the front of the URLs
diff --git a/tests/regressiontests/admin_custom_urls/tests.py b/tests/regressiontests/admin_custom_urls/tests.py
index 4a6235e7d5..64ff9f6692 100644
--- a/tests/regressiontests/admin_custom_urls/tests.py
+++ b/tests/regressiontests/admin_custom_urls/tests.py
@@ -10,6 +10,12 @@ from .models import Action
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class AdminCustomUrlsTest(TestCase):
+ """
+ Remember that:
+ * The Action model has a CharField PK.
+ * The ModelAdmin for Action customizes the add_view URL, it's
+ '<app name>/<model name>/!add/'
+ """
fixtures = ['users.json', 'actions.json']
def setUp(self):
@@ -20,23 +26,24 @@ class AdminCustomUrlsTest(TestCase):
def testBasicAddGet(self):
"""
- A smoke test to ensure GET on the add_view works.
+ Ensure GET on the add_view works.
"""
response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/')
self.assertIsInstance(response, TemplateResponse)
self.assertEqual(response.status_code, 200)
def testAddWithGETArgs(self):
+ """
+ Ensure GET on the add_view plus specifying a field value in the query
+ string works.
+ """
response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/', {'name': 'My Action'})
self.assertEqual(response.status_code, 200)
- self.assertTrue(
- 'value="My Action"' in response.content,
- "Couldn't find an input with the right value in the response."
- )
+ self.assertContains(response, 'value="My Action"')
def testBasicAddPost(self):
"""
- A smoke test to ensure POST on add_view works.
+ Ensure POST on add_view works.
"""
post_data = {
'_popup': '1',
@@ -50,8 +57,7 @@ class AdminCustomUrlsTest(TestCase):
def testAdminUrlsNoClash(self):
"""
- Test that some admin URLs work correctly. The model has a CharField
- PK and the add_view URL has been customized.
+ Test that some admin URLs work correctly.
"""
# Should get the change_view for model instance with PK 'add', not show
# the add_view
@@ -60,17 +66,28 @@ class AdminCustomUrlsTest(TestCase):
self.assertContains(response, 'Change action')
# Ditto, but use reverse() to build the URL
- path = reverse('admin:%s_action_change' % Action._meta.app_label,
+ url = reverse('admin:%s_action_change' % Action._meta.app_label,
args=('add',))
- response = self.client.get(path)
+ response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Change action')
# Should correctly get the change_view for the model instance with the
- # funny-looking PK
- path = reverse('admin:%s_action_change' % Action._meta.app_label,
+ # funny-looking PK (the one wth a 'path/to/html/document.html' value)
+ url = reverse('admin:%s_action_change' % Action._meta.app_label,
args=("path/to/html/document.html",))
- response = self.client.get(path)
+ response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Change action')
self.assertContains(response, 'value="path/to/html/document.html"')
+
+ def testChangeViewHistoryButton(self):
+ url = reverse('admin:%s_action_change' % Action._meta.app_label,
+ args=('The name of an action',))
+ response = self.client.get(url)
+ self.assertEqual(response.status_code, 200)
+ expected_link = reverse('admin:%s_action_history' %
+ Action._meta.app_label,
+ args=('The name of an action',))
+ self.assertContains(response, '<a href="%s" class="historylink"' %
+ expected_link)
diff --git a/tests/regressiontests/admin_filters/models.py b/tests/regressiontests/admin_filters/models.py
index 371c67061f..e0b8bde2de 100644
--- a/tests/regressiontests/admin_filters/models.py
+++ b/tests/regressiontests/admin_filters/models.py
@@ -2,8 +2,10 @@ from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Book(models.Model):
title = models.CharField(max_length=50)
year = models.PositiveIntegerField(null=True, blank=True)
@@ -13,20 +15,22 @@ class Book(models.Model):
date_registered = models.DateField(null=True)
no = models.IntegerField(verbose_name='number', blank=True, null=True) # This field is intentionally 2 characters long. See #16080.
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Department(models.Model):
code = models.CharField(max_length=4, unique=True)
description = models.CharField(max_length=50, blank=True, null=True)
- def __unicode__(self):
+ def __str__(self):
return self.description
+@python_2_unicode_compatible
class Employee(models.Model):
department = models.ForeignKey(Department, to_field="code")
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
index 5a0f4d84b9..5b703a7481 100644
--- a/tests/regressiontests/admin_inlines/models.py
+++ b/tests/regressiontests/admin_inlines/models.py
@@ -7,22 +7,26 @@ from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Parent(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Teacher(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Child(models.Model):
name = models.CharField(max_length=50)
teacher = models.ForeignKey(Teacher)
@@ -31,7 +35,7 @@ class Child(models.Model):
object_id = models.PositiveIntegerField()
parent = generic.GenericForeignKey()
- def __unicode__(self):
+ def __str__(self):
return 'I am %s, a child of %s' % (self.name, self.parent)
diff --git a/tests/regressiontests/admin_scripts/custom_templates/project_template/ticket-18091-non-ascii-template.txt b/tests/regressiontests/admin_scripts/custom_templates/project_template/ticket-18091-non-ascii-template.txt
new file mode 100644
index 0000000000..873eaded88
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/custom_templates/project_template/ticket-18091-non-ascii-template.txt
@@ -0,0 +1,2 @@
+Some non-ASCII text for testing ticket #18091:
+üäö €
diff --git a/tests/regressiontests/admin_scripts/models.py b/tests/regressiontests/admin_scripts/models.py
index da803d0174..cd96052098 100644
--- a/tests/regressiontests/admin_scripts/models.py
+++ b/tests/regressiontests/admin_scripts/models.py
@@ -1,11 +1,13 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
index 546fa7d79c..2710f80929 100644
--- a/tests/regressiontests/admin_scripts/tests.py
+++ b/tests/regressiontests/admin_scripts/tests.py
@@ -1,8 +1,10 @@
+# -*- coding: utf-8 -*-
"""
A series of tests to establish that the command-line managment tools work as
advertised - especially with regards to the handling of the DJANGO_SETTINGS_MODULE
and default settings.py files.
"""
+from __future__ import unicode_literals
import os
import re
@@ -10,6 +12,7 @@ import shutil
import socket
import subprocess
import sys
+import codecs
from django import conf, bin, get_version
from django.conf import settings
@@ -71,6 +74,10 @@ class AdminScriptTestCase(unittest.TestCase):
os.remove(full_name + 'c')
except OSError:
pass
+ # Also remove a __pycache__ directory, if it exists
+ cache_name = os.path.join(test_dir, '__pycache__')
+ if os.path.isdir(cache_name):
+ shutil.rmtree(cache_name)
def _ext_backend_paths(self):
"""
@@ -110,14 +117,11 @@ class AdminScriptTestCase(unittest.TestCase):
python_path.extend(ext_backend_base_dirs)
os.environ[python_path_var_name] = os.pathsep.join(python_path)
- # Silence the DeprecationWarning caused by having a locale directory
- # in the project directory.
- cmd = [sys.executable, '-Wignore:::django.utils.translation', script]
-
# Move to the test directory and run
os.chdir(test_dir)
- out, err = subprocess.Popen(cmd + args,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ out, err = subprocess.Popen([sys.executable, script] + args,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True).communicate()
# Restore the old environment
if old_django_settings_module:
@@ -1572,3 +1576,17 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
self.assertOutput(err, "Destination directory '%s' does not exist, please create it first." % testproject_dir)
self.assertFalse(os.path.exists(testproject_dir))
+
+ def test_custom_project_template_with_non_ascii_templates(self):
+ "Ticket 18091: Make sure the startproject management command is able to render templates with non-ASCII content"
+ template_path = os.path.join(test_dir, 'admin_scripts', 'custom_templates', 'project_template')
+ args = ['startproject', '--template', template_path, '--extension=txt', 'customtestproject']
+ testproject_dir = os.path.join(test_dir, 'customtestproject')
+
+ out, err = self.run_django_admin(args)
+ self.addCleanup(shutil.rmtree, testproject_dir)
+ self.assertNoOutput(err)
+ self.assertTrue(os.path.isdir(testproject_dir))
+ path = os.path.join(testproject_dir, 'ticket-18091-non-ascii-template.txt')
+ self.assertEqual(codecs.open(path, 'r', 'utf-8').read(),
+ 'Some non-ASCII text for testing ticket #18091:\nüäö €\n')
diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py
index 5541097022..b3504a1fa4 100644
--- a/tests/regressiontests/admin_util/models.py
+++ b/tests/regressiontests/admin_util/models.py
@@ -1,5 +1,6 @@
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class Article(models.Model):
@@ -18,11 +19,12 @@ class Article(models.Model):
return "nothing"
test_from_model_with_override.short_description = "not What you Expect"
+@python_2_unicode_compatible
class Count(models.Model):
num = models.PositiveSmallIntegerField()
parent = models.ForeignKey('self', null=True)
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.num)
class Event(models.Model):
diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py
index 6b6dad4336..d04740ce95 100644
--- a/tests/regressiontests/admin_util/tests.py
+++ b/tests/regressiontests/admin_util/tests.py
@@ -171,7 +171,7 @@ class UtilTests(unittest.TestCase):
)
self.assertEqual(
label_for_field("__str__", Article),
- b"article"
+ str("article")
)
self.assertRaises(
diff --git a/tests/regressiontests/admin_validation/models.py b/tests/regressiontests/admin_validation/models.py
index 5e080a9232..d23849a2a8 100644
--- a/tests/regressiontests/admin_validation/models.py
+++ b/tests/regressiontests/admin_validation/models.py
@@ -3,12 +3,14 @@ Tests of ModelAdmin validation logic.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Album(models.Model):
title = models.CharField(max_length=150)
+@python_2_unicode_compatible
class Song(models.Model):
title = models.CharField(max_length=150)
album = models.ForeignKey(Album)
@@ -17,7 +19,7 @@ class Song(models.Model):
class Meta:
ordering = ('title',)
- def __unicode__(self):
+ def __str__(self):
return self.title
def readonly_method_on_model(self):
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index aee193b572..0d5e327ecf 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -10,6 +10,7 @@ from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.core.files.storage import FileSystemStorage
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Section(models.Model):
@@ -20,6 +21,7 @@ class Section(models.Model):
name = models.CharField(max_length=100)
+@python_2_unicode_compatible
class Article(models.Model):
"""
A simple article to test admin views. Test backwards compatibility.
@@ -29,7 +31,7 @@ class Article(models.Model):
date = models.DateTimeField()
section = models.ForeignKey(Section, null=True, blank=True)
- def __unicode__(self):
+ def __str__(self):
return self.title
def model_year(self):
@@ -38,30 +40,33 @@ class Article(models.Model):
model_year.short_description = ''
+@python_2_unicode_compatible
class Book(models.Model):
"""
A simple book that has chapters.
"""
name = models.CharField(max_length=100, verbose_name='¿Name?')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Promo(models.Model):
name = models.CharField(max_length=100, verbose_name='¿Name?')
book = models.ForeignKey(Book)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Chapter(models.Model):
title = models.CharField(max_length=100, verbose_name='¿Title?')
content = models.TextField()
book = models.ForeignKey(Book)
- def __unicode__(self):
+ def __str__(self):
return self.title
class Meta:
@@ -69,19 +74,21 @@ class Chapter(models.Model):
verbose_name = '¿Chapter?'
+@python_2_unicode_compatible
class ChapterXtra1(models.Model):
chap = models.OneToOneField(Chapter, verbose_name='¿Chap?')
xtra = models.CharField(max_length=100, verbose_name='¿Xtra?')
- def __unicode__(self):
+ def __str__(self):
return '¿Xtra1: %s' % self.xtra
+@python_2_unicode_compatible
class ChapterXtra2(models.Model):
chap = models.OneToOneField(Chapter, verbose_name='¿Chap?')
xtra = models.CharField(max_length=100, verbose_name='¿Xtra?')
- def __unicode__(self):
+ def __str__(self):
return '¿Xtra2: %s' % self.xtra
@@ -94,20 +101,22 @@ class CustomArticle(models.Model):
date = models.DateTimeField()
+@python_2_unicode_compatible
class ModelWithStringPrimaryKey(models.Model):
string_pk = models.CharField(max_length=255, primary_key=True)
- def __unicode__(self):
+ def __str__(self):
return self.string_pk
def get_absolute_url(self):
return '/dummy/%s/' % self.string_pk
+@python_2_unicode_compatible
class Color(models.Model):
value = models.CharField(max_length=10)
warm = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return self.value
# we replicate Color to register with another ModelAdmin
@@ -115,29 +124,33 @@ class Color2(Color):
class Meta:
proxy = True
+@python_2_unicode_compatible
class Thing(models.Model):
title = models.CharField(max_length=20)
color = models.ForeignKey(Color, limit_choices_to={'warm': True})
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Actor(models.Model):
name = models.CharField(max_length=50)
age = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Inquisition(models.Model):
expected = models.BooleanField()
leader = models.ForeignKey(Actor)
country = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return "by %s from %s" % (self.leader, self.country)
+@python_2_unicode_compatible
class Sketch(models.Model):
title = models.CharField(max_length=100)
inquisition = models.ForeignKey(Inquisition, limit_choices_to={'leader__name': 'Palin',
@@ -145,7 +158,7 @@ class Sketch(models.Model):
'expected': False,
})
- def __unicode__(self):
+ def __str__(self):
return self.title
@@ -161,6 +174,7 @@ class Fabric(models.Model):
surface = models.CharField(max_length=20, choices=NG_CHOICES)
+@python_2_unicode_compatible
class Person(models.Model):
GENDER_CHOICES = (
(1, "Male"),
@@ -171,20 +185,22 @@ class Person(models.Model):
age = models.IntegerField(default=21)
alive = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Persona(models.Model):
"""
A simple persona associated with accounts, to test inlining of related
accounts which inherit from a common accounts class.
"""
name = models.CharField(blank=False, max_length=80)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Account(models.Model):
"""
A simple, generic account encapsulating the information shared by all
@@ -194,7 +210,7 @@ class Account(models.Model):
persona = models.ForeignKey(Persona, related_name="accounts")
servicename = 'generic service'
- def __unicode__(self):
+ def __str__(self):
return "%s: %s" % (self.servicename, self.username)
@@ -208,11 +224,12 @@ class BarAccount(Account):
servicename = 'bar'
+@python_2_unicode_compatible
class Subscriber(models.Model):
name = models.CharField(blank=False, max_length=80)
email = models.EmailField(blank=False, max_length=175)
- def __unicode__(self):
+ def __str__(self):
return "%s (%s)" % (self.name, self.email)
@@ -249,8 +266,9 @@ class Child(models.Model):
name = models.CharField(max_length=30, blank=True)
+@python_2_unicode_compatible
class EmptyModel(models.Model):
- def __unicode__(self):
+ def __str__(self):
return "Primary key = %s" % self.id
@@ -332,6 +350,7 @@ class FancyDoodad(Doodad):
expensive = models.BooleanField(default=True)
+@python_2_unicode_compatible
class Category(models.Model):
collector = models.ForeignKey(Collector)
order = models.PositiveIntegerField()
@@ -339,7 +358,7 @@ class Category(models.Model):
class Meta:
ordering = ('order',)
- def __unicode__(self):
+ def __str__(self):
return '%s:o%s' % (self.id, self.order)
@@ -376,17 +395,19 @@ class Post(models.Model):
return "Very awesome."
+@python_2_unicode_compatible
class Gadget(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Villain(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -394,6 +415,7 @@ class SuperVillain(Villain):
pass
+@python_2_unicode_compatible
class FunkyTag(models.Model):
"Because we all know there's only one real use case for GFKs."
name = models.CharField(max_length=25)
@@ -401,59 +423,65 @@ class FunkyTag(models.Model):
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Plot(models.Model):
name = models.CharField(max_length=100)
team_leader = models.ForeignKey(Villain, related_name='lead_plots')
contact = models.ForeignKey(Villain, related_name='contact_plots')
tags = generic.GenericRelation(FunkyTag)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class PlotDetails(models.Model):
details = models.CharField(max_length=100)
plot = models.OneToOneField(Plot)
- def __unicode__(self):
+ def __str__(self):
return self.details
+@python_2_unicode_compatible
class SecretHideout(models.Model):
""" Secret! Not registered with the admin! """
location = models.CharField(max_length=100)
villain = models.ForeignKey(Villain)
- def __unicode__(self):
+ def __str__(self):
return self.location
+@python_2_unicode_compatible
class SuperSecretHideout(models.Model):
""" Secret! Not registered with the admin! """
location = models.CharField(max_length=100)
supervillain = models.ForeignKey(SuperVillain)
- def __unicode__(self):
+ def __str__(self):
return self.location
+@python_2_unicode_compatible
class CyclicOne(models.Model):
name = models.CharField(max_length=25)
two = models.ForeignKey('CyclicTwo')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class CyclicTwo(models.Model):
name = models.CharField(max_length=25)
one = models.ForeignKey(CyclicOne)
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -484,11 +512,12 @@ class Question(models.Model):
question = models.CharField(max_length=20)
+@python_2_unicode_compatible
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.PROTECT)
answer = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return self.answer
@@ -523,11 +552,12 @@ class Paper(models.Model):
author = models.CharField(max_length=30, blank=True, null=True)
+@python_2_unicode_compatible
class CoverLetter(models.Model):
author = models.CharField(max_length=30)
date_written = models.DateField(null=True, blank=True)
- def __unicode__(self):
+ def __str__(self):
return self.author
@@ -575,10 +605,11 @@ class AdminOrderedCallable(models.Model):
order = models.IntegerField()
stuff = models.CharField(max_length=200)
+@python_2_unicode_compatible
class Report(models.Model):
title = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.title
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index 09be55baba..cf7d4855fb 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -30,7 +30,7 @@ from django.template.response import TemplateResponse
from django.test import TestCase
from django.utils import formats, translation, unittest
from django.utils.cache import get_max_age
-from django.utils.encoding import iri_to_uri
+from django.utils.encoding import iri_to_uri, force_bytes
from django.utils.html import escape
from django.utils.http import urlencode
from django.utils import six
@@ -78,12 +78,22 @@ class AdminViewBasicTest(TestCase):
self.client.logout()
formats.reset_format_cache()
+ def assertContentBefore(self, response, text1, text2, failing_msg=None):
+ """
+ Testing utility asserting that text1 appears before text2 in response
+ content.
+ """
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(response.content.index(force_bytes(text1)) < response.content.index(force_bytes(text2)),
+ failing_msg
+ )
+
def testTrailingSlashRequired(self):
"""
If you leave off the trailing slash, app should redirect and add it.
"""
- request = self.client.get('/test_admin/%s/admin_views/article/add' % self.urlbit)
- self.assertRedirects(request,
+ response = self.client.get('/test_admin/%s/admin_views/article/add' % self.urlbit)
+ self.assertRedirects(response,
'/test_admin/%s/admin_views/article/add/' % self.urlbit, status_code=301
)
@@ -219,12 +229,10 @@ class AdminViewBasicTest(TestCase):
(column 2 is callable_year in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': 2})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Oldest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Newest content'),
- "Results of sorting on callable are out of order."
- )
+ self.assertContentBefore(response, 'Oldest content', 'Middle content',
+ "Results of sorting on callable are out of order.")
+ self.assertContentBefore(response, 'Middle content', 'Newest content',
+ "Results of sorting on callable are out of order.")
def testChangeListSortingModel(self):
"""
@@ -232,12 +240,10 @@ class AdminViewBasicTest(TestCase):
(colunn 3 is 'model_year' in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': '-3'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Newest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Oldest content'),
- "Results of sorting on Model method are out of order."
- )
+ self.assertContentBefore(response, 'Newest content', 'Middle content',
+ "Results of sorting on Model method are out of order.")
+ self.assertContentBefore(response, 'Middle content', 'Oldest content',
+ "Results of sorting on Model method are out of order.")
def testChangeListSortingModelAdmin(self):
"""
@@ -245,12 +251,10 @@ class AdminViewBasicTest(TestCase):
(colunn 4 is 'modeladmin_year' in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': '4'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index('Oldest content') < response.content.index('Middle content') and
- response.content.index('Middle content') < response.content.index('Newest content'),
- "Results of sorting on ModelAdmin method are out of order."
- )
+ self.assertContentBefore(response, 'Oldest content', 'Middle content',
+ "Results of sorting on ModelAdmin method are out of order.")
+ self.assertContentBefore(response, 'Middle content', 'Newest content',
+ "Results of sorting on ModelAdmin method are out of order.")
def testChangeListSortingMultiple(self):
p1 = Person.objects.create(name="Chris", gender=1, alive=True)
@@ -262,19 +266,13 @@ class AdminViewBasicTest(TestCase):
# This hard-codes the URL because it'll fail if it runs against the
# 'admin2' custom admin (which doesn't have the Person model).
response = self.client.get('/test_admin/admin/admin_views/person/', {'o': '1.2'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % p3.id) < response.content.index(link % p1.id) and
- response.content.index(link % p1.id) < response.content.index(link % p2.id)
- )
+ self.assertContentBefore(response, link % p3.id, link % p1.id)
+ self.assertContentBefore(response, link % p1.id, link % p2.id)
# Sort by gender descending, name
response = self.client.get('/test_admin/admin/admin_views/person/', {'o': '-2.1'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % p2.id) < response.content.index(link % p3.id) and
- response.content.index(link % p3.id) < response.content.index(link % p1.id)
- )
+ self.assertContentBefore(response, link % p2.id, link % p3.id)
+ self.assertContentBefore(response, link % p3.id, link % p1.id)
def testChangeListSortingPreserveQuerySetOrdering(self):
"""
@@ -291,11 +289,8 @@ class AdminViewBasicTest(TestCase):
# This hard-codes the URL because it'll fail if it runs against the
# 'admin2' custom admin (which doesn't have the Person model).
response = self.client.get('/test_admin/admin/admin_views/person/', {})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % p3.id) < response.content.index(link % p2.id) and
- response.content.index(link % p2.id) < response.content.index(link % p1.id)
- )
+ self.assertContentBefore(response, link % p3.id, link % p2.id)
+ self.assertContentBefore(response, link % p2.id, link % p1.id)
def testChangeListSortingModelMeta(self):
# Test ordering on Model Meta is respected
@@ -305,17 +300,11 @@ class AdminViewBasicTest(TestCase):
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/language/', {})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % l2.pk) < response.content.index(link % l1.pk)
- )
+ self.assertContentBefore(response, link % l2.pk, link % l1.pk)
# Test we can override with query string
response = self.client.get('/test_admin/admin/admin_views/language/', {'o':'-1'})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % l1.pk) < response.content.index(link % l2.pk)
- )
+ self.assertContentBefore(response, link % l1.pk, link % l2.pk)
def testChangeListSortingOverrideModelAdmin(self):
# Test ordering on Model Admin is respected, and overrides Model Meta
@@ -325,10 +314,7 @@ class AdminViewBasicTest(TestCase):
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/podcast/', {})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % p1.pk) < response.content.index(link % p2.pk)
- )
+ self.assertContentBefore(response, link % p1.pk, link % p2.pk)
def testMultipleSortSameField(self):
# Check that we get the columns we expect if we have two columns
@@ -339,17 +325,13 @@ class AdminViewBasicTest(TestCase):
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/podcast/', {})
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- response.content.index(link % p1.pk) < response.content.index(link % p2.pk)
- )
+ self.assertContentBefore(response, link % p1.pk, link % p2.pk)
p1 = ComplexSortedPerson.objects.create(name="Bob", age=10)
p2 = ComplexSortedPerson.objects.create(name="Amy", age=20)
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/complexsortedperson/', {})
- self.assertEqual(response.status_code, 200)
# Should have 5 columns (including action checkbox col)
self.assertContains(response, '<th scope="col"', count=5)
@@ -357,14 +339,10 @@ class AdminViewBasicTest(TestCase):
self.assertContains(response, 'Colored name')
# Check order
- self.assertTrue(
- response.content.index('Name') < response.content.index('Colored name')
- )
+ self.assertContentBefore(response, 'Name', 'Colored name')
# Check sorting - should be by name
- self.assertTrue(
- response.content.index(link % p2.id) < response.content.index(link % p1.id)
- )
+ self.assertContentBefore(response, link % p2.id, link % p1.id)
def testSortIndicatorsAdminOrder(self):
"""
@@ -389,8 +367,8 @@ class AdminViewBasicTest(TestCase):
# the implicit 'action_checkbox' and 1 being the column 'stuff'.
self.assertEqual(response.context['cl'].get_ordering_field_columns(), {2: 'asc'})
# Check order of records.
- self.assertTrue(response.content.index('The First Item') <
- response.content.index('The Middle Item') < response.content.index('The Last Item'))
+ self.assertContentBefore(response, 'The First Item', 'The Middle Item')
+ self.assertContentBefore(response, 'The Middle Item', 'The Last Item')
def testLimitedFilter(self):
"""Ensure admin changelist filters do not contain objects excluded via limit_choices_to.
@@ -480,12 +458,9 @@ class AdminViewBasicTest(TestCase):
has been used in the choices option of a field.
"""
response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
- self.assertTrue(
- '<a href="1/">Horizontal</a>' in response.content and
- '<a href="2/">Vertical</a>' in response.content,
- "Changelist table isn't showing the right human-readable values set by a model field 'choices' option named group."
- )
+ fail_msg = "Changelist table isn't showing the right human-readable values set by a model field 'choices' option named group."
+ self.assertContains(response, '<a href="1/">Horizontal</a>', msg_prefix=fail_msg, html=True)
+ self.assertContains(response, '<a href="2/">Vertical</a>', msg_prefix=fail_msg, html=True)
def testNamedGroupFieldChoicesFilter(self):
"""
@@ -493,13 +468,12 @@ class AdminViewBasicTest(TestCase):
been used in the choices option of a model field.
"""
response = self.client.get('/test_admin/%s/admin_views/fabric/' % self.urlbit)
- self.assertEqual(response.status_code, 200)
+ fail_msg = "Changelist filter isn't showing options contained inside a model field 'choices' option named group."
self.assertContains(response, '<div id="changelist-filter">')
- self.assertTrue(
- '<a href="?surface__exact=x">Horizontal</a>' in response.content and
- '<a href="?surface__exact=y">Vertical</a>' in response.content,
- "Changelist filter isn't showing options contained inside a model field 'choices' option named group."
- )
+ self.assertContains(response,
+ '<a href="?surface__exact=x">Horizontal</a>', msg_prefix=fail_msg, html=True)
+ self.assertContains(response,
+ '<a href="?surface__exact=y">Vertical</a>', msg_prefix=fail_msg, html=True)
def testChangeListNullBooleanDisplay(self):
Post.objects.create(public=None)
@@ -590,8 +564,8 @@ class AdminViewBasicTest(TestCase):
user.save()
response = self.client.get('/test_admin/admin/')
- self.assertFalse(reverse('admin:password_change') in response.content,
- msg='The "change password" link should not be displayed if a user does not have a usable password.')
+ self.assertNotContains(response, reverse('admin:password_change'),
+ msg_prefix='The "change password" link should not be displayed if a user does not have a usable password.')
def test_change_view_with_show_delete_extra_context(self):
"""
@@ -618,7 +592,7 @@ class AdminViewFormUrlTest(TestCase):
def testChangeFormUrlHasCorrectValue(self):
"""
- Tests whether change_view has form_url in request.context
+ Tests whether change_view has form_url in response.context
"""
response = self.client.get('/test_admin/%s/admin_views/section/1/' % self.urlbit)
self.assertTrue('form_url' in response.context, msg='form_url not present in response.context')
@@ -755,39 +729,39 @@ class CustomModelAdminTest(AdminViewBasicTest):
def testCustomAdminSiteLoginTemplate(self):
self.client.logout()
- request = self.client.get('/test_admin/admin2/')
- self.assertIsInstance(request, TemplateResponse)
- self.assertTemplateUsed(request, 'custom_admin/login.html')
- self.assertTrue('Hello from a custom login template' in request.content)
+ response = self.client.get('/test_admin/admin2/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/login.html')
+ self.assertContains(response, 'Hello from a custom login template')
def testCustomAdminSiteLogoutTemplate(self):
- request = self.client.get('/test_admin/admin2/logout/')
- self.assertIsInstance(request, TemplateResponse)
- self.assertTemplateUsed(request, 'custom_admin/logout.html')
- self.assertTrue('Hello from a custom logout template' in request.content)
+ response = self.client.get('/test_admin/admin2/logout/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/logout.html')
+ self.assertContains(response, 'Hello from a custom logout template')
def testCustomAdminSiteIndexViewAndTemplate(self):
- request = self.client.get('/test_admin/admin2/')
- self.assertIsInstance(request, TemplateResponse)
- self.assertTemplateUsed(request, 'custom_admin/index.html')
- self.assertTrue('Hello from a custom index template *bar*' in request.content)
+ response = self.client.get('/test_admin/admin2/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/index.html')
+ self.assertContains(response, 'Hello from a custom index template *bar*')
def testCustomAdminSitePasswordChangeTemplate(self):
- request = self.client.get('/test_admin/admin2/password_change/')
- self.assertIsInstance(request, TemplateResponse)
- self.assertTemplateUsed(request, 'custom_admin/password_change_form.html')
- self.assertTrue('Hello from a custom password change form template' in request.content)
+ response = self.client.get('/test_admin/admin2/password_change/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/password_change_form.html')
+ self.assertContains(response, 'Hello from a custom password change form template')
def testCustomAdminSitePasswordChangeDoneTemplate(self):
- request = self.client.get('/test_admin/admin2/password_change/done/')
- self.assertIsInstance(request, TemplateResponse)
- self.assertTemplateUsed(request, 'custom_admin/password_change_done.html')
- self.assertTrue('Hello from a custom password change done template' in request.content)
+ response = self.client.get('/test_admin/admin2/password_change/done/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/password_change_done.html')
+ self.assertContains(response, 'Hello from a custom password change done template')
def testCustomAdminSiteView(self):
self.client.login(username='super', password='secret')
response = self.client.get('/test_admin/%s/my_view/' % self.urlbit)
- self.assertEqual(response.content, "Django is a magical pony!")
+ self.assertEqual(response.content, b"Django is a magical pony!")
def get_perm(Model, perm):
"""Return the permission object, for the Model"""
@@ -885,16 +859,16 @@ class AdminViewPermissionsTest(TestCase):
a 200 status code.
"""
# Super User
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.super_login)
self.assertRedirects(login, '/test_admin/admin/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Test if user enters e-mail address
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.super_email_login)
self.assertContains(login, "Your e-mail address is not your username")
# only correct passwords get a username hint
@@ -907,47 +881,47 @@ class AdminViewPermissionsTest(TestCase):
self.assertContains(login, ERROR_MESSAGE)
# Add User
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.adduser_login)
self.assertRedirects(login, '/test_admin/admin/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Change User
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.changeuser_login)
self.assertRedirects(login, '/test_admin/admin/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Delete User
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.deleteuser_login)
self.assertRedirects(login, '/test_admin/admin/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Regular User should not be able to login.
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.joepublic_login)
self.assertEqual(login.status_code, 200)
self.assertContains(login, ERROR_MESSAGE)
# Requests without username should not return 500 errors.
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/', self.no_username_login)
self.assertEqual(login.status_code, 200)
form = login.context[0].get('form')
self.assertEqual(form.errors['username'][0], 'This field is required.')
def testLoginSuccessfullyRedirectsToOriginalUrl(self):
- request = self.client.get('/test_admin/admin/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
query_string = 'the-answer=42'
redirect_url = '/test_admin/admin/?%s' % query_string
new_next = {REDIRECT_FIELD_NAME: redirect_url}
@@ -967,8 +941,8 @@ class AdminViewPermissionsTest(TestCase):
self.client.post('/test_admin/admin/', self.changeuser_login)
# make sure the view removes test cookie
self.assertEqual(self.client.session.test_cookie_worked(), False)
- request = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(request.status_code, 403)
+ response = self.client.get('/test_admin/admin/admin_views/article/add/')
+ self.assertEqual(response.status_code, 403)
# Try POST just to make sure
post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
self.assertEqual(post.status_code, 403)
@@ -979,10 +953,9 @@ class AdminViewPermissionsTest(TestCase):
self.client.get('/test_admin/admin/')
self.client.post('/test_admin/admin/', self.adduser_login)
addpage = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(addpage.status_code, 200)
change_list_link = '&rsaquo; <a href="/test_admin/admin/admin_views/article/">Articles</a>'
- self.assertFalse(change_list_link in addpage.content,
- 'User restricted to add permission is given link to change list view in breadcrumbs.')
+ self.assertNotContains(addpage, change_list_link,
+ msg_prefix='User restricted to add permission is given link to change list view in breadcrumbs.')
post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
self.assertRedirects(post, '/test_admin/admin/')
self.assertEqual(Article.objects.all().count(), 4)
@@ -994,9 +967,8 @@ class AdminViewPermissionsTest(TestCase):
self.client.get('/test_admin/admin/')
self.client.post('/test_admin/admin/', self.super_login)
addpage = self.client.get('/test_admin/admin/admin_views/article/add/')
- self.assertEqual(addpage.status_code, 200)
- self.assertFalse(change_list_link not in addpage.content,
- 'Unrestricted user is not given link to change list view in breadcrumbs.')
+ self.assertContains(addpage, change_list_link,
+ msg_prefix='Unrestricted user is not given link to change list view in breadcrumbs.')
post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
self.assertRedirects(post, '/test_admin/admin/admin_views/article/')
self.assertEqual(Article.objects.all().count(), 5)
@@ -1022,10 +994,10 @@ class AdminViewPermissionsTest(TestCase):
# add user shoud not be able to view the list of article or change any of them
self.client.get('/test_admin/admin/')
self.client.post('/test_admin/admin/', self.adduser_login)
- request = self.client.get('/test_admin/admin/admin_views/article/')
- self.assertEqual(request.status_code, 403)
- request = self.client.get('/test_admin/admin/admin_views/article/1/')
- self.assertEqual(request.status_code, 403)
+ response = self.client.get('/test_admin/admin/admin_views/article/')
+ self.assertEqual(response.status_code, 403)
+ response = self.client.get('/test_admin/admin/admin_views/article/1/')
+ self.assertEqual(response.status_code, 403)
post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
self.assertEqual(post.status_code, 403)
self.client.get('/test_admin/admin/logout/')
@@ -1033,10 +1005,10 @@ class AdminViewPermissionsTest(TestCase):
# change user can view all items and edit them
self.client.get('/test_admin/admin/')
self.client.post('/test_admin/admin/', self.changeuser_login)
- request = self.client.get('/test_admin/admin/admin_views/article/')
- self.assertEqual(request.status_code, 200)
- request = self.client.get('/test_admin/admin/admin_views/article/1/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/admin_views/article/')
+ self.assertEqual(response.status_code, 200)
+ response = self.client.get('/test_admin/admin/admin_views/article/1/')
+ self.assertEqual(response.status_code, 200)
post = self.client.post('/test_admin/admin/admin_views/article/1/', change_dict)
self.assertRedirects(post, '/test_admin/admin/admin_views/article/')
self.assertEqual(Article.objects.get(pk=1).content, '<p>edited article</p>')
@@ -1058,33 +1030,33 @@ class AdminViewPermissionsTest(TestCase):
RowLevelChangePermissionModel.objects.create(id=2, name="even id")
for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
self.client.post('/test_admin/admin/', login_dict)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
- self.assertEqual(request.status_code, 403)
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
+ response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
+ self.assertEqual(response.status_code, 403)
+ response = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
self.assertEqual(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
- self.assertEqual(request.status_code, 403)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
- self.assertEqual(request.status_code, 200)
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed'})
+ self.assertEqual(response.status_code, 403)
+ response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
+ self.assertEqual(response.status_code, 200)
+ response = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed'})
self.assertEqual(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
- self.assertRedirects(request, '/test_admin/admin/')
+ self.assertRedirects(response, '/test_admin/admin/')
self.client.get('/test_admin/admin/logout/')
for login_dict in [self.joepublic_login, self.no_username_login]:
self.client.post('/test_admin/admin/', login_dict)
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
+ response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/')
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'login-form')
+ response = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/1/', {'name': 'changed'})
self.assertEqual(RowLevelChangePermissionModel.objects.get(id=1).name, 'odd id')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
- request = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed again'})
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'login-form')
+ response = self.client.get('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/')
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'login-form')
+ response = self.client.post('/test_admin/admin/admin_views/rowlevelchangepermissionmodel/2/', {'name': 'changed again'})
self.assertEqual(RowLevelChangePermissionModel.objects.get(id=2).name, 'changed')
- self.assertEqual(request.status_code, 200)
- self.assertContains(request, 'login-form')
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'login-form')
self.client.get('/test_admin/admin/logout/')
def testConditionallyShowAddSectionLink(self):
@@ -1114,14 +1086,13 @@ class AdminViewPermissionsTest(TestCase):
self.client.post('/test_admin/admin/', self.super_login)
# Test custom change list template with custom extra context
- request = self.client.get('/test_admin/admin/admin_views/customarticle/')
- self.assertEqual(request.status_code, 200)
- self.assertTrue("var hello = 'Hello!';" in request.content)
- self.assertTemplateUsed(request, 'custom_admin/change_list.html')
+ response = self.client.get('/test_admin/admin/admin_views/customarticle/')
+ self.assertContains(response, "var hello = 'Hello!';")
+ self.assertTemplateUsed(response, 'custom_admin/change_list.html')
# Test custom add form template
- request = self.client.get('/test_admin/admin/admin_views/customarticle/add/')
- self.assertTemplateUsed(request, 'custom_admin/add_form.html')
+ response = self.client.get('/test_admin/admin/admin_views/customarticle/add/')
+ self.assertTemplateUsed(response, 'custom_admin/add_form.html')
# Add an article so we can test delete, change, and history views
post = self.client.post('/test_admin/admin/admin_views/customarticle/add/', {
@@ -1135,18 +1106,18 @@ class AdminViewPermissionsTest(TestCase):
# Test custom delete, change, and object history templates
# Test custom change form template
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/change_form.html')
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/delete/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/delete_confirmation.html')
- request = self.client.post('/test_admin/admin/admin_views/customarticle/', data={
+ response = self.client.get('/test_admin/admin/admin_views/customarticle/%d/' % article_pk)
+ self.assertTemplateUsed(response, 'custom_admin/change_form.html')
+ response = self.client.get('/test_admin/admin/admin_views/customarticle/%d/delete/' % article_pk)
+ self.assertTemplateUsed(response, 'custom_admin/delete_confirmation.html')
+ response = self.client.post('/test_admin/admin/admin_views/customarticle/', data={
'index': 0,
'action': ['delete_selected'],
'_selected_action': ['1'],
})
- self.assertTemplateUsed(request, 'custom_admin/delete_selected_confirmation.html')
- request = self.client.get('/test_admin/admin/admin_views/customarticle/%d/history/' % article_pk)
- self.assertTemplateUsed(request, 'custom_admin/object_history.html')
+ self.assertTemplateUsed(response, 'custom_admin/delete_selected_confirmation.html')
+ response = self.client.get('/test_admin/admin/admin_views/customarticle/%d/history/' % article_pk)
+ self.assertTemplateUsed(response, 'custom_admin/object_history.html')
self.client.get('/test_admin/admin/logout/')
@@ -1158,8 +1129,8 @@ class AdminViewPermissionsTest(TestCase):
# add user shoud not be able to delete articles
self.client.get('/test_admin/admin/')
self.client.post('/test_admin/admin/', self.adduser_login)
- request = self.client.get('/test_admin/admin/admin_views/article/1/delete/')
- self.assertEqual(request.status_code, 403)
+ response = self.client.get('/test_admin/admin/admin_views/article/1/delete/')
+ self.assertEqual(response.status_code, 403)
post = self.client.post('/test_admin/admin/admin_views/article/1/delete/', delete_dict)
self.assertEqual(post.status_code, 403)
self.assertEqual(Article.objects.all().count(), 3)
@@ -1246,9 +1217,9 @@ class AdminViewDeletedObjectsTest(TestCase):
Objects should be nested to display the relationships that
cause them to be scheduled for deletion.
"""
- pattern = re.compile(r"""<li>Plot: <a href=".+/admin_views/plot/1/">World Domination</a>\s*<ul>\s*<li>Plot details: <a href=".+/admin_views/plotdetails/1/">almost finished</a>""")
+ pattern = re.compile(br"""<li>Plot: <a href=".+/admin_views/plot/1/">World Domination</a>\s*<ul>\s*<li>Plot details: <a href=".+/admin_views/plotdetails/1/">almost finished</a>""")
response = self.client.get('/test_admin/admin/admin_views/villain/%s/delete/' % quote(1))
- self.assertTrue(pattern.search(response.content))
+ self.assertRegexpMatches(response.content, pattern)
def test_cyclic(self):
"""
@@ -1407,9 +1378,9 @@ class AdminViewStringPrimaryKeyTest(TestCase):
logentry.content_type = None
logentry.save()
- counted_presence_before = response.content.count(should_contain)
+ counted_presence_before = response.content.count(force_bytes(should_contain))
response = self.client.get('/test_admin/admin/')
- counted_presence_after = response.content.count(should_contain)
+ counted_presence_after = response.content.count(force_bytes(should_contain))
self.assertEqual(counted_presence_before - 1,
counted_presence_after)
@@ -1512,8 +1483,8 @@ class SecureViewTests(TestCase):
self.assertTemplateUsed(response, 'admin/login.html')
def test_secure_view_login_successfully_redirects_to_original_url(self):
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
query_string = 'the-answer=42'
redirect_url = '/test_admin/admin/secure-view/?%s' % query_string
new_next = {REDIRECT_FIELD_NAME: redirect_url}
@@ -1529,8 +1500,8 @@ class SecureViewTests(TestCase):
a 200 status code.
"""
# Super User
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.super_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
@@ -1539,8 +1510,8 @@ class SecureViewTests(TestCase):
self.assertEqual(self.client.session.test_cookie_worked(), False)
# Test if user enters e-mail address
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.super_email_login)
self.assertContains(login, "Your e-mail address is not your username")
# only correct passwords get a username hint
@@ -1553,32 +1524,32 @@ class SecureViewTests(TestCase):
self.assertContains(login, ERROR_MESSAGE)
# Add User
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.adduser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Change User
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.changeuser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Delete User
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.deleteuser_login)
self.assertRedirects(login, '/test_admin/admin/secure-view/')
self.assertFalse(login.context)
self.client.get('/test_admin/admin/logout/')
# Regular User should not be able to login.
- request = self.client.get('/test_admin/admin/secure-view/')
- self.assertEqual(request.status_code, 200)
+ response = self.client.get('/test_admin/admin/secure-view/')
+ self.assertEqual(response.status_code, 200)
login = self.client.post('/test_admin/admin/secure-view/', self.joepublic_login)
self.assertEqual(login.status_code, 200)
# Login.context is a list of context dicts we just need to check the first one.
@@ -2107,7 +2078,7 @@ class AdminInheritedInlinesTest(TestCase):
foo_user = "foo username"
bar_user = "bar username"
- name_re = re.compile('name="(.*?)"')
+ name_re = re.compile(b'name="(.*?)"')
# test the add case
response = self.client.get('/test_admin/admin/admin_views/persona/add/')
@@ -2214,7 +2185,7 @@ class AdminActionsTest(TestCase):
confirmation = self.client.post('/test_admin/admin/admin_views/subscriber/', action_data)
self.assertIsInstance(confirmation, TemplateResponse)
self.assertContains(confirmation, "Are you sure you want to delete the selected subscribers?")
- self.assertTrue(confirmation.content.count(ACTION_CHECKBOX_NAME) == 2)
+ self.assertContains(confirmation, ACTION_CHECKBOX_NAME, count=2)
response = self.client.post('/test_admin/admin/admin_views/subscriber/', delete_confirmation_data)
self.assertEqual(Subscriber.objects.count(), 0)
@@ -2390,7 +2361,7 @@ class AdminActionsTest(TestCase):
def test_popup_actions(self):
""" Actions should not be shown in popups. """
response = self.client.get('/test_admin/admin/admin_views/subscriber/')
- self.assertNotEquals(response.context["action_form"], None)
+ self.assertNotEqual(response.context["action_form"], None)
response = self.client.get(
'/test_admin/admin/admin_views/subscriber/?%s' % IS_POPUP_VAR)
self.assertEqual(response.context["action_form"], None)
@@ -2514,7 +2485,7 @@ class AdminInlineFileUploadTest(TestCase):
# to use a NamedTemporaryFile.
tdir = tempfile.gettempdir()
file1 = tempfile.NamedTemporaryFile(suffix=".file1", dir=tdir)
- file1.write('a' * (2 ** 21))
+ file1.write(b'a' * (2 ** 21))
filename = file1.name
file1.close()
self.gallery = Gallery(name="Test Gallery")
@@ -3197,9 +3168,9 @@ class RawIdFieldsTest(TestCase):
country="Spain")
response = self.client.get('/test_admin/admin/admin_views/sketch/add/')
# Find the link
- m = re.search(r'<a href="([^"]*)"[^>]* id="lookup_id_inquisition"', response.content)
+ m = re.search(br'<a href="([^"]*)"[^>]* id="lookup_id_inquisition"', response.content)
self.assertTrue(m) # Got a match
- popup_url = m.groups()[0].replace("&amp;", "&")
+ popup_url = m.groups()[0].decode().replace("&amp;", "&")
# Handle relative links
popup_url = urljoin(response.request['PATH_INFO'], popup_url)
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py
index 81a4ec7aba..2e452798b7 100644
--- a/tests/regressiontests/admin_widgets/models.py
+++ b/tests/regressiontests/admin_widgets/models.py
@@ -2,39 +2,44 @@ from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
+from django.utils.encoding import python_2_unicode_compatible
class MyFileField(models.FileField):
pass
+@python_2_unicode_compatible
class Member(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateTimeField(blank=True, null=True)
gender = models.CharField(max_length=1, blank=True, choices=[('M','Male'), ('F', 'Female')])
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Band(models.Model):
name = models.CharField(max_length=100)
members = models.ManyToManyField(Member)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Album(models.Model):
band = models.ForeignKey(Band)
name = models.CharField(max_length=100)
cover_art = models.FileField(upload_to='albums')
backside_art = MyFileField(upload_to='albums_back', null=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
class HiddenInventoryManager(models.Manager):
def get_query_set(self):
return super(HiddenInventoryManager, self).get_query_set().filter(hidden=False)
+@python_2_unicode_compatible
class Inventory(models.Model):
barcode = models.PositiveIntegerField(unique=True)
parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True)
@@ -45,7 +50,7 @@ class Inventory(models.Model):
default_manager = models.Manager()
objects = HiddenInventoryManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
class Event(models.Model):
@@ -56,12 +61,13 @@ class Event(models.Model):
link = models.URLField(blank=True)
min_age = models.IntegerField(blank=True, null=True)
+@python_2_unicode_compatible
class Car(models.Model):
owner = models.ForeignKey(User)
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.make, self.model)
class CarTire(models.Model):
@@ -103,19 +109,21 @@ class Advisor(models.Model):
companies = models.ManyToManyField(Company)
+@python_2_unicode_compatible
class Student(models.Model):
name = models.CharField(max_length=255)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
ordering = ('name',)
+@python_2_unicode_compatible
class School(models.Model):
name = models.CharField(max_length=255)
students = models.ManyToManyField(Student, related_name='current_schools')
alumni = models.ManyToManyField(Student, related_name='previous_schools')
- def __unicode__(self):
- return self.name \ No newline at end of file
+ def __str__(self):
+ return self.name
diff --git a/tests/regressiontests/aggregation_regress/models.py b/tests/regressiontests/aggregation_regress/models.py
index ccef9a5fc8..dd4ff50aec 100644
--- a/tests/regressiontests/aggregation_regress/models.py
+++ b/tests/regressiontests/aggregation_regress/models.py
@@ -1,24 +1,28 @@
# coding: utf-8
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
friends = models.ManyToManyField('self', blank=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Publisher(models.Model):
name = models.CharField(max_length=255)
num_awards = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Book(models.Model):
isbn = models.CharField(max_length=9)
name = models.CharField(max_length=255)
@@ -33,17 +37,18 @@ class Book(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Store(models.Model):
name = models.CharField(max_length=255)
books = models.ManyToManyField(Book)
original_opening = models.DateTimeField()
friday_night_closing = models.TimeField()
- def __unicode__(self):
+ def __str__(self):
return self.name
class Entries(models.Model):
@@ -58,8 +63,9 @@ class Clues(models.Model):
Clue = models.CharField(max_length=150)
+@python_2_unicode_compatible
class HardbackBook(Book):
weight = models.FloatField()
- def __unicode__(self):
+ def __str__(self):
return "%s (hardback): %s" % (self.name, self.weight)
diff --git a/tests/regressiontests/aggregation_regress/tests.py b/tests/regressiontests/aggregation_regress/tests.py
index e24eb43b87..b9f3ab27eb 100644
--- a/tests/regressiontests/aggregation_regress/tests.py
+++ b/tests/regressiontests/aggregation_regress/tests.py
@@ -866,3 +866,15 @@ class AggregationTests(TestCase):
['Peter Norvig'],
lambda b: b.name
)
+
+ def test_type_conversion(self):
+ # The database backend convert_values function should not try to covert
+ # CharFields to float. Refs #13844.
+ from django.db.models import CharField
+ from django.db import connection
+ testData = 'not_a_float_value'
+ testField = CharField()
+ self.assertEqual(
+ connection.ops.convert_values(testData, testField),
+ testData
+ )
diff --git a/tests/regressiontests/backends/models.py b/tests/regressiontests/backends/models.py
index af4952dce8..344cf4c798 100644
--- a/tests/regressiontests/backends/models.py
+++ b/tests/regressiontests/backends/models.py
@@ -3,21 +3,24 @@ from __future__ import unicode_literals
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models, connection
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Square(models.Model):
root = models.IntegerField()
square = models.PositiveIntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s ** 2 == %s" % (self.root, self.square)
+@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
@@ -55,18 +58,20 @@ class Post(models.Model):
db_table = 'CaseSensitive_Post'
+@python_2_unicode_compatible
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
- def __unicode__(self):
+ def __str__(self):
return self.headline
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index a6425c5591..dc92189344 100644
--- a/tests/regressiontests/backends/tests.py
+++ b/tests/regressiontests/backends/tests.py
@@ -584,7 +584,7 @@ class ThreadTests(TestCase):
connections['default'] = main_thread_connection
try:
models.Person.objects.get(first_name="John", last_name="Doe")
- except DatabaseError as e:
+ except Exception as e:
exceptions.append(e)
t = threading.Thread(target=runner, args=[connections['default']])
t.start()
@@ -594,21 +594,21 @@ class ThreadTests(TestCase):
exceptions = []
do_thread()
# Forbidden!
- self.assertTrue(isinstance(exceptions[0], DatabaseError))
+ self.assertIsInstance(exceptions[0], DatabaseError)
# If explicitly setting allow_thread_sharing to False
connections['default'].allow_thread_sharing = False
exceptions = []
do_thread()
# Forbidden!
- self.assertTrue(isinstance(exceptions[0], DatabaseError))
+ self.assertIsInstance(exceptions[0], DatabaseError)
# If explicitly setting allow_thread_sharing to True
connections['default'].allow_thread_sharing = True
exceptions = []
do_thread()
# All good
- self.assertEqual(len(exceptions), 0)
+ self.assertEqual(exceptions, [])
def test_closing_non_shared_connections(self):
"""
diff --git a/tests/regressiontests/builtin_server/tests.py b/tests/regressiontests/builtin_server/tests.py
index 4a3b44176b..c8dc77e42e 100644
--- a/tests/regressiontests/builtin_server/tests.py
+++ b/tests/regressiontests/builtin_server/tests.py
@@ -1,5 +1,8 @@
+from __future__ import unicode_literals
+
+from io import BytesIO
+
from django.core.servers.basehttp import ServerHandler
-from django.utils.six import StringIO
from django.utils.unittest import TestCase
#
@@ -23,12 +26,12 @@ class FileWrapperHandler(ServerHandler):
return True
def wsgi_app(environ, start_response):
- start_response('200 OK', [('Content-Type', 'text/plain')])
- return ['Hello World!']
+ start_response(str('200 OK'), [(str('Content-Type'), str('text/plain'))])
+ return [b'Hello World!']
def wsgi_app_file_wrapper(environ, start_response):
- start_response('200 OK', [('Content-Type', 'text/plain')])
- return environ['wsgi.file_wrapper'](StringIO('foo'))
+ start_response(str('200 OK'), [(str('Content-Type'), str('text/plain'))])
+ return environ['wsgi.file_wrapper'](BytesIO(b'foo'))
class WSGIFileWrapperTests(TestCase):
"""
@@ -37,15 +40,16 @@ class WSGIFileWrapperTests(TestCase):
def test_file_wrapper_uses_sendfile(self):
env = {'SERVER_PROTOCOL': 'HTTP/1.0'}
- err = StringIO()
- handler = FileWrapperHandler(None, StringIO(), err, env)
+ handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
handler.run(wsgi_app_file_wrapper)
self.assertTrue(handler._used_sendfile)
+ self.assertEqual(handler.stdout.getvalue(), b'')
+ self.assertEqual(handler.stderr.getvalue(), b'')
def test_file_wrapper_no_sendfile(self):
env = {'SERVER_PROTOCOL': 'HTTP/1.0'}
- err = StringIO()
- handler = FileWrapperHandler(None, StringIO(), err, env)
+ handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
handler.run(wsgi_app)
self.assertFalse(handler._used_sendfile)
- self.assertEqual(handler.stdout.getvalue().splitlines()[-1],'Hello World!')
+ self.assertEqual(handler.stdout.getvalue().splitlines()[-1], b'Hello World!')
+ self.assertEqual(handler.stderr.getvalue(), b'')
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index 8fc749aaa2..a6534c5f54 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -6,7 +6,9 @@ from __future__ import absolute_import, unicode_literals
import hashlib
import os
+import random
import re
+import string
import tempfile
import time
import warnings
@@ -364,25 +366,25 @@ class BaseCacheTests(object):
# Binary strings should be cacheable
from zlib import compress, decompress
value = 'value_to_be_compressed'
- compressed_value = compress(value)
+ compressed_value = compress(value.encode())
# Test set
self.cache.set('binary1', compressed_value)
compressed_result = self.cache.get('binary1')
self.assertEqual(compressed_value, compressed_result)
- self.assertEqual(value, decompress(compressed_result))
+ self.assertEqual(value, decompress(compressed_result).decode())
# Test add
self.cache.add('binary1-add', compressed_value)
compressed_result = self.cache.get('binary1-add')
self.assertEqual(compressed_value, compressed_result)
- self.assertEqual(value, decompress(compressed_result))
+ self.assertEqual(value, decompress(compressed_result).decode())
# Test set_many
self.cache.set_many({'binary1-set_many': compressed_value})
compressed_result = self.cache.get('binary1-set_many')
self.assertEqual(compressed_value, compressed_result)
- self.assertEqual(value, decompress(compressed_result))
+ self.assertEqual(value, decompress(compressed_result).decode())
def test_set_many(self):
# Multiple keys can be set using set_many
@@ -774,13 +776,13 @@ class BaseCacheTests(object):
get_cache_data = fetch_middleware.process_request(request)
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(get_cache_data.content, content)
+ self.assertEqual(get_cache_data.content, content.encode('utf-8'))
self.assertEqual(get_cache_data.cookies, response.cookies)
update_middleware.process_response(request, get_cache_data)
get_cache_data = fetch_middleware.process_request(request)
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(get_cache_data.content, content)
+ self.assertEqual(get_cache_data.content, content.encode('utf-8'))
self.assertEqual(get_cache_data.cookies, response.cookies)
def custom_key_func(key, key_prefix, version):
@@ -932,21 +934,24 @@ class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
# memcached backend isn't guaranteed to be available.
# To check the memcached backend, the test settings file will
-# need to contain a cache backend setting that points at
+# need to contain at least one cache backend setting that points at
# your memcache server.
@unittest.skipUnless(
- settings.CACHES[DEFAULT_CACHE_ALIAS]['BACKEND'].startswith('django.core.cache.backends.memcached.'),
+ any(cache['BACKEND'].startswith('django.core.cache.backends.memcached.')
+ for cache in settings.CACHES.values()),
"memcached not available")
class MemcachedCacheTests(unittest.TestCase, BaseCacheTests):
- backend_name = 'django.core.cache.backends.memcached.MemcachedCache'
def setUp(self):
- name = settings.CACHES[DEFAULT_CACHE_ALIAS]['LOCATION']
- self.cache = get_cache(self.backend_name, LOCATION=name)
- self.prefix_cache = get_cache(self.backend_name, LOCATION=name, KEY_PREFIX='cacheprefix')
- self.v2_cache = get_cache(self.backend_name, LOCATION=name, VERSION=2)
- self.custom_key_cache = get_cache(self.backend_name, LOCATION=name, KEY_FUNCTION=custom_key_func)
- self.custom_key_cache2 = get_cache(self.backend_name, LOCATION=name, KEY_FUNCTION='regressiontests.cache.tests.custom_key_func')
+ for cache_key, cache in settings.CACHES.items():
+ if cache['BACKEND'].startswith('django.core.cache.backends.memcached.'):
+ break
+ random_prefix = ''.join(random.choice(string.ascii_letters) for x in range(10))
+ self.cache = get_cache(cache_key)
+ self.prefix_cache = get_cache(cache_key, KEY_PREFIX=random_prefix)
+ self.v2_cache = get_cache(cache_key, VERSION=2)
+ self.custom_key_cache = get_cache(cache_key, KEY_FUNCTION=custom_key_func)
+ self.custom_key_cache2 = get_cache(cache_key, KEY_FUNCTION='regressiontests.cache.tests.custom_key_func')
def tearDown(self):
self.cache.clear()
@@ -988,7 +993,7 @@ class FileBasedCacheTests(unittest.TestCase, BaseCacheTests):
"""Test that keys are hashed into subdirectories correctly"""
self.cache.set("foo", "bar")
key = self.cache.make_key("foo")
- keyhash = hashlib.md5(key).hexdigest()
+ keyhash = hashlib.md5(key.encode()).hexdigest()
keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
self.assertTrue(os.path.exists(keypath))
@@ -998,7 +1003,7 @@ class FileBasedCacheTests(unittest.TestCase, BaseCacheTests):
"""
self.cache.set("foo", "bar")
key = self.cache.make_key("foo")
- keyhash = hashlib.md5(key).hexdigest()
+ keyhash = hashlib.md5(key.encode()).hexdigest()
keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
self.assertTrue(os.path.exists(keypath))
@@ -1222,7 +1227,7 @@ class CacheHEADTest(TestCase):
request = self._get_request('HEAD')
get_cache_data = FetchFromCacheMiddleware().process_request(request)
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(test_content, get_cache_data.content)
+ self.assertEqual(test_content.encode(), get_cache_data.content)
def test_head_with_cached_get(self):
test_content = 'test content'
@@ -1233,7 +1238,7 @@ class CacheHEADTest(TestCase):
request = self._get_request('HEAD')
get_cache_data = FetchFromCacheMiddleware().process_request(request)
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(test_content, get_cache_data.content)
+ self.assertEqual(test_content.encode(), get_cache_data.content)
@override_settings(
@@ -1308,7 +1313,7 @@ class CacheI18nTest(TestCase):
# This is tightly coupled to the implementation,
# but it's the most straightforward way to test the key.
tz = force_text(timezone.get_current_timezone_name(), errors='ignore')
- tz = tz.encode('ascii', 'ignore').replace(' ', '_')
+ tz = tz.encode('ascii', 'ignore').decode('ascii').replace(' ', '_')
response = HttpResponse()
key = learn_cache_key(request, response)
self.assertIn(tz, key, "Cache keys should include the time zone name when time zones are active")
@@ -1320,7 +1325,7 @@ class CacheI18nTest(TestCase):
request = self._get_request()
lang = translation.get_language()
tz = force_text(timezone.get_current_timezone_name(), errors='ignore')
- tz = tz.encode('ascii', 'ignore').replace(' ', '_')
+ tz = tz.encode('ascii', 'ignore').decode('ascii').replace(' ', '_')
response = HttpResponse()
key = learn_cache_key(request, response)
self.assertNotIn(lang, key, "Cache keys shouldn't include the language name when i18n isn't active")
@@ -1373,7 +1378,7 @@ class CacheI18nTest(TestCase):
get_cache_data = FetchFromCacheMiddleware().process_request(request)
# cache must return content
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(get_cache_data.content, content)
+ self.assertEqual(get_cache_data.content, content.encode())
# different QUERY_STRING, cache must be empty
request = self._get_request_cache(query_string='foo=bar&somethingelse=true')
get_cache_data = FetchFromCacheMiddleware().process_request(request)
@@ -1388,7 +1393,7 @@ class CacheI18nTest(TestCase):
get_cache_data = FetchFromCacheMiddleware().process_request(request)
# Check that we can recover the cache
self.assertNotEqual(get_cache_data, None)
- self.assertEqual(get_cache_data.content, en_message)
+ self.assertEqual(get_cache_data.content, en_message.encode())
# Check that we use etags
self.assertTrue(get_cache_data.has_header('ETag'))
# Check that we can disable etags
@@ -1404,11 +1409,11 @@ class CacheI18nTest(TestCase):
translation.activate('en')
# retrieve the content from cache
get_cache_data = FetchFromCacheMiddleware().process_request(request)
- self.assertEqual(get_cache_data.content, en_message)
+ self.assertEqual(get_cache_data.content, en_message.encode())
# change again the language
translation.activate('es')
get_cache_data = FetchFromCacheMiddleware().process_request(request)
- self.assertEqual(get_cache_data.content, es_message)
+ self.assertEqual(get_cache_data.content, es_message.encode())
# reset the language
translation.deactivate()
@@ -1513,8 +1518,8 @@ class CacheMiddlewareTest(TestCase):
# Repeating the request should result in a cache hit
result = middleware.process_request(request)
- self.assertNotEquals(result, None)
- self.assertEqual(result.content, 'Hello World 1')
+ self.assertNotEqual(result, None)
+ self.assertEqual(result.content, b'Hello World 1')
# The same request through a different middleware won't hit
result = prefix_middleware.process_request(request)
@@ -1522,8 +1527,8 @@ class CacheMiddlewareTest(TestCase):
# The same request with a timeout _will_ hit
result = timeout_middleware.process_request(request)
- self.assertNotEquals(result, None)
- self.assertEqual(result.content, 'Hello World 1')
+ self.assertNotEqual(result, None)
+ self.assertEqual(result.content, b'Hello World 1')
@override_settings(CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True)
def test_cache_middleware_anonymous_only_wont_cause_session_access(self):
@@ -1592,43 +1597,43 @@ class CacheMiddlewareTest(TestCase):
# Request the view once
response = default_view(request, '1')
- self.assertEqual(response.content, 'Hello World 1')
+ self.assertEqual(response.content, b'Hello World 1')
# Request again -- hit the cache
response = default_view(request, '2')
- self.assertEqual(response.content, 'Hello World 1')
+ self.assertEqual(response.content, b'Hello World 1')
# Requesting the same view with the explicit cache should yield the same result
response = explicit_default_view(request, '3')
- self.assertEqual(response.content, 'Hello World 1')
+ self.assertEqual(response.content, b'Hello World 1')
# Requesting with a prefix will hit a different cache key
response = explicit_default_with_prefix_view(request, '4')
- self.assertEqual(response.content, 'Hello World 4')
+ self.assertEqual(response.content, b'Hello World 4')
# Hitting the same view again gives a cache hit
response = explicit_default_with_prefix_view(request, '5')
- self.assertEqual(response.content, 'Hello World 4')
+ self.assertEqual(response.content, b'Hello World 4')
# And going back to the implicit cache will hit the same cache
response = default_with_prefix_view(request, '6')
- self.assertEqual(response.content, 'Hello World 4')
+ self.assertEqual(response.content, b'Hello World 4')
# Requesting from an alternate cache won't hit cache
response = other_view(request, '7')
- self.assertEqual(response.content, 'Hello World 7')
+ self.assertEqual(response.content, b'Hello World 7')
# But a repeated hit will hit cache
response = other_view(request, '8')
- self.assertEqual(response.content, 'Hello World 7')
+ self.assertEqual(response.content, b'Hello World 7')
# And prefixing the alternate cache yields yet another cache entry
response = other_with_prefix_view(request, '9')
- self.assertEqual(response.content, 'Hello World 9')
+ self.assertEqual(response.content, b'Hello World 9')
# Request from the alternate cache with a new prefix and a custom timeout
response = other_with_timeout_view(request, '10')
- self.assertEqual(response.content, 'Hello World 10')
+ self.assertEqual(response.content, b'Hello World 10')
# But if we wait a couple of seconds...
time.sleep(2)
@@ -1636,38 +1641,38 @@ class CacheMiddlewareTest(TestCase):
# ... the default cache will still hit
cache = get_cache('default')
response = default_view(request, '11')
- self.assertEqual(response.content, 'Hello World 1')
+ self.assertEqual(response.content, b'Hello World 1')
# ... the default cache with a prefix will still hit
response = default_with_prefix_view(request, '12')
- self.assertEqual(response.content, 'Hello World 4')
+ self.assertEqual(response.content, b'Hello World 4')
# ... the explicit default cache will still hit
response = explicit_default_view(request, '13')
- self.assertEqual(response.content, 'Hello World 1')
+ self.assertEqual(response.content, b'Hello World 1')
# ... the explicit default cache with a prefix will still hit
response = explicit_default_with_prefix_view(request, '14')
- self.assertEqual(response.content, 'Hello World 4')
+ self.assertEqual(response.content, b'Hello World 4')
# .. but a rapidly expiring cache won't hit
response = other_view(request, '15')
- self.assertEqual(response.content, 'Hello World 15')
+ self.assertEqual(response.content, b'Hello World 15')
# .. even if it has a prefix
response = other_with_prefix_view(request, '16')
- self.assertEqual(response.content, 'Hello World 16')
+ self.assertEqual(response.content, b'Hello World 16')
# ... but a view with a custom timeout will still hit
response = other_with_timeout_view(request, '17')
- self.assertEqual(response.content, 'Hello World 10')
+ self.assertEqual(response.content, b'Hello World 10')
# And if we wait a few more seconds
time.sleep(2)
- # the custom timeouot cache will miss
+ # the custom timeout cache will miss
response = other_with_timeout_view(request, '18')
- self.assertEqual(response.content, 'Hello World 18')
+ self.assertEqual(response.content, b'Hello World 18')
@override_settings(
diff --git a/tests/regressiontests/comment_tests/models.py b/tests/regressiontests/comment_tests/models.py
index 4093af14b5..472b66decd 100644
--- a/tests/regressiontests/comment_tests/models.py
+++ b/tests/regressiontests/comment_tests/models.py
@@ -3,9 +3,13 @@ Comments may be attached to any object. See the comment documentation for
more information.
"""
+from __future__ import unicode_literals
+
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
@@ -13,6 +17,7 @@ class Author(models.Model):
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Article(models.Model):
author = models.ForeignKey(Author)
headline = models.CharField(max_length=100)
@@ -20,6 +25,7 @@ class Article(models.Model):
def __str__(self):
return self.headline
+@python_2_unicode_compatible
class Entry(models.Model):
title = models.CharField(max_length=250)
body = models.TextField()
diff --git a/tests/regressiontests/conditional_processing/models.py b/tests/regressiontests/conditional_processing/models.py
index d1a8ac605b..d0838e153d 100644
--- a/tests/regressiontests/conditional_processing/models.py
+++ b/tests/regressiontests/conditional_processing/models.py
@@ -1,4 +1,6 @@
# -*- coding:utf-8 -*-
+from __future__ import unicode_literals
+
from datetime import datetime
from django.test import TestCase
@@ -20,7 +22,7 @@ class ConditionalGet(TestCase):
def assertFullResponse(self, response, check_last_modified=True, check_etag=True):
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, FULL_RESPONSE)
+ self.assertEqual(response.content, FULL_RESPONSE.encode())
if check_last_modified:
self.assertEqual(response['Last-Modified'], LAST_MODIFIED_STR)
if check_etag:
@@ -28,7 +30,7 @@ class ConditionalGet(TestCase):
def assertNotModified(self, response):
self.assertEqual(response.status_code, 304)
- self.assertEqual(response.content, '')
+ self.assertEqual(response.content, b'')
def testWithoutConditions(self):
response = self.client.get('/condition/')
diff --git a/tests/regressiontests/csrf_tests/tests.py b/tests/regressiontests/csrf_tests/tests.py
index 52fd3ea1c7..c5b66a31d1 100644
--- a/tests/regressiontests/csrf_tests/tests.py
+++ b/tests/regressiontests/csrf_tests/tests.py
@@ -216,7 +216,7 @@ class CsrfViewMiddlewareTest(TestCase):
"""
req = self._get_GET_no_csrf_cookie_request()
resp = token_view(req)
- self.assertEqual("", resp.content)
+ self.assertEqual(resp.content, b'')
def test_token_node_empty_csrf_cookie(self):
"""
diff --git a/tests/regressiontests/custom_columns_regress/models.py b/tests/regressiontests/custom_columns_regress/models.py
index c768c12772..169b2246c3 100644
--- a/tests/regressiontests/custom_columns_regress/models.py
+++ b/tests/regressiontests/custom_columns_regress/models.py
@@ -8,26 +8,29 @@ table creation or queries.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
Article_ID = models.AutoField(primary_key=True, db_column='Article ID')
headline = models.CharField(max_length=100)
authors = models.ManyToManyField('Author', db_table='my m2m table')
primary_author = models.ForeignKey('Author', db_column='Author ID', related_name='primary_set')
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
ordering = ('headline',)
+@python_2_unicode_compatible
class Author(models.Model):
Author_ID = models.AutoField(primary_key=True, db_column='Author ID')
first_name = models.CharField(max_length=30, db_column='first name')
last_name = models.CharField(max_length=30, db_column='last name')
- def __unicode__(self):
+ def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
class Meta:
diff --git a/tests/regressiontests/custom_managers_regress/models.py b/tests/regressiontests/custom_managers_regress/models.py
index 3c4e621769..71073f0fe7 100644
--- a/tests/regressiontests/custom_managers_regress/models.py
+++ b/tests/regressiontests/custom_managers_regress/models.py
@@ -3,6 +3,7 @@ Regression tests for custom manager classes.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class RestrictedManager(models.Manager):
@@ -12,12 +13,14 @@ class RestrictedManager(models.Manager):
def get_query_set(self):
return super(RestrictedManager, self).get_query_set().filter(is_public=True)
+@python_2_unicode_compatible
class RelatedModel(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class RestrictedModel(models.Model):
name = models.CharField(max_length=50)
is_public = models.BooleanField(default=False)
@@ -26,9 +29,10 @@ class RestrictedModel(models.Model):
objects = RestrictedManager()
plain_manager = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class OneToOneRestrictedModel(models.Model):
name = models.CharField(max_length=50)
is_public = models.BooleanField(default=False)
@@ -37,5 +41,5 @@ class OneToOneRestrictedModel(models.Model):
objects = RestrictedManager()
plain_manager = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/datatypes/models.py b/tests/regressiontests/datatypes/models.py
index 332ce84307..8e6027dd0f 100644
--- a/tests/regressiontests/datatypes/models.py
+++ b/tests/regressiontests/datatypes/models.py
@@ -4,8 +4,10 @@ types, which in the past were problematic for some database backends.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Donut(models.Model):
name = models.CharField(max_length=100)
is_frosted = models.BooleanField(default=False)
diff --git a/tests/regressiontests/dates/models.py b/tests/regressiontests/dates/models.py
index e1fc1e74fe..e4bffb7199 100644
--- a/tests/regressiontests/dates/models.py
+++ b/tests/regressiontests/dates/models.py
@@ -1,22 +1,25 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Article(models.Model):
title = models.CharField(max_length=100)
pub_date = models.DateField()
categories = models.ManyToManyField("Category", related_name="articles")
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Comment(models.Model):
article = models.ForeignKey(Article, related_name="comments")
text = models.TextField()
pub_date = models.DateField()
approval_date = models.DateField(null=True)
- def __unicode__(self):
+ def __str__(self):
return 'Comment to %s (%s)' % (self.article.title, self.pub_date)
class Category(models.Model):
diff --git a/tests/regressiontests/decorators/tests.py b/tests/regressiontests/decorators/tests.py
index dceaa62abc..7dc36aa479 100644
--- a/tests/regressiontests/decorators/tests.py
+++ b/tests/regressiontests/decorators/tests.py
@@ -220,7 +220,7 @@ class MethodDecoratorTests(TestCase):
self.assertEqual(getattr(Test.method, 'myattr2', False), True)
self.assertEqual(Test.method.__doc__, 'A method')
- self.assertEqual(Test.method.__func__.__name__, 'method')
+ self.assertEqual(Test.method.__name__, 'method')
class XFrameOptionsDecoratorsTests(TestCase):
diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py
index 2852572d32..bdf3c867c6 100644
--- a/tests/regressiontests/defaultfilters/tests.py
+++ b/tests/regressiontests/defaultfilters/tests.py
@@ -9,6 +9,7 @@ from django.test import TestCase
from django.utils import six
from django.utils import unittest, translation
from django.utils.safestring import SafeData
+from django.utils.encoding import python_2_unicode_compatible
class DefaultFiltersTests(TestCase):
@@ -456,10 +457,11 @@ class DefaultFiltersTests(TestCase):
'Lawrence</li>\n\t\t\t<li>Topeka</li>\n\t\t</ul>\n\t\t</li>'\
'\n\t\t<li>Illinois</li>\n\t</ul>\n\t</li>')
+ @python_2_unicode_compatible
class ULItem(object):
def __init__(self, title):
self.title = title
- def __unicode__(self):
+ def __str__(self):
return 'ulitem-%s' % str(self.title)
a = ULItem('a')
diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py
index bd4f845f27..d02adccde9 100644
--- a/tests/regressiontests/defer_regress/models.py
+++ b/tests/regressiontests/defer_regress/models.py
@@ -3,15 +3,17 @@ Regression tests for defer() / only() behavior.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Item(models.Model):
name = models.CharField(max_length=15)
text = models.TextField(default="xyzzy")
value = models.IntegerField()
other_value = models.IntegerField(default=0)
- def __unicode__(self):
+ def __str__(self):
return self.name
class RelatedItem(models.Model):
@@ -21,13 +23,14 @@ class Child(models.Model):
name = models.CharField(max_length=10)
value = models.IntegerField()
+@python_2_unicode_compatible
class Leaf(models.Model):
name = models.CharField(max_length=10)
child = models.ForeignKey(Child)
second_child = models.ForeignKey(Child, related_name="other", null=True)
value = models.IntegerField(default=42)
- def __unicode__(self):
+ def __str__(self):
return self.name
class ResolveThis(models.Model):
@@ -38,11 +41,12 @@ class Proxy(Item):
class Meta:
proxy = True
+@python_2_unicode_compatible
class SimpleItem(models.Model):
name = models.CharField(max_length=15)
value = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
class Feature(models.Model):
diff --git a/tests/regressiontests/dispatch/tests/test_saferef.py b/tests/regressiontests/dispatch/tests/test_saferef.py
index cfe6c5df85..30eaddfe18 100644
--- a/tests/regressiontests/dispatch/tests/test_saferef.py
+++ b/tests/regressiontests/dispatch/tests/test_saferef.py
@@ -54,10 +54,8 @@ class SaferefTests(unittest.TestCase):
sd[s] = 1
for t in self.ts:
if hasattr(t, 'x'):
- self.assertTrue(sd.has_key(safeRef(t.x)))
self.assertTrue(safeRef(t.x) in sd)
else:
- self.assertTrue(sd.has_key(safeRef(t)))
self.assertTrue(safeRef(t) in sd)
def testRepresentation(self):
diff --git a/tests/regressiontests/expressions_regress/models.py b/tests/regressiontests/expressions_regress/models.py
index f3b6999377..711329031d 100644
--- a/tests/regressiontests/expressions_regress/models.py
+++ b/tests/regressiontests/expressions_regress/models.py
@@ -1,15 +1,17 @@
from __future__ import unicode_literals
+from django.utils.encoding import python_2_unicode_compatible
"""
Model for testing arithmetic expressions.
"""
from django.db import models
+@python_2_unicode_compatible
class Number(models.Model):
integer = models.IntegerField(db_column='the_integer')
float = models.FloatField(null=True, db_column='the_float')
- def __unicode__(self):
+ def __str__(self):
return '%i, %.3f' % (self.integer, self.float)
class Experiment(models.Model):
diff --git a/tests/regressiontests/extra_regress/models.py b/tests/regressiontests/extra_regress/models.py
index 7d2a6fab34..11996438b4 100644
--- a/tests/regressiontests/extra_regress/models.py
+++ b/tests/regressiontests/extra_regress/models.py
@@ -5,14 +5,16 @@ import datetime
from django.contrib.auth.models import User
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class RevisionableModel(models.Model):
base = models.ForeignKey('self', null=True)
title = models.CharField(blank=True, max_length=255)
when = models.DateTimeField(default=datetime.datetime.now)
- def __unicode__(self):
+ def __str__(self):
return "%s (%s, %s)" % (self.title, self.id, self.base.id)
def save(self, *args, **kwargs):
@@ -32,11 +34,12 @@ class Order(models.Model):
created_by = models.ForeignKey(User)
text = models.TextField()
+@python_2_unicode_compatible
class TestObject(models.Model):
first = models.CharField(max_length=20)
second = models.CharField(max_length=20)
third = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return 'TestObject: %s,%s,%s' % (self.first,self.second,self.third)
diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py
index 31e33d915c..87b509e320 100644
--- a/tests/regressiontests/file_storage/tests.py
+++ b/tests/regressiontests/file_storage/tests.py
@@ -21,6 +21,7 @@ from django.core.files.images import get_image_dimensions
from django.core.files.storage import FileSystemStorage, get_storage_class
from django.core.files.uploadedfile import UploadedFile
from django.test import SimpleTestCase
+from django.utils import six
from django.utils import unittest
from ..servers.tests import LiveServerBase
@@ -127,7 +128,7 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('test.file'))
- f = ContentFile(b'custom contents')
+ f = ContentFile('custom contents')
f_name = self.storage.save('test.file', f)
atime = self.storage.accessed_time(f_name)
@@ -143,7 +144,7 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('test.file'))
- f = ContentFile(b'custom contents')
+ f = ContentFile('custom contents')
f_name = self.storage.save('test.file', f)
ctime = self.storage.created_time(f_name)
@@ -160,7 +161,7 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('test.file'))
- f = ContentFile(b'custom contents')
+ f = ContentFile('custom contents')
f_name = self.storage.save('test.file', f)
mtime = self.storage.modified_time(f_name)
@@ -177,7 +178,7 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('test.file'))
- f = ContentFile(b'custom contents')
+ f = ContentFile('custom contents')
f.name = 'test.file'
storage_f_name = self.storage.save(None, f)
@@ -194,11 +195,11 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('path/to'))
self.storage.save('path/to/test.file',
- ContentFile(b'file saved with path'))
+ ContentFile('file saved with path'))
self.assertTrue(self.storage.exists('path/to'))
- self.assertEqual(self.storage.open('path/to/test.file').read(),
- b'file saved with path')
+ with self.storage.open('path/to/test.file') as f:
+ self.assertEqual(f.read(), b'file saved with path')
self.assertTrue(os.path.exists(
os.path.join(self.temp_dir, 'path', 'to', 'test.file')))
@@ -211,7 +212,7 @@ class FileStorageTests(unittest.TestCase):
"""
self.assertFalse(self.storage.exists('test.file'))
- f = ContentFile(b'custom contents')
+ f = ContentFile('custom contents')
f_name = self.storage.save('test.file', f)
self.assertEqual(self.storage.path(f_name),
@@ -246,8 +247,8 @@ class FileStorageTests(unittest.TestCase):
self.assertFalse(self.storage.exists('storage_test_2'))
self.assertFalse(self.storage.exists('storage_dir_1'))
- f = self.storage.save('storage_test_1', ContentFile(b'custom content'))
- f = self.storage.save('storage_test_2', ContentFile(b'custom content'))
+ f = self.storage.save('storage_test_1', ContentFile('custom content'))
+ f = self.storage.save('storage_test_2', ContentFile('custom content'))
os.mkdir(os.path.join(self.temp_dir, 'storage_dir_1'))
dirs, files = self.storage.listdir('')
@@ -304,18 +305,18 @@ class FileStorageTests(unittest.TestCase):
os.makedirs = fake_makedirs
self.storage.save('normal/test.file',
- ContentFile(b'saved normally'))
- self.assertEqual(self.storage.open('normal/test.file').read(),
- b'saved normally')
+ ContentFile('saved normally'))
+ with self.storage.open('normal/test.file') as f:
+ self.assertEqual(f.read(), b'saved normally')
self.storage.save('raced/test.file',
- ContentFile(b'saved with race'))
- self.assertEqual(self.storage.open('raced/test.file').read(),
- b'saved with race')
+ ContentFile('saved with race'))
+ with self.storage.open('raced/test.file') as f:
+ self.assertEqual(f.read(), b'saved with race')
# Check that OSErrors aside from EEXIST are still raised.
self.assertRaises(OSError,
- self.storage.save, 'error/test.file', ContentFile(b'not saved'))
+ self.storage.save, 'error/test.file', ContentFile('not saved'))
finally:
os.makedirs = real_makedirs
@@ -341,20 +342,31 @@ class FileStorageTests(unittest.TestCase):
try:
os.remove = fake_remove
- self.storage.save('normal.file', ContentFile(b'delete normally'))
+ self.storage.save('normal.file', ContentFile('delete normally'))
self.storage.delete('normal.file')
self.assertFalse(self.storage.exists('normal.file'))
- self.storage.save('raced.file', ContentFile(b'delete with race'))
+ self.storage.save('raced.file', ContentFile('delete with race'))
self.storage.delete('raced.file')
self.assertFalse(self.storage.exists('normal.file'))
# Check that OSErrors aside from ENOENT are still raised.
- self.storage.save('error.file', ContentFile(b'delete with error'))
+ self.storage.save('error.file', ContentFile('delete with error'))
self.assertRaises(OSError, self.storage.delete, 'error.file')
finally:
os.remove = real_remove
+ def test_file_chunks_error(self):
+ """
+ Test behaviour when file.chunks() is raising an error
+ """
+ f1 = ContentFile('chunks fails')
+ def failing_chunks():
+ raise IOError
+ f1.chunks = failing_chunks
+ with self.assertRaises(IOError):
+ self.storage.save('error.file', f1)
+
class CustomStorage(FileSystemStorage):
def get_available_name(self, name):
@@ -374,9 +386,9 @@ class CustomStorageTests(FileStorageTests):
storage_class = CustomStorage
def test_custom_get_available_name(self):
- first = self.storage.save('custom_storage', ContentFile(b'custom contents'))
+ first = self.storage.save('custom_storage', ContentFile('custom contents'))
self.assertEqual(first, 'custom_storage')
- second = self.storage.save('custom_storage', ContentFile(b'more contents'))
+ second = self.storage.save('custom_storage', ContentFile('more contents'))
self.assertEqual(second, 'custom_storage.2')
self.storage.delete(first)
self.storage.delete(second)
@@ -433,7 +445,7 @@ class FileStoragePermissions(unittest.TestCase):
shutil.rmtree(self.storage_dir)
def test_file_upload_permissions(self):
- name = self.storage.save("the_file", ContentFile(b"data"))
+ name = self.storage.save("the_file", ContentFile("data"))
actual_mode = os.stat(self.storage.path(name))[0] & 0o777
self.assertEqual(actual_mode, 0o666)
@@ -453,8 +465,8 @@ class FileStoragePathParsing(unittest.TestCase):
sure we still mangle the file name instead of the directory name.
"""
- self.storage.save('dotted.path/test', ContentFile(b"1"))
- self.storage.save('dotted.path/test', ContentFile(b"2"))
+ self.storage.save('dotted.path/test', ContentFile("1"))
+ self.storage.save('dotted.path/test', ContentFile("2"))
self.assertFalse(os.path.exists(os.path.join(self.storage_dir, 'dotted_.path')))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test')))
@@ -465,8 +477,8 @@ class FileStoragePathParsing(unittest.TestCase):
File names with a dot as their first character don't have an extension,
and the underscore should get added to the end.
"""
- self.storage.save('dotted.path/.test', ContentFile(b"1"))
- self.storage.save('dotted.path/.test', ContentFile(b"2"))
+ self.storage.save('dotted.path/.test', ContentFile("1"))
+ self.storage.save('dotted.path/.test', ContentFile("2"))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_1')))
@@ -538,16 +550,25 @@ class InconsistentGetImageDimensionsBug(unittest.TestCase):
self.assertEqual(size_1, size_2)
class ContentFileTestCase(unittest.TestCase):
- """
- Test that the constructor of ContentFile accepts 'name' (#16590).
- """
+
def test_content_file_default_name(self):
self.assertEqual(ContentFile(b"content").name, None)
def test_content_file_custom_name(self):
+ """
+ Test that the constructor of ContentFile accepts 'name' (#16590).
+ """
name = "I can have a name too!"
self.assertEqual(ContentFile(b"content", name=name).name, name)
+ def test_content_file_input_type(self):
+ """
+ Test that ContentFile can accept both bytes and unicode and that the
+ retrieved content is of the same type.
+ """
+ self.assertTrue(isinstance(ContentFile(b"content").read(), bytes))
+ self.assertTrue(isinstance(ContentFile("español").read(), six.text_type))
+
class NoNameFileTestCase(unittest.TestCase):
"""
Other examples of unnamed files may be tempfile.SpooledTemporaryFile or
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
index d2362d7197..a545ed649e 100644
--- a/tests/regressiontests/file_uploads/tests.py
+++ b/tests/regressiontests/file_uploads/tests.py
@@ -12,6 +12,7 @@ from django.core.files import temp as tempfile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http.multipartparser import MultiPartParser
from django.test import TestCase, client
+from django.utils.encoding import force_bytes
from django.utils.six import StringIO
from django.utils import unittest
@@ -48,12 +49,12 @@ class FileUploadTests(TestCase):
'file_field2': file2,
}
- for key in post_data.keys():
+ for key in list(post_data):
try:
post_data[key + '_hash'] = hashlib.sha1(post_data[key].read()).hexdigest()
post_data[key].seek(0)
except AttributeError:
- post_data[key + '_hash'] = hashlib.sha1(post_data[key]).hexdigest()
+ post_data[key + '_hash'] = hashlib.sha1(force_bytes(post_data[key])).hexdigest()
response = self.client.post('/file_uploads/verify/', post_data)
@@ -67,7 +68,7 @@ class FileUploadTests(TestCase):
'Content-Type: application/octet-stream',
'Content-Transfer-Encoding: base64',
'',
- base64.b64encode(test_string),
+ base64.b64encode(force_bytes(test_string)).decode('ascii'),
'--' + client.BOUNDARY + '--',
'',
]).encode('utf-8')
@@ -79,7 +80,7 @@ class FileUploadTests(TestCase):
'wsgi.input': client.FakePayload(payload),
}
response = self.client.request(**r)
- received = json.loads(response.content)
+ received = json.loads(response.content.decode('utf-8'))
self.assertEqual(received['file'], test_string)
@@ -87,7 +88,7 @@ class FileUploadTests(TestCase):
tdir = tempfile.gettempdir()
# This file contains chinese symbols and an accented char in the name.
- with open(os.path.join(tdir, UNICODE_FILENAME.encode('utf-8')), 'w+b') as file1:
+ with open(os.path.join(tdir, UNICODE_FILENAME), 'w+b') as file1:
file1.write(b'b' * (2 ** 10))
file1.seek(0)
@@ -150,7 +151,7 @@ class FileUploadTests(TestCase):
response = self.client.request(**r)
# The filenames should have been sanitized by the time it got to the view.
- recieved = json.loads(response.content)
+ recieved = json.loads(response.content.decode('utf-8'))
for i, name in enumerate(scary_file_names):
got = recieved["file%s" % i]
self.assertEqual(got, "hax0rd.txt")
@@ -174,7 +175,7 @@ class FileUploadTests(TestCase):
'REQUEST_METHOD': 'POST',
'wsgi.input': client.FakePayload(payload),
}
- got = json.loads(self.client.request(**r).content)
+ got = json.loads(self.client.request(**r).content.decode('utf-8'))
self.assertTrue(len(got['file']) < 256, "Got a long file name (%s characters)." % len(got['file']))
def test_truncated_multipart_handled_gracefully(self):
@@ -200,7 +201,7 @@ class FileUploadTests(TestCase):
'REQUEST_METHOD': 'POST',
'wsgi.input': client.FakePayload(payload),
}
- got = json.loads(self.client.request(**r).content)
+ got = json.loads(self.client.request(**r).content.decode('utf-8'))
self.assertEqual(got, {})
def test_empty_multipart_handled_gracefully(self):
@@ -215,7 +216,7 @@ class FileUploadTests(TestCase):
'REQUEST_METHOD': 'POST',
'wsgi.input': client.FakePayload(b''),
}
- got = json.loads(self.client.request(**r).content)
+ got = json.loads(self.client.request(**r).content.decode('utf-8'))
self.assertEqual(got, {})
def test_custom_upload_handler(self):
@@ -231,12 +232,12 @@ class FileUploadTests(TestCase):
# Small file posting should work.
response = self.client.post('/file_uploads/quota/', {'f': smallfile})
- got = json.loads(response.content)
+ got = json.loads(response.content.decode('utf-8'))
self.assertTrue('f' in got)
# Large files don't go through.
response = self.client.post("/file_uploads/quota/", {'f': bigfile})
- got = json.loads(response.content)
+ got = json.loads(response.content.decode('utf-8'))
self.assertTrue('f' not in got)
def test_broken_custom_upload_handler(self):
@@ -274,7 +275,7 @@ class FileUploadTests(TestCase):
'field5': 'test7',
'file2': (file2, file2a)
})
- got = json.loads(response.content)
+ got = json.loads(response.content.decode('utf-8'))
self.assertEqual(got.get('file1'), 1)
self.assertEqual(got.get('file2'), 2)
@@ -299,8 +300,8 @@ class FileUploadTests(TestCase):
# it raises when there is an attempt to read more than the available bytes:
try:
client.FakePayload(b'a').read(2)
- except Exception as reference_error:
- pass
+ except Exception as err:
+ reference_error = err
# install the custom handler that tries to access request.POST
self.client.handler = POSTAccessingHandler()
diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py
index c5d2720e1a..fcf32cecea 100644
--- a/tests/regressiontests/file_uploads/views.py
+++ b/tests/regressiontests/file_uploads/views.py
@@ -7,6 +7,7 @@ import os
from django.core.files.uploadedfile import UploadedFile
from django.http import HttpResponse, HttpResponseServerError
from django.utils import six
+from django.utils.encoding import force_bytes
from .models import FileModel, UPLOAD_TO
from .tests import UNICODE_FILENAME
@@ -45,7 +46,7 @@ def file_upload_view_verify(request):
if isinstance(value, UploadedFile):
new_hash = hashlib.sha1(value.read()).hexdigest()
else:
- new_hash = hashlib.sha1(value).hexdigest()
+ new_hash = hashlib.sha1(force_bytes(value)).hexdigest()
if new_hash != submitted_hash:
return HttpResponseServerError()
@@ -95,7 +96,7 @@ def file_upload_echo_content(request):
"""
Simple view to echo back the content of uploaded files for tests.
"""
- r = dict([(k, f.read()) for k, f in request.FILES.items()])
+ r = dict([(k, f.read().decode('utf-8')) for k, f in request.FILES.items()])
return HttpResponse(json.dumps(r))
def file_upload_quota(request):
diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py
index 7151cb0ed9..1cc30d2e51 100644
--- a/tests/regressiontests/fixtures_regress/models.py
+++ b/tests/regressiontests/fixtures_regress/models.py
@@ -3,8 +3,10 @@ from __future__ import absolute_import, unicode_literals
from django.contrib.auth.models import User
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Animal(models.Model):
name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
@@ -14,7 +16,7 @@ class Animal(models.Model):
# use a non-default name for the default manager
specimens = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -25,11 +27,12 @@ class Plant(models.Model):
# For testing when upper case letter in app name; regression for #4057
db_table = "Fixtures_regress_plant"
+@python_2_unicode_compatible
class Stuff(models.Model):
name = models.CharField(max_length=20, null=True)
owner = models.ForeignKey(User, null=True)
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.name) + ' is owned by ' + six.text_type(self.owner)
@@ -68,13 +71,14 @@ class Article(models.Model):
# Models to regression test #11428
+@python_2_unicode_compatible
class Widget(models.Model):
name = models.CharField(max_length=255)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
@@ -89,6 +93,7 @@ class TestManager(models.Manager):
return self.get(name=key)
+@python_2_unicode_compatible
class Store(models.Model):
objects = TestManager()
name = models.CharField(max_length=255)
@@ -97,13 +102,14 @@ class Store(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
def natural_key(self):
return (self.name,)
+@python_2_unicode_compatible
class Person(models.Model):
objects = TestManager()
name = models.CharField(max_length=255)
@@ -111,7 +117,7 @@ class Person(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
# Person doesn't actually have a dependency on store, but we need to define
@@ -121,6 +127,7 @@ class Person(models.Model):
natural_key.dependencies = ['fixtures_regress.store']
+@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=255)
author = models.ForeignKey(Person)
@@ -129,7 +136,7 @@ class Book(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return '%s by %s (available at %s)' % (
self.name,
self.author.name,
@@ -142,6 +149,7 @@ class NKManager(models.Manager):
return self.get(data=data)
+@python_2_unicode_compatible
class NKChild(Parent):
data = models.CharField(max_length=10, unique=True)
objects = NKManager()
@@ -149,16 +157,17 @@ class NKChild(Parent):
def natural_key(self):
return self.data
- def __unicode__(self):
+ def __str__(self):
return 'NKChild %s:%s' % (self.name, self.data)
+@python_2_unicode_compatible
class RefToNKChild(models.Model):
text = models.CharField(max_length=10)
nk_fk = models.ForeignKey(NKChild, related_name='ref_fks')
nk_m2m = models.ManyToManyField(NKChild, related_name='ref_m2ms')
- def __unicode__(self):
+ def __str__(self):
return '%s: Reference to %s [%s]' % (
self.text,
self.nk_fk,
diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
index ab93341699..b3d0f42465 100644
--- a/tests/regressiontests/fixtures_regress/tests.py
+++ b/tests/regressiontests/fixtures_regress/tests.py
@@ -4,7 +4,6 @@ from __future__ import absolute_import, unicode_literals
import os
import re
-from io import BytesIO
from django.core import management
from django.core.management.base import CommandError
@@ -14,6 +13,7 @@ from django.db.models import signals
from django.test import (TestCase, TransactionTestCase, skipIfDBFeature,
skipUnlessDBFeature)
from django.test.utils import override_settings
+from django.utils.six import PY3, StringIO
from .models import (Animal, Stuff, Absolute, Parent, Child, Article, Widget,
Store, Person, Book, NKChild, RefToNKChild, Circle1, Circle2, Circle3,
@@ -126,6 +126,20 @@ class TestFixtures(TestCase):
commit=False,
)
+ @override_settings(SERIALIZATION_MODULES={'unkn': 'unexistent.path'})
+ def test_unimportable_serializer(self):
+ """
+ Test that failing serializer import raises the proper error
+ """
+ with self.assertRaisesRegexp(ImportError,
+ "No module named unexistent.path"):
+ management.call_command(
+ 'loaddata',
+ 'bad_fixture1.unkn',
+ verbosity=0,
+ commit=False,
+ )
+
def test_invalid_data(self):
"""
Test for ticket #4371 -- Loading a fixture file with invalid data
@@ -244,7 +258,8 @@ class TestFixtures(TestCase):
self.assertEqual(
pre_save_checks,
[
- ("Count = 42 (<type 'int'>)", "Weight = 1.2 (<type 'float'>)")
+ ("Count = 42 (<%s 'int'>)" % ('class' if PY3 else 'type'),
+ "Weight = 1.2 (<%s 'float'>)" % ('class' if PY3 else 'type'))
]
)
finally:
@@ -276,7 +291,7 @@ class TestFixtures(TestCase):
)
animal.save()
- stdout = BytesIO()
+ stdout = StringIO()
management.call_command(
'dumpdata',
'fixtures_regress.animal',
@@ -305,7 +320,7 @@ class TestFixtures(TestCase):
"""
Regression for #11428 - Proxy models aren't included when you dumpdata
"""
- stdout = BytesIO()
+ stdout = StringIO()
# Create an instance of the concrete class
widget = Widget.objects.create(name='grommet')
management.call_command(
@@ -380,7 +395,7 @@ class TestFixtures(TestCase):
)
def test_loaddata_not_existant_fixture_file(self):
- stdout_output = BytesIO()
+ stdout_output = StringIO()
management.call_command(
'loaddata',
'this_fixture_doesnt_exist',
@@ -465,7 +480,7 @@ class NaturalKeyFixtureTests(TestCase):
commit=False
)
- stdout = BytesIO()
+ stdout = StringIO()
management.call_command(
'dumpdata',
'fixtures_regress.book',
diff --git a/tests/regressiontests/forms/models.py b/tests/regressiontests/forms/models.py
index 18e6ddce6d..2f3ee9fa31 100644
--- a/tests/regressiontests/forms/models.py
+++ b/tests/regressiontests/forms/models.py
@@ -7,6 +7,7 @@ import tempfile
from django.core.files.storage import FileSystemStorage
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
temp_storage_location = tempfile.mkdtemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
@@ -36,6 +37,7 @@ class ChoiceModel(models.Model):
name = models.CharField(max_length=10)
+@python_2_unicode_compatible
class ChoiceOptionModel(models.Model):
"""Destination for ChoiceFieldModel's ForeignKey.
Can't reuse ChoiceModel because error_message tests require that it have no instances."""
@@ -44,7 +46,7 @@ class ChoiceOptionModel(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return 'ChoiceOption %d' % self.pk
@@ -66,10 +68,11 @@ class FileModel(models.Model):
file = models.FileField(storage=temp_storage, upload_to='tests')
+@python_2_unicode_compatible
class Group(models.Model):
name = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return '%s' % self.name
diff --git a/tests/regressiontests/forms/tests/error_messages.py b/tests/regressiontests/forms/tests/error_messages.py
index f69b419483..b76e122bc0 100644
--- a/tests/regressiontests/forms/tests/error_messages.py
+++ b/tests/regressiontests/forms/tests/error_messages.py
@@ -5,6 +5,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.forms import *
from django.test import TestCase
from django.utils.safestring import mark_safe
+from django.utils.encoding import python_2_unicode_compatible
class AssertFormErrorsMixin(object):
@@ -213,8 +214,9 @@ class FormsErrorMessagesTestCase(TestCase, AssertFormErrorsMixin):
def clean(self):
raise ValidationError("I like to be awkward.")
+ @python_2_unicode_compatible
class CustomErrorList(util.ErrorList):
- def __unicode__(self):
+ def __str__(self):
return self.as_divs()
def as_divs(self):
diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py
index e0e62858d0..2ab5d40942 100644
--- a/tests/regressiontests/forms/tests/extra.py
+++ b/tests/regressiontests/forms/tests/extra.py
@@ -8,8 +8,9 @@ from django.forms import *
from django.forms.extras import SelectDateWidget
from django.forms.util import ErrorList
from django.test import TestCase
+from django.utils import six
from django.utils import translation
-from django.utils.encoding import force_text, smart_text
+from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible
from .error_messages import AssertFormErrorsMixin
@@ -553,14 +554,24 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
def test_smart_text(self):
class Test:
- def __str__(self):
- return 'ŠĐĆŽćžšđ'.encode('utf-8')
+ if six.PY3:
+ def __str__(self):
+ return 'ŠĐĆŽćžšđ'
+ else:
+ def __str__(self):
+ return 'ŠĐĆŽćžšđ'.encode('utf-8')
class TestU:
- def __str__(self):
- return 'Foo'
- def __unicode__(self):
- return '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
+ if six.PY3:
+ def __str__(self):
+ return 'ŠĐĆŽćžšđ'
+ def __bytes__(self):
+ return b'Foo'
+ else:
+ def __str__(self):
+ return b'Foo'
+ def __unicode__(self):
+ return '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
self.assertEqual(smart_text(Test()), '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
self.assertEqual(smart_text(TestU()), '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
@@ -585,8 +596,9 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
self.assertEqual(f.cleaned_data['username'], 'sirrobin')
def test_overriding_errorlist(self):
+ @python_2_unicode_compatible
class DivErrorList(ErrorList):
- def __unicode__(self):
+ def __str__(self):
return self.as_divs()
def as_divs(self):
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
index feb2ade458..6efdb9682f 100644
--- a/tests/regressiontests/forms/tests/fields.py
+++ b/tests/regressiontests/forms/tests/fields.py
@@ -668,6 +668,18 @@ class FieldsTests(SimpleTestCase):
# Valid IDN
self.assertEqual(url, f.clean(url))
+ def test_urlfield_10(self):
+ """Test URLField correctly validates IPv6 (#18779)."""
+ f = URLField()
+ urls = (
+ 'http://::/',
+ 'http://6:21b4:92/',
+ 'http://[12:34:3a53]/',
+ 'http://[a34:9238::]:8080/',
+ )
+ for url in urls:
+ self.assertEqual(url, f.clean(url))
+
def test_urlfield_not_string(self):
f = URLField(required=False)
self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 23)
diff --git a/tests/regressiontests/forms/tests/models.py b/tests/regressiontests/forms/tests/models.py
index 7687335b48..c351509cee 100644
--- a/tests/regressiontests/forms/tests/models.py
+++ b/tests/regressiontests/forms/tests/models.py
@@ -178,7 +178,7 @@ class RelatedModelFormTests(TestCase):
class Meta:
model=A
- self.assertRaises(ValueError, ModelFormMetaclass, b'Form', (ModelForm,), {'Meta': Meta})
+ self.assertRaises(ValueError, ModelFormMetaclass, str('Form'), (ModelForm,), {'Meta': Meta})
class B(models.Model):
pass
@@ -196,4 +196,4 @@ class RelatedModelFormTests(TestCase):
class Meta:
model=A
- self.assertTrue(issubclass(ModelFormMetaclass(b'Form', (ModelForm,), {'Meta': Meta}), ModelForm))
+ self.assertTrue(issubclass(ModelFormMetaclass(str('Form'), (ModelForm,), {'Meta': Meta}), ModelForm))
diff --git a/tests/regressiontests/forms/tests/util.py b/tests/regressiontests/forms/tests/util.py
index b7cc4ec809..c2d213ae23 100644
--- a/tests/regressiontests/forms/tests/util.py
+++ b/tests/regressiontests/forms/tests/util.py
@@ -7,6 +7,7 @@ from django.test import TestCase
from django.utils.safestring import mark_safe
from django.utils import six
from django.utils.translation import ugettext_lazy
+from django.utils.encoding import python_2_unicode_compatible
class FormsUtilTestCase(TestCase):
@@ -46,8 +47,9 @@ class FormsUtilTestCase(TestCase):
self.assertHTMLEqual(str(ErrorList(ValidationError(["First error.", "Not \u03C0.", ugettext_lazy("Error.")]).messages)),
'<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>')
+ @python_2_unicode_compatible
class VeryBadError:
- def __unicode__(self): return "A very bad error."
+ def __str__(self): return "A very bad error."
# Can take a non-string.
self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)),
diff --git a/tests/regressiontests/forms/tests/widgets.py b/tests/regressiontests/forms/tests/widgets.py
index 3ea42cf549..c950aef719 100644
--- a/tests/regressiontests/forms/tests/widgets.py
+++ b/tests/regressiontests/forms/tests/widgets.py
@@ -13,6 +13,7 @@ from django.utils.safestring import mark_safe
from django.utils import six
from django.utils.translation import activate, deactivate
from django.test import TestCase
+from django.utils.encoding import python_2_unicode_compatible
class FormsWidgetTestCase(TestCase):
@@ -1096,6 +1097,7 @@ class WidgetTests(TestCase):
self.assertFalse(form.is_valid())
+@python_2_unicode_compatible
class FakeFieldFile(object):
"""
Quacks like a FieldFile (has a .url and unicode representation), but
@@ -1104,7 +1106,7 @@ class FakeFieldFile(object):
"""
url = 'something'
- def __unicode__(self):
+ def __str__(self):
return self.url
class ClearableFileInputTests(TestCase):
@@ -1125,10 +1127,11 @@ class ClearableFileInputTests(TestCase):
rendering HTML. Refs #15182.
"""
+ @python_2_unicode_compatible
class StrangeFieldFile(object):
url = "something?chapter=1&sect=2&copy=3&lang=en"
- def __unicode__(self):
+ def __str__(self):
return '''something<div onclick="alert('oops')">.jpg'''
widget = ClearableFileInput()
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py
index a1555666b3..dedc351075 100644
--- a/tests/regressiontests/generic_inline_admin/models.py
+++ b/tests/regressiontests/generic_inline_admin/models.py
@@ -1,6 +1,7 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Episode(models.Model):
@@ -9,6 +10,7 @@ class Episode(models.Model):
author = models.CharField(max_length=100, blank=True)
+@python_2_unicode_compatible
class Media(models.Model):
"""
Media that can associated to any object.
@@ -20,7 +22,7 @@ class Media(models.Model):
description = models.CharField(max_length=100, blank=True)
keywords = models.CharField(max_length=100, blank=True)
- def __unicode__(self):
+ def __str__(self):
return self.url
#
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index c97f4c4f03..fea30b4946 100644
--- a/tests/regressiontests/generic_inline_admin/tests.py
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -276,7 +276,7 @@ class GenericInlineModelAdminTest(TestCase):
ma = EpisodeAdmin(Episode, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
['keywords', 'id', 'DELETE'])
def test_custom_form_meta_exclude(self):
@@ -306,7 +306,7 @@ class GenericInlineModelAdminTest(TestCase):
ma = EpisodeAdmin(Episode, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
['url', 'keywords', 'id', 'DELETE'])
# Then, only with `ModelForm` -----------------
@@ -322,5 +322,5 @@ class GenericInlineModelAdminTest(TestCase):
ma = EpisodeAdmin(Episode, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
['description', 'keywords', 'id', 'DELETE'])
diff --git a/tests/regressiontests/generic_relations_regress/models.py b/tests/regressiontests/generic_relations_regress/models.py
index 7ec752b02b..dacc9b380b 100644
--- a/tests/regressiontests/generic_relations_regress/models.py
+++ b/tests/regressiontests/generic_relations_regress/models.py
@@ -1,31 +1,36 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
__all__ = ('Link', 'Place', 'Restaurant', 'Person', 'Address',
'CharLink', 'TextLink', 'OddRelation1', 'OddRelation2',
'Contact', 'Organization', 'Note')
+@python_2_unicode_compatible
class Link(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
- def __unicode__(self):
+ def __str__(self):
return "Link to %s id=%s" % (self.content_type, self.object_id)
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=100)
links = generic.GenericRelation(Link)
- def __unicode__(self):
+ def __str__(self):
return "Place: %s" % self.name
+@python_2_unicode_compatible
class Restaurant(Place):
- def __unicode__(self):
+ def __str__(self):
return "Restaurant: %s" % self.name
+@python_2_unicode_compatible
class Address(models.Model):
street = models.CharField(max_length=80)
city = models.CharField(max_length=50)
@@ -35,15 +40,16 @@ class Address(models.Model):
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
- def __unicode__(self):
+ def __str__(self):
return '%s %s, %s %s' % (self.street, self.city, self.state, self.zipcode)
+@python_2_unicode_compatible
class Person(models.Model):
account = models.IntegerField(primary_key=True)
name = models.CharField(max_length=128)
addresses = generic.GenericRelation(Address)
- def __unicode__(self):
+ def __str__(self):
return self.name
class CharLink(models.Model):
diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py
index fc3dc05fd7..439b0d7327 100644
--- a/tests/regressiontests/generic_views/base.py
+++ b/tests/regressiontests/generic_views/base.py
@@ -69,7 +69,7 @@ class ViewTest(unittest.TestCase):
def _assert_simple(self, response):
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'This is a simple view')
+ self.assertEqual(response.content, b'This is a simple view')
def test_no_init_kwargs(self):
"""
@@ -173,15 +173,6 @@ class ViewTest(unittest.TestCase):
"""
self.assertTrue(DecoratedDispatchView.as_view().is_decorated)
- def test_head_no_get(self):
- """
- Test that a view class with no get responds to a HEAD request with HTTP
- 405.
- """
- request = self.rf.head('/')
- view = PostOnlyView.as_view()
- self.assertEqual(405, view(request).status_code)
-
def test_options(self):
"""
Test that views respond to HTTP OPTIONS requests with an Allow header
@@ -275,7 +266,8 @@ class TemplateViewTest(TestCase):
"""
response = self.client.get('/template/simple/bar/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.context['params'], {'foo': 'bar'})
+ self.assertEqual(response.context['foo'], 'bar')
+ self.assertTrue(isinstance(response.context['view'], View))
def test_extra_template_params(self):
"""
@@ -283,8 +275,9 @@ class TemplateViewTest(TestCase):
"""
response = self.client.get('/template/custom/bar/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.context['params'], {'foo': 'bar'})
+ self.assertEqual(response.context['foo'], 'bar')
self.assertEqual(response.context['key'], 'value')
+ self.assertTrue(isinstance(response.context['view'], View))
def test_cached_views(self):
"""
diff --git a/tests/regressiontests/generic_views/dates.py b/tests/regressiontests/generic_views/dates.py
index ad65fd9f10..c2fa71b376 100644
--- a/tests/regressiontests/generic_views/dates.py
+++ b/tests/regressiontests/generic_views/dates.py
@@ -1,14 +1,27 @@
from __future__ import absolute_import
+import time
import datetime
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from django.test.utils import override_settings
from django.utils import timezone
+from django.utils.unittest import skipUnless
from .models import Book, BookSigning
+TZ_SUPPORT = hasattr(time, 'tzset')
+
+# On OSes that don't provide tzset (Windows), we can't set the timezone
+# in which the program runs. As a consequence, we must skip tests that
+# don't enforce a specific timezone (with timezone.override or equivalent),
+# or attempt to interpret naive datetimes in the default timezone.
+
+requires_tz_support = skipUnless(TZ_SUPPORT,
+ "This test relies on the ability to run a program in an arbitrary "
+ "time zone, but your operating system isn't able to do that.")
+
class ArchiveIndexViewTests(TestCase):
fixtures = ['generic-views-test-data.json']
@@ -47,7 +60,6 @@ class ArchiveIndexViewTests(TestCase):
res = self.client.get('/dates/books/allow_empty/')
self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['date_list']), [])
- self.assertEqual(list(res.context['date_list']), [])
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
def test_archive_view_template(self):
@@ -67,6 +79,11 @@ class ArchiveIndexViewTests(TestCase):
def test_archive_view_invalid(self):
self.assertRaises(ImproperlyConfigured, self.client.get, '/dates/books/invalid/')
+ def test_archive_view_by_month(self):
+ res = self.client.get('/dates/books/by_month/')
+ self.assertEqual(res.status_code, 200)
+ self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'month')[::-1])
+
def test_paginated_archive_view(self):
self._make_books(20, base_date=datetime.date.today())
res = self.client.get('/dates/books/paginated/')
@@ -100,6 +117,7 @@ class ArchiveIndexViewTests(TestCase):
res = self.client.get('/dates/booksignings/')
self.assertEqual(res.status_code, 200)
+ @requires_tz_support
@override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
def test_aware_datetime_archive_view(self):
BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
@@ -480,7 +498,7 @@ class DayArchiveViewTests(TestCase):
def test_next_prev_context(self):
res = self.client.get('/dates/books/2008/oct/01/')
- self.assertEqual(res.content, "Archive for Oct. 1, 2008. Previous day is May 1, 2006")
+ self.assertEqual(res.content, b"Archive for Oct. 1, 2008. Previous day is May 1, 2006")
def test_custom_month_format(self):
res = self.client.get('/dates/books/2008/10/01/')
@@ -502,6 +520,7 @@ class DayArchiveViewTests(TestCase):
res = self.client.get('/dates/booksignings/2008/apr/2/')
self.assertEqual(res.status_code, 200)
+ @requires_tz_support
@override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
def test_aware_datetime_day_view(self):
bs = BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
@@ -578,6 +597,7 @@ class DateDetailViewTests(TestCase):
res = self.client.get('/dates/booksignings/2008/apr/2/%d/' % bs.pk)
self.assertEqual(res.status_code, 200)
+ @requires_tz_support
@override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
def test_aware_datetime_date_detail(self):
bs = BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
diff --git a/tests/regressiontests/generic_views/detail.py b/tests/regressiontests/generic_views/detail.py
index 60c5f7afe9..c8f1999a2a 100644
--- a/tests/regressiontests/generic_views/detail.py
+++ b/tests/regressiontests/generic_views/detail.py
@@ -2,6 +2,7 @@ from __future__ import absolute_import
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
+from django.views.generic.base import View
from .models import Artist, Author, Page
@@ -14,6 +15,7 @@ class DetailViewTest(TestCase):
res = self.client.get('/detail/obj/')
self.assertEqual(res.status_code, 200)
self.assertEqual(res.context['object'], {'foo': 'bar'})
+ self.assertTrue(isinstance(res.context['view'], View))
self.assertTemplateUsed(res, 'generic_views/detail.html')
def test_detail_by_pk(self):
diff --git a/tests/regressiontests/generic_views/edit.py b/tests/regressiontests/generic_views/edit.py
index 651e14fff3..16f4da8efe 100644
--- a/tests/regressiontests/generic_views/edit.py
+++ b/tests/regressiontests/generic_views/edit.py
@@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse
from django import forms
from django.test import TestCase
from django.utils.unittest import expectedFailure
+from django.views.generic.base import View
from django.views.generic.edit import FormMixin
from . import views
@@ -31,6 +32,7 @@ class CreateViewTests(TestCase):
res = self.client.get('/edit/authors/create/')
self.assertEqual(res.status_code, 200)
self.assertTrue(isinstance(res.context['form'], forms.ModelForm))
+ self.assertTrue(isinstance(res.context['view'], View))
self.assertFalse('object' in res.context)
self.assertFalse('author' in res.context)
self.assertTemplateUsed(res, 'generic_views/author_form.html')
@@ -101,6 +103,7 @@ class CreateViewTests(TestCase):
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/')
+
class UpdateViewTests(TestCase):
urls = 'regressiontests.generic_views.urls'
@@ -226,6 +229,7 @@ class UpdateViewTests(TestCase):
res = self.client.get('/edit/author/update/')
self.assertEqual(res.status_code, 200)
self.assertTrue(isinstance(res.context['form'], forms.ModelForm))
+ self.assertTrue(isinstance(res.context['view'], View))
self.assertEqual(res.context['object'], Author.objects.get(pk=a.pk))
self.assertEqual(res.context['author'], Author.objects.get(pk=a.pk))
self.assertTemplateUsed(res, 'generic_views/author_form.html')
@@ -237,6 +241,7 @@ class UpdateViewTests(TestCase):
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
+
class DeleteViewTests(TestCase):
urls = 'regressiontests.generic_views.urls'
diff --git a/tests/regressiontests/generic_views/list.py b/tests/regressiontests/generic_views/list.py
index b925758524..14dc1d725d 100644
--- a/tests/regressiontests/generic_views/list.py
+++ b/tests/regressiontests/generic_views/list.py
@@ -2,6 +2,7 @@ from __future__ import absolute_import
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
+from django.views.generic.base import View
from .models import Author, Artist
@@ -21,6 +22,7 @@ class ListViewTests(TestCase):
self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'generic_views/author_list.html')
self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
+ self.assertTrue(isinstance(res.context['view'], View))
self.assertIs(res.context['author_list'], res.context['object_list'])
self.assertIsNone(res.context['paginator'])
self.assertIsNone(res.context['page_obj'])
diff --git a/tests/regressiontests/generic_views/models.py b/tests/regressiontests/generic_views/models.py
index 2355769d58..f59389ef78 100644
--- a/tests/regressiontests/generic_views/models.py
+++ b/tests/regressiontests/generic_views/models.py
@@ -1,6 +1,8 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Artist(models.Model):
name = models.CharField(max_length=100)
@@ -9,13 +11,14 @@ class Artist(models.Model):
verbose_name = 'professional artist'
verbose_name_plural = 'professional artists'
- def __unicode__(self):
+ def __str__(self):
return self.name
@models.permalink
def get_absolute_url(self):
return ('artist_detail', (), {'pk': self.id})
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField()
@@ -23,9 +26,10 @@ class Author(models.Model):
class Meta:
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=300)
slug = models.SlugField()
@@ -36,7 +40,7 @@ class Book(models.Model):
class Meta:
ordering = ['-pubdate']
- def __unicode__(self):
+ def __str__(self):
return self.name
class Page(models.Model):
diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py
index 5e15c6c9c1..c72bfecb65 100644
--- a/tests/regressiontests/generic_views/urls.py
+++ b/tests/regressiontests/generic_views/urls.py
@@ -113,6 +113,8 @@ urlpatterns = patterns('',
views.BookArchive.as_view(paginate_by=10)),
(r'^dates/books/reverse/$',
views.BookArchive.as_view(queryset=models.Book.objects.order_by('pubdate'))),
+ (r'^dates/books/by_month/$',
+ views.BookArchive.as_view(date_list_period='month')),
(r'^dates/booksignings/$',
views.BookSigningArchive.as_view()),
diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
index 0f61c2d840..21ba198bc3 100644
--- a/tests/regressiontests/httpwrappers/tests.py
+++ b/tests/regressiontests/httpwrappers/tests.py
@@ -6,19 +6,22 @@ import pickle
from django.core.exceptions import SuspiciousOperation
from django.http import (QueryDict, HttpResponse, HttpResponseRedirect,
- HttpResponsePermanentRedirect,
+ HttpResponsePermanentRedirect, HttpResponseNotAllowed,
+ HttpResponseNotModified,
SimpleCookie, BadHeaderError,
parse_cookie)
+from django.test import TestCase
+from django.utils import six
from django.utils import unittest
class QueryDictTests(unittest.TestCase):
def test_missing_key(self):
- q = QueryDict('')
+ q = QueryDict(str(''))
self.assertRaises(KeyError, q.__getitem__, 'foo')
def test_immutability(self):
- q = QueryDict('')
+ q = QueryDict(str(''))
self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
self.assertRaises(AttributeError, q.setlist, 'foo', ['bar'])
self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
@@ -28,26 +31,26 @@ class QueryDictTests(unittest.TestCase):
self.assertRaises(AttributeError, q.clear)
def test_immutable_get_with_default(self):
- q = QueryDict('')
+ q = QueryDict(str(''))
self.assertEqual(q.get('foo', 'default'), 'default')
def test_immutable_basic_operations(self):
- q = QueryDict('')
+ q = QueryDict(str(''))
self.assertEqual(q.getlist('foo'), [])
- self.assertEqual(q.has_key('foo'), False)
+ if not six.PY3:
+ self.assertEqual(q.has_key('foo'), False)
self.assertEqual('foo' in q, False)
- self.assertEqual(q.items(), [])
- self.assertEqual(q.lists(), [])
- self.assertEqual(q.items(), [])
- self.assertEqual(q.keys(), [])
- self.assertEqual(q.values(), [])
+ self.assertEqual(list(six.iteritems(q)), [])
+ self.assertEqual(list(six.iterlists(q)), [])
+ self.assertEqual(list(six.iterkeys(q)), [])
+ self.assertEqual(list(six.itervalues(q)), [])
self.assertEqual(len(q), 0)
self.assertEqual(q.urlencode(), '')
def test_single_key_value(self):
"""Test QueryDict with one key/value pair"""
- q = QueryDict('foo=bar')
+ q = QueryDict(str('foo=bar'))
self.assertEqual(q['foo'], 'bar')
self.assertRaises(KeyError, q.__getitem__, 'bar')
self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
@@ -60,15 +63,17 @@ class QueryDictTests(unittest.TestCase):
self.assertRaises(AttributeError, q.setlist, 'foo', ['bar'])
self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
- self.assertTrue(q.has_key('foo'))
+ if not six.PY3:
+ self.assertTrue(q.has_key('foo'))
self.assertTrue('foo' in q)
- self.assertFalse(q.has_key('bar'))
+ if not six.PY3:
+ self.assertFalse(q.has_key('bar'))
self.assertFalse('bar' in q)
- self.assertEqual(q.items(), [('foo', 'bar')])
- self.assertEqual(q.lists(), [('foo', ['bar'])])
- self.assertEqual(q.keys(), ['foo'])
- self.assertEqual(q.values(), ['bar'])
+ self.assertEqual(list(six.iteritems(q)), [('foo', 'bar')])
+ self.assertEqual(list(six.iterlists(q)), [('foo', ['bar'])])
+ self.assertEqual(list(six.iterkeys(q)), ['foo'])
+ self.assertEqual(list(six.itervalues(q)), ['bar'])
self.assertEqual(len(q), 1)
self.assertRaises(AttributeError, q.update, {'foo': 'bar'})
@@ -80,30 +85,30 @@ class QueryDictTests(unittest.TestCase):
self.assertEqual(q.urlencode(), 'foo=bar')
def test_urlencode(self):
- q = QueryDict('', mutable=True)
+ q = QueryDict(str(''), mutable=True)
q['next'] = '/a&b/'
self.assertEqual(q.urlencode(), 'next=%2Fa%26b%2F')
self.assertEqual(q.urlencode(safe='/'), 'next=/a%26b/')
- q = QueryDict('', mutable=True)
+ q = QueryDict(str(''), mutable=True)
q['next'] = '/t\xebst&key/'
self.assertEqual(q.urlencode(), 'next=%2Ft%C3%ABst%26key%2F')
self.assertEqual(q.urlencode(safe='/'), 'next=/t%C3%ABst%26key/')
def test_mutable_copy(self):
"""A copy of a QueryDict is mutable."""
- q = QueryDict('').copy()
+ q = QueryDict(str('')).copy()
self.assertRaises(KeyError, q.__getitem__, "foo")
q['name'] = 'john'
self.assertEqual(q['name'], 'john')
def test_mutable_delete(self):
- q = QueryDict('').copy()
+ q = QueryDict(str('')).copy()
q['name'] = 'john'
del q['name']
self.assertFalse('name' in q)
def test_basic_mutable_operations(self):
- q = QueryDict('').copy()
+ q = QueryDict(str('')).copy()
q['name'] = 'john'
self.assertEqual(q.get('foo', 'default'), 'default')
self.assertEqual(q.get('name', 'default'), 'john')
@@ -117,13 +122,14 @@ class QueryDictTests(unittest.TestCase):
q.appendlist('foo', 'another')
self.assertEqual(q.getlist('foo'), ['bar', 'baz', 'another'])
self.assertEqual(q['foo'], 'another')
- self.assertTrue(q.has_key('foo'))
+ if not six.PY3:
+ self.assertTrue(q.has_key('foo'))
self.assertTrue('foo' in q)
- self.assertEqual(q.items(), [('foo', 'another'), ('name', 'john')])
- self.assertEqual(q.lists(), [('foo', ['bar', 'baz', 'another']), ('name', ['john'])])
- self.assertEqual(q.keys(), ['foo', 'name'])
- self.assertEqual(q.values(), ['another', 'john'])
+ self.assertEqual(list(six.iteritems(q)), [('foo', 'another'), ('name', 'john')])
+ self.assertEqual(list(six.iterlists(q)), [('foo', ['bar', 'baz', 'another']), ('name', ['john'])])
+ self.assertEqual(list(six.iterkeys(q)), ['foo', 'name'])
+ self.assertEqual(list(six.itervalues(q)), ['another', 'john'])
self.assertEqual(len(q), 2)
q.update({'foo': 'hello'})
@@ -144,7 +150,7 @@ class QueryDictTests(unittest.TestCase):
def test_multiple_keys(self):
"""Test QueryDict with two key/value pairs with same keys."""
- q = QueryDict('vote=yes&vote=no')
+ q = QueryDict(str('vote=yes&vote=no'))
self.assertEqual(q['vote'], 'no')
self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
@@ -158,14 +164,16 @@ class QueryDictTests(unittest.TestCase):
self.assertRaises(AttributeError, q.setlist, 'foo', ['bar', 'baz'])
self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
- self.assertEqual(q.has_key('vote'), True)
+ if not six.PY3:
+ self.assertEqual(q.has_key('vote'), True)
self.assertEqual('vote' in q, True)
- self.assertEqual(q.has_key('foo'), False)
+ if not six.PY3:
+ self.assertEqual(q.has_key('foo'), False)
self.assertEqual('foo' in q, False)
- self.assertEqual(q.items(), [('vote', 'no')])
- self.assertEqual(q.lists(), [('vote', ['yes', 'no'])])
- self.assertEqual(q.keys(), ['vote'])
- self.assertEqual(q.values(), ['no'])
+ self.assertEqual(list(six.iteritems(q)), [('vote', 'no')])
+ self.assertEqual(list(six.iterlists(q)), [('vote', ['yes', 'no'])])
+ self.assertEqual(list(six.iterkeys(q)), ['vote'])
+ self.assertEqual(list(six.itervalues(q)), ['no'])
self.assertEqual(len(q), 1)
self.assertRaises(AttributeError, q.update, {'foo': 'bar'})
@@ -175,45 +183,49 @@ class QueryDictTests(unittest.TestCase):
self.assertRaises(AttributeError, q.setdefault, 'foo', 'bar')
self.assertRaises(AttributeError, q.__delitem__, 'vote')
- def test_invalid_input_encoding(self):
- """
- QueryDicts must be able to handle invalid input encoding (in this
- case, bad UTF-8 encoding).
- """
- q = QueryDict(b'foo=bar&foo=\xff')
- self.assertEqual(q['foo'], '\ufffd')
- self.assertEqual(q.getlist('foo'), ['bar', '\ufffd'])
+ if not six.PY3:
+ def test_invalid_input_encoding(self):
+ """
+ QueryDicts must be able to handle invalid input encoding (in this
+ case, bad UTF-8 encoding).
+
+ This test doesn't apply under Python 3 because the URL is a string
+ and not a bytestring.
+ """
+ q = QueryDict(str(b'foo=bar&foo=\xff'))
+ self.assertEqual(q['foo'], '\ufffd')
+ self.assertEqual(q.getlist('foo'), ['bar', '\ufffd'])
def test_pickle(self):
- q = QueryDict('')
+ q = QueryDict(str(''))
q1 = pickle.loads(pickle.dumps(q, 2))
self.assertEqual(q == q1, True)
- q = QueryDict('a=b&c=d')
+ q = QueryDict(str('a=b&c=d'))
q1 = pickle.loads(pickle.dumps(q, 2))
self.assertEqual(q == q1, True)
- q = QueryDict('a=b&c=d&a=1')
+ q = QueryDict(str('a=b&c=d&a=1'))
q1 = pickle.loads(pickle.dumps(q, 2))
self.assertEqual(q == q1, True)
def test_update_from_querydict(self):
"""Regression test for #8278: QueryDict.update(QueryDict)"""
- x = QueryDict("a=1&a=2", mutable=True)
- y = QueryDict("a=3&a=4")
+ x = QueryDict(str("a=1&a=2"), mutable=True)
+ y = QueryDict(str("a=3&a=4"))
x.update(y)
self.assertEqual(x.getlist('a'), ['1', '2', '3', '4'])
def test_non_default_encoding(self):
"""#13572 - QueryDict with a non-default encoding"""
- q = QueryDict(b'sbb=one', encoding='rot_13')
- self.assertEqual(q.encoding , 'rot_13' )
- self.assertEqual(q.items() , [('foo', 'bar')] )
- self.assertEqual(q.urlencode() , 'sbb=one' )
+ q = QueryDict(str('cur=%A4'), encoding='iso-8859-15')
+ self.assertEqual(q.encoding, 'iso-8859-15')
+ self.assertEqual(list(six.iteritems(q)), [('cur', '€')])
+ self.assertEqual(q.urlencode(), 'cur=%A4')
q = q.copy()
- self.assertEqual(q.encoding , 'rot_13' )
- self.assertEqual(q.items() , [('foo', 'bar')] )
- self.assertEqual(q.urlencode() , 'sbb=one' )
- self.assertEqual(copy.copy(q).encoding , 'rot_13' )
- self.assertEqual(copy.deepcopy(q).encoding , 'rot_13')
+ self.assertEqual(q.encoding, 'iso-8859-15')
+ self.assertEqual(list(six.iteritems(q)), [('cur', '€')])
+ self.assertEqual(q.urlencode(), 'cur=%A4')
+ self.assertEqual(copy.copy(q).encoding, 'iso-8859-15')
+ self.assertEqual(copy.deepcopy(q).encoding, 'iso-8859-15')
class HttpResponseTests(unittest.TestCase):
def test_unicode_headers(self):
@@ -260,45 +272,40 @@ class HttpResponseTests(unittest.TestCase):
def test_non_string_content(self):
#Bug 16494: HttpResponse should behave consistently with non-strings
r = HttpResponse(12345)
- self.assertEqual(r.content, '12345')
+ self.assertEqual(r.content, b'12345')
#test content via property
r = HttpResponse()
r.content = 12345
- self.assertEqual(r.content, '12345')
+ self.assertEqual(r.content, b'12345')
def test_iter_content(self):
r = HttpResponse(['abc', 'def', 'ghi'])
- self.assertEqual(r.content, 'abcdefghi')
+ self.assertEqual(r.content, b'abcdefghi')
#test iter content via property
r = HttpResponse()
r.content = ['idan', 'alex', 'jacob']
- self.assertEqual(r.content, 'idanalexjacob')
+ self.assertEqual(r.content, b'idanalexjacob')
r = HttpResponse()
r.content = [1, 2, 3]
- self.assertEqual(r.content, '123')
+ self.assertEqual(r.content, b'123')
#test retrieval explicitly using iter and odd inputs
r = HttpResponse()
- r.content = ['1', '2', 3, unichr(1950)]
- result = []
+ r.content = ['1', '2', 3, '\u079e']
my_iter = r.__iter__()
- while True:
- try:
- result.append(next(my_iter))
- except StopIteration:
- break
+ result = list(my_iter)
#'\xde\x9e' == unichr(1950).encode('utf-8')
- self.assertEqual(result, ['1', '2', '3', b'\xde\x9e'])
+ self.assertEqual(result, [b'1', b'2', b'3', b'\xde\x9e'])
self.assertEqual(r.content, b'123\xde\x9e')
#with Content-Encoding header
r = HttpResponse([1,1,2,4,8])
r['Content-Encoding'] = 'winning'
- self.assertEqual(r.content, '11248')
- r.content = [unichr(1950),]
+ self.assertEqual(r.content, b'11248')
+ r.content = ['\u079e',]
self.assertRaises(UnicodeEncodeError,
getattr, r, 'content')
@@ -325,6 +332,33 @@ class HttpResponseTests(unittest.TestCase):
HttpResponsePermanentRedirect, url)
+class HttpResponseSubclassesTests(TestCase):
+ def test_redirect(self):
+ response = HttpResponseRedirect('/redirected/')
+ self.assertEqual(response.status_code, 302)
+ # Test that standard HttpResponse init args can be used
+ response = HttpResponseRedirect('/redirected/',
+ content='The resource has temporarily moved',
+ content_type='text/html')
+ self.assertContains(response, 'The resource has temporarily moved', status_code=302)
+
+ def test_not_modified(self):
+ response = HttpResponseNotModified()
+ self.assertEqual(response.status_code, 304)
+ # 304 responses should not have content/content-type
+ with self.assertRaises(AttributeError):
+ response.content = "Hello dear"
+ self.assertNotIn('content-type', response)
+
+ def test_not_allowed(self):
+ response = HttpResponseNotAllowed(['GET'])
+ self.assertEqual(response.status_code, 405)
+ # Test that standard HttpResponse init args can be used
+ response = HttpResponseNotAllowed(['GET'],
+ content='Only the GET method is allowed',
+ content_type='text/html')
+ self.assertContains(response, 'Only the GET method is allowed', status_code=405)
+
class CookieTests(unittest.TestCase):
def test_encode(self):
"""
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 9ca66bdb9b..bce3d617d2 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -18,7 +18,7 @@ from django.utils.formats import (get_format, date_format, time_format,
number_format)
from django.utils.importlib import import_module
from django.utils.numberformat import format as nformat
-from django.utils.safestring import mark_safe, SafeString, SafeUnicode
+from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
from django.utils import six
from django.utils.six import PY3
from django.utils.translation import (ugettext, ugettext_lazy, activate,
@@ -232,12 +232,12 @@ class TranslationTests(TestCase):
"""
Translating a string requiring no auto-escaping shouldn't change the "safe" status.
"""
- s = mark_safe(b'Password')
+ s = mark_safe(str('Password'))
self.assertEqual(SafeString, type(s))
with translation.override('de', deactivate=True):
- self.assertEqual(SafeUnicode, type(ugettext(s)))
- self.assertEqual('aPassword', SafeString('a') + s)
- self.assertEqual('Passworda', s + SafeString('a'))
+ self.assertEqual(SafeText, type(ugettext(s)))
+ self.assertEqual('aPassword', SafeText('a') + s)
+ self.assertEqual('Passworda', s + SafeText('a'))
self.assertEqual('Passworda', s + mark_safe('a'))
self.assertEqual('aPassword', mark_safe('a') + s)
self.assertEqual('as', mark_safe('a') + mark_safe('s'))
@@ -808,13 +808,13 @@ class MiscTests(TestCase):
r.META = {'HTTP_ACCEPT_LANGUAGE': 'de'}
self.assertEqual(g(r), 'zh-cn')
- def test_get_language_from_path(self):
+ def test_get_language_from_path_real(self):
from django.utils.translation.trans_real import get_language_from_path as g
self.assertEqual(g('/pl/'), 'pl')
self.assertEqual(g('/pl'), 'pl')
self.assertEqual(g('/xyz/'), None)
- def test_get_language_from_path(self):
+ def test_get_language_from_path_null(self):
from django.utils.translation.trans_null import get_language_from_path as g
self.assertEqual(g('/pl/'), None)
self.assertEqual(g('/pl'), None)
@@ -897,9 +897,9 @@ class TestModels(TestCase):
def test_safestr(self):
c = Company(cents_paid=12, products_delivered=1)
- c.name = SafeUnicode('Iñtërnâtiônàlizætiøn1')
+ c.name = SafeText('Iñtërnâtiônàlizætiøn1')
c.save()
- c.name = SafeString('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
+ c.name = SafeBytes('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
c.save()
diff --git a/tests/regressiontests/inline_formsets/models.py b/tests/regressiontests/inline_formsets/models.py
index d76eea758b..40c85fe739 100644
--- a/tests/regressiontests/inline_formsets/models.py
+++ b/tests/regressiontests/inline_formsets/models.py
@@ -1,5 +1,6 @@
# coding: utf-8
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class School(models.Model):
@@ -14,15 +15,17 @@ class Child(models.Model):
school = models.ForeignKey(School)
name = models.CharField(max_length=100)
+@python_2_unicode_compatible
class Poet(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Poem(models.Model):
poet = models.ForeignKey(Poet)
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/inspectdb/models.py b/tests/regressiontests/inspectdb/models.py
index 9f815855b6..4a6621402f 100644
--- a/tests/regressiontests/inspectdb/models.py
+++ b/tests/regressiontests/inspectdb/models.py
@@ -19,3 +19,12 @@ class DigitsInColumnName(models.Model):
all_digits = models.CharField(max_length=11, db_column='123')
leading_digit = models.CharField(max_length=11, db_column='4extra')
leading_digits = models.CharField(max_length=11, db_column='45extra')
+
+class SpecialColumnName(models.Model):
+ field = models.IntegerField(db_column='field')
+ # Underscores
+ field_field_0 = models.IntegerField(db_column='Field_')
+ field_field_1 = models.IntegerField(db_column='Field__')
+ field_field_2 = models.IntegerField(db_column='__field')
+ # Other chars
+ prc_x = models.IntegerField(db_column='prc(%) x')
diff --git a/tests/regressiontests/inspectdb/tests.py b/tests/regressiontests/inspectdb/tests.py
index aae7bc5cc7..484e7f4060 100644
--- a/tests/regressiontests/inspectdb/tests.py
+++ b/tests/regressiontests/inspectdb/tests.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.core.management import call_command
from django.test import TestCase, skipUnlessDBFeature
from django.utils.six import StringIO
@@ -17,7 +19,6 @@ class InspectDBTestCase(TestCase):
# the Django test suite, check that one of its tables hasn't been
# inspected
self.assertNotIn("class DjangoContentType(models.Model):", out.getvalue(), msg=error_message)
- out.close()
@skipUnlessDBFeature('can_introspect_foreign_keys')
def test_attribute_name_not_python_keyword(self):
@@ -27,15 +28,16 @@ class InspectDBTestCase(TestCase):
call_command('inspectdb',
table_name_filter=lambda tn:tn.startswith('inspectdb_'),
stdout=out)
+ output = out.getvalue()
error_message = "inspectdb generated an attribute name which is a python keyword"
- self.assertNotIn("from = models.ForeignKey(InspectdbPeople)", out.getvalue(), msg=error_message)
+ self.assertNotIn("from = models.ForeignKey(InspectdbPeople)", output, msg=error_message)
# As InspectdbPeople model is defined after InspectdbMessage, it should be quoted
- self.assertIn("from_field = models.ForeignKey('InspectdbPeople')", out.getvalue())
+ self.assertIn("from_field = models.ForeignKey('InspectdbPeople', db_column='from_id')",
+ output)
self.assertIn("people_pk = models.ForeignKey(InspectdbPeople, primary_key=True)",
- out.getvalue())
+ output)
self.assertIn("people_unique = models.ForeignKey(InspectdbPeople, unique=True)",
- out.getvalue())
- out.close()
+ output)
def test_digits_column_name_introspection(self):
"""Introspection of column names consist/start with digits (#16536/#17676)"""
@@ -45,13 +47,27 @@ class InspectDBTestCase(TestCase):
call_command('inspectdb',
table_name_filter=lambda tn:tn.startswith('inspectdb_'),
stdout=out)
+ output = out.getvalue()
error_message = "inspectdb generated a model field name which is a number"
- self.assertNotIn(" 123 = models.CharField", out.getvalue(), msg=error_message)
- self.assertIn("number_123 = models.CharField", out.getvalue())
+ self.assertNotIn(" 123 = models.CharField", output, msg=error_message)
+ self.assertIn("number_123 = models.CharField", output)
error_message = "inspectdb generated a model field name which starts with a digit"
- self.assertNotIn(" 4extra = models.CharField", out.getvalue(), msg=error_message)
- self.assertIn("number_4extra = models.CharField", out.getvalue())
+ self.assertNotIn(" 4extra = models.CharField", output, msg=error_message)
+ self.assertIn("number_4extra = models.CharField", output)
+
+ self.assertNotIn(" 45extra = models.CharField", output, msg=error_message)
+ self.assertIn("number_45extra = models.CharField", output)
- self.assertNotIn(" 45extra = models.CharField", out.getvalue(), msg=error_message)
- self.assertIn("number_45extra = models.CharField", out.getvalue())
+ def test_special_column_name_introspection(self):
+ """Introspection of column names containing special characters,
+ unsuitable for Python identifiers
+ """
+ out = StringIO()
+ call_command('inspectdb', stdout=out)
+ output = out.getvalue()
+ self.assertIn("field = models.IntegerField()", output)
+ self.assertIn("field_field = models.IntegerField(db_column='Field_')", output)
+ self.assertIn("field_field_0 = models.IntegerField(db_column='Field__')", output)
+ self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output)
+ self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output)
diff --git a/tests/regressiontests/introspection/models.py b/tests/regressiontests/introspection/models.py
index 3ca80c5aab..6e5beba61d 100644
--- a/tests/regressiontests/introspection/models.py
+++ b/tests/regressiontests/introspection/models.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
@@ -12,15 +14,16 @@ class Reporter(models.Model):
class Meta:
unique_together = ('first_name', 'last_name')
- def __unicode__(self):
+ def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
- def __unicode__(self):
+ def __str__(self):
return self.headline
class Meta:
diff --git a/tests/regressiontests/introspection/tests.py b/tests/regressiontests/introspection/tests.py
index 06736a68cb..a54e0c670b 100644
--- a/tests/regressiontests/introspection/tests.py
+++ b/tests/regressiontests/introspection/tests.py
@@ -4,6 +4,7 @@ from functools import update_wrapper
from django.db import connection
from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature
+from django.utils import six
from .models import Reporter, Article
@@ -35,8 +36,7 @@ class IgnoreNotimplementedError(type):
attrs[k] = ignore_not_implemented(v)
return type.__new__(cls, name, bases, attrs)
-class IntrospectionTests(TestCase):
- __metaclass__ = IgnoreNotimplementedError
+class IntrospectionTests(six.with_metaclass(IgnoreNotimplementedError, TestCase)):
def test_table_names(self):
tl = connection.introspection.table_names()
@@ -89,6 +89,11 @@ class IntrospectionTests(TestCase):
[datatype(r[1], r) for r in desc],
['IntegerField', 'CharField', 'CharField', 'CharField', 'BigIntegerField']
)
+ # Check also length of CharFields
+ self.assertEqual(
+ [r[3] for r in desc if datatype(r[1], r) == 'CharField'],
+ [30, 30, 75]
+ )
# Oracle forces null=True under the hood in some cases (see
# https://docs.djangoproject.com/en/dev/ref/databases/#null-and-empty-strings)
diff --git a/tests/regressiontests/m2m_regress/models.py b/tests/regressiontests/m2m_regress/models.py
index be8dcae9c1..7c1108456e 100644
--- a/tests/regressiontests/m2m_regress/models.py
+++ b/tests/regressiontests/m2m_regress/models.py
@@ -1,37 +1,42 @@
from django.contrib.auth import models as auth
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# No related name is needed here, since symmetrical relations are not
# explicitly reversible.
+@python_2_unicode_compatible
class SelfRefer(models.Model):
name = models.CharField(max_length=10)
references = models.ManyToManyField('self')
related = models.ManyToManyField('self')
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return self.name
# Regression for #11956 -- a many to many to the base class
+@python_2_unicode_compatible
class TagCollection(Tag):
tags = models.ManyToManyField(Tag, related_name='tag_collections')
- def __unicode__(self):
+ def __str__(self):
return self.name
# A related_name is required on one of the ManyToManyField entries here because
# they are both addressable as reverse relations from Tag.
+@python_2_unicode_compatible
class Entry(models.Model):
name = models.CharField(max_length=10)
topics = models.ManyToManyField(Tag)
related = models.ManyToManyField(Tag, related_name="similar")
- def __unicode__(self):
+ def __str__(self):
return self.name
# Two models both inheriting from a base model with a self-referential m2m field
diff --git a/tests/regressiontests/m2m_through_regress/models.py b/tests/regressiontests/m2m_through_regress/models.py
index 1db3de1a4c..47c24ed5b2 100644
--- a/tests/regressiontests/m2m_through_regress/models.py
+++ b/tests/regressiontests/m2m_through_regress/models.py
@@ -2,40 +2,45 @@ from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# Forward declared intermediate model
+@python_2_unicode_compatible
class Membership(models.Model):
person = models.ForeignKey('Person')
group = models.ForeignKey('Group')
price = models.IntegerField(default=100)
- def __unicode__(self):
+ def __str__(self):
return "%s is a member of %s" % (self.person.name, self.group.name)
# using custom id column to test ticket #11107
+@python_2_unicode_compatible
class UserMembership(models.Model):
id = models.AutoField(db_column='usermembership_id', primary_key=True)
user = models.ForeignKey(User)
group = models.ForeignKey('Group')
price = models.IntegerField(default=100)
- def __unicode__(self):
+ def __str__(self):
return "%s is a user and member of %s" % (self.user.username, self.group.name)
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=128)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Group(models.Model):
name = models.CharField(max_length=128)
# Membership object defined as a class
members = models.ManyToManyField(Person, through=Membership)
user_members = models.ManyToManyField(User, through='UserMembership')
- def __unicode__(self):
+ def __str__(self):
return self.name
# A set of models that use an non-abstract inherited model as the 'through' model.
@@ -55,22 +60,25 @@ class B(models.Model):
# Using to_field on the through model
+@python_2_unicode_compatible
class Car(models.Model):
make = models.CharField(max_length=20, unique=True)
drivers = models.ManyToManyField('Driver', through='CarDriver')
- def __unicode__(self, ):
+ def __str__(self):
return self.make
+@python_2_unicode_compatible
class Driver(models.Model):
name = models.CharField(max_length=20, unique=True)
- def __unicode__(self, ):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class CarDriver(models.Model):
car = models.ForeignKey('Car', to_field='make')
driver = models.ForeignKey('Driver', to_field='name')
- def __unicode__(self, ):
+ def __str__(self):
return "pk=%s car=%s driver=%s" % (str(self.pk), self.car, self.driver)
diff --git a/tests/regressiontests/m2m_through_regress/tests.py b/tests/regressiontests/m2m_through_regress/tests.py
index 73a13654e7..458c194f89 100644
--- a/tests/regressiontests/m2m_through_regress/tests.py
+++ b/tests/regressiontests/m2m_through_regress/tests.py
@@ -1,10 +1,9 @@
from __future__ import absolute_import
-from io import BytesIO
-
from django.core import management
from django.contrib.auth.models import User
from django.test import TestCase
+from django.utils.six import StringIO
from .models import (Person, Group, Membership, UserMembership, Car, Driver,
CarDriver)
@@ -70,11 +69,11 @@ class M2MThroughTestCase(TestCase):
pks = {"p_pk": p.pk, "g_pk": g.pk, "m_pk": m.pk}
- out = BytesIO()
+ out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out)
self.assertEqual(out.getvalue().strip(), """[{"pk": %(m_pk)s, "model": "m2m_through_regress.membership", "fields": {"person": %(p_pk)s, "price": 100, "group": %(g_pk)s}}, {"pk": %(p_pk)s, "model": "m2m_through_regress.person", "fields": {"name": "Bob"}}, {"pk": %(g_pk)s, "model": "m2m_through_regress.group", "fields": {"name": "Roll"}}]""" % pks)
- out = BytesIO()
+ out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="xml",
indent=2, stdout=out)
self.assertEqual(out.getvalue().strip(), """
@@ -142,6 +141,6 @@ class ThroughLoadDataTestCase(TestCase):
def test_sequence_creation(self):
"Check that sequences on an m2m_through are created for the through model, not a phantom auto-generated m2m table. Refs #11107"
- out = BytesIO()
+ out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out)
self.assertEqual(out.getvalue().strip(), """[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}]""")
diff --git a/tests/regressiontests/mail/tests.py b/tests/regressiontests/mail/tests.py
index c948662bc3..3e9ae84650 100644
--- a/tests/regressiontests/mail/tests.py
+++ b/tests/regressiontests/mail/tests.py
@@ -553,6 +553,8 @@ class FileBackendTests(BaseEmailBackendTests, TestCase):
msg.send()
self.assertEqual(len(os.listdir(self.tmp_dir)), 3)
+ connection.close()
+
class ConsoleBackendTests(BaseEmailBackendTests, TestCase):
email_backend = 'django.core.mail.backends.console.EmailBackend'
diff --git a/tests/regressiontests/managers_regress/models.py b/tests/regressiontests/managers_regress/models.py
index fb6c530722..892505f24a 100644
--- a/tests/regressiontests/managers_regress/models.py
+++ b/tests/regressiontests/managers_regress/models.py
@@ -3,6 +3,7 @@ Various edge-cases for model managers.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class OnlyFred(models.Manager):
@@ -44,35 +45,40 @@ class AbstractBase3(models.Model):
class Meta:
abstract = True
+@python_2_unicode_compatible
class Parent(models.Model):
name = models.CharField(max_length=50)
manager = OnlyFred()
- def __unicode__(self):
+ def __str__(self):
return self.name
# Managers from base classes are inherited and, if no manager is specified
# *and* the parent has a manager specified, the first one (in the MRO) will
# become the default.
+@python_2_unicode_compatible
class Child1(AbstractBase1):
data = models.CharField(max_length=25)
- def __unicode__(self):
+ def __str__(self):
return self.data
+@python_2_unicode_compatible
class Child2(AbstractBase1, AbstractBase2):
data = models.CharField(max_length=25)
- def __unicode__(self):
+ def __str__(self):
return self.data
+@python_2_unicode_compatible
class Child3(AbstractBase1, AbstractBase3):
data = models.CharField(max_length=25)
- def __unicode__(self):
+ def __str__(self):
return self.data
+@python_2_unicode_compatible
class Child4(AbstractBase1):
data = models.CharField(max_length=25)
@@ -80,16 +86,17 @@ class Child4(AbstractBase1):
# inherited.
default = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.data
+@python_2_unicode_compatible
class Child5(AbstractBase3):
name = models.CharField(max_length=25)
default = OnlyFred()
objects = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.name
# Will inherit managers from AbstractBase1, but not Child4.
diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py
index 1e59c4c8c8..f3727820f8 100644
--- a/tests/regressiontests/many_to_one_regress/models.py
+++ b/tests/regressiontests/many_to_one_regress/models.py
@@ -4,6 +4,7 @@ Regression tests for a few ForeignKey bugs.
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# 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
@@ -30,18 +31,20 @@ class Child(models.Model):
# Multiple paths to the same model (#7110, #7125)
+@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Record(models.Model):
category = models.ForeignKey(Category)
+@python_2_unicode_compatible
class Relation(models.Model):
left = models.ForeignKey(Record, related_name='left_set')
right = models.ForeignKey(Record, related_name='right_set')
- def __unicode__(self):
+ def __str__(self):
return "%s - %s" % (self.left.category.name, self.right.category.name)
diff --git a/tests/regressiontests/middleware/tests.py b/tests/regressiontests/middleware/tests.py
index 08a385e6cf..eb66f2bbf3 100644
--- a/tests/regressiontests/middleware/tests.py
+++ b/tests/regressiontests/middleware/tests.py
@@ -3,6 +3,7 @@
import gzip
import re
import random
+from io import BytesIO
from django.conf import settings
from django.core import mail
@@ -14,8 +15,9 @@ from django.middleware.http import ConditionalGetMiddleware
from django.middleware.gzip import GZipMiddleware
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
+from django.utils import six
from django.utils.six.moves import xrange
-from django.utils.six import StringIO
+
class CommonMiddlewareTest(TestCase):
def setUp(self):
@@ -506,9 +508,9 @@ class GZipMiddlewareTest(TestCase):
"""
Tests the GZip middleware.
"""
- short_string = "This string is too short to be worth compressing."
- compressible_string = 'a' * 500
- uncompressible_string = ''.join(chr(random.randint(0, 255)) for _ in xrange(500))
+ short_string = b"This string is too short to be worth compressing."
+ compressible_string = b'a' * 500
+ uncompressible_string = b''.join(six.int2byte(random.randint(0, 255)) for _ in xrange(500))
def setUp(self):
self.req = HttpRequest()
@@ -526,7 +528,7 @@ class GZipMiddlewareTest(TestCase):
@staticmethod
def decompress(gzipped_string):
- return gzip.GzipFile(mode='rb', fileobj=StringIO(gzipped_string)).read()
+ return gzip.GzipFile(mode='rb', fileobj=BytesIO(gzipped_string)).read()
def test_compress_response(self):
"""
@@ -590,7 +592,7 @@ class ETagGZipMiddlewareTest(TestCase):
"""
Tests if the ETag middleware behaves correctly with GZip middleware.
"""
- compressible_string = 'a' * 500
+ compressible_string = b'a' * 500
def setUp(self):
self.rf = RequestFactory()
diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py
index 4dcfb17bb3..d9c123fb39 100644
--- a/tests/regressiontests/model_fields/models.py
+++ b/tests/regressiontests/model_fields/models.py
@@ -69,6 +69,33 @@ class BooleanModel(models.Model):
class RenamedField(models.Model):
modelname = models.IntegerField(name="fieldname", choices=((1,'One'),))
+class VerboseNameField(models.Model):
+ id = models.AutoField("verbose pk", primary_key=True)
+ field1 = models.BigIntegerField("verbose field1")
+ field2 = models.BooleanField("verbose field2")
+ field3 = models.CharField("verbose field3", max_length=10)
+ field4 = models.CommaSeparatedIntegerField("verbose field4", max_length=99)
+ field5 = models.DateField("verbose field5")
+ field6 = models.DateTimeField("verbose field6")
+ field7 = models.DecimalField("verbose field7", max_digits=6, decimal_places=1)
+ field8 = models.EmailField("verbose field8")
+ field9 = models.FileField("verbose field9", upload_to="unused")
+ field10 = models.FilePathField("verbose field10")
+ field11 = models.FloatField("verbose field11")
+ # Don't want to depend on PIL in this test
+ #field_image = models.ImageField("verbose field")
+ field12 = models.IntegerField("verbose field12")
+ field13 = models.IPAddressField("verbose field13")
+ field14 = models.GenericIPAddressField("verbose field14", protocol="ipv4")
+ field15 = models.NullBooleanField("verbose field15")
+ field16 = models.PositiveIntegerField("verbose field16")
+ field17 = models.PositiveSmallIntegerField("verbose field17")
+ field18 = models.SlugField("verbose field18")
+ field19 = models.SmallIntegerField("verbose field19")
+ field20 = models.TextField("verbose field20")
+ field21 = models.TimeField("verbose field21")
+ field22 = models.URLField("verbose field22")
+
# This model isn't used in any test, just here to ensure it validates successfully.
# See ticket #16570.
class DecimalLessThanOne(models.Model):
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index 7d6071accc..526aca4f98 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -12,7 +12,7 @@ from django.utils import six
from django.utils import unittest
from .models import (Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post,
- NullBooleanModel, BooleanModel, Document, RenamedField)
+ NullBooleanModel, BooleanModel, Document, RenamedField, VerboseNameField)
from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests,
TwoImageFieldTests, ImageFieldNoDimensionsTests,
@@ -64,6 +64,14 @@ class BasicFieldTests(test.TestCase):
self.assertTrue(hasattr(instance, 'get_fieldname_display'))
self.assertFalse(hasattr(instance, 'get_modelname_display'))
+ def test_field_verbose_name(self):
+ m = VerboseNameField
+ for i in range(1, 23):
+ self.assertEqual(m._meta.get_field('field%d' % i).verbose_name,
+ 'verbose field%d' % i)
+
+ self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk')
+
class DecimalFieldTests(test.TestCase):
def test_to_python(self):
f = models.DecimalField(max_digits=4, decimal_places=2)
diff --git a/tests/regressiontests/model_forms_regress/models.py b/tests/regressiontests/model_forms_regress/models.py
index 9259e260f0..f6e08d24dc 100644
--- a/tests/regressiontests/model_forms_regress/models.py
+++ b/tests/regressiontests/model_forms_regress/models.py
@@ -4,6 +4,7 @@ import os
from django.core.exceptions import ValidationError
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class Person(models.Model):
@@ -20,18 +21,20 @@ class Triple(models.Model):
class FilePathModel(models.Model):
path = models.FilePathField(path=os.path.dirname(__file__), match=".*\.py$", blank=True)
+@python_2_unicode_compatible
class Publication(models.Model):
title = models.CharField(max_length=30)
date_published = models.DateField()
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
- def __unicode__(self):
+ def __str__(self):
return self.headline
class CustomFileField(models.FileField):
diff --git a/tests/regressiontests/model_forms_regress/tests.py b/tests/regressiontests/model_forms_regress/tests.py
index 3cb129f84e..90c907f2a6 100644
--- a/tests/regressiontests/model_forms_regress/tests.py
+++ b/tests/regressiontests/model_forms_regress/tests.py
@@ -485,9 +485,8 @@ class CustomMetaclass(ModelFormMetaclass):
new.base_fields = {}
return new
-class CustomMetaclassForm(forms.ModelForm):
- __metaclass__ = CustomMetaclass
-
+class CustomMetaclassForm(six.with_metaclass(CustomMetaclass, forms.ModelForm)):
+ pass
class CustomMetaclassTestCase(TestCase):
def test_modelform_factory_metaclass(self):
diff --git a/tests/regressiontests/model_formsets_regress/models.py b/tests/regressiontests/model_formsets_regress/models.py
index 189ed8072e..f94ad51929 100644
--- a/tests/regressiontests/model_formsets_regress/models.py
+++ b/tests/regressiontests/model_formsets_regress/models.py
@@ -1,4 +1,5 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class User(models.Model):
@@ -22,9 +23,10 @@ class Manager(models.Model):
class Network(models.Model):
name = models.CharField(max_length=15)
+@python_2_unicode_compatible
class Host(models.Model):
network = models.ForeignKey(Network)
hostname = models.CharField(max_length=25)
- def __unicode__(self):
+ def __str__(self):
return self.hostname
diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py
index 5481298963..811c8175bb 100644
--- a/tests/regressiontests/model_inheritance_regress/models.py
+++ b/tests/regressiontests/model_inheritance_regress/models.py
@@ -3,7 +3,9 @@ from __future__ import unicode_literals
import datetime
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
@@ -11,28 +13,31 @@ class Place(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return "%s the place" % self.name
+@python_2_unicode_compatible
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the restaurant" % self.name
+@python_2_unicode_compatible
class ItalianRestaurant(Restaurant):
serves_gnocchi = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the italian restaurant" % self.name
+@python_2_unicode_compatible
class ParkingLot(Place):
# An explicit link to the parent (we can control the attribute name).
parent = models.OneToOneField(Place, primary_key=True, parent_link=True)
capacity = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return "%s the parking lot" % self.name
class ParkingLot2(Place):
@@ -64,13 +69,14 @@ class SelfRefParent(models.Model):
class SelfRefChild(SelfRefParent):
child_data = models.IntegerField()
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
class Meta:
ordering = ('-pub_date', 'headline')
- def __unicode__(self):
+ def __str__(self):
return self.headline
class ArticleWithAuthor(Article):
@@ -91,17 +97,19 @@ class Evaluation(Article):
class QualityControl(Evaluation):
assignee = models.CharField(max_length=50)
+@python_2_unicode_compatible
class BaseM(models.Model):
base_name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.base_name
+@python_2_unicode_compatible
class DerivedM(BaseM):
customPK = models.IntegerField(primary_key=True)
derived_name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return "PK = %d, base_name = %s, derived_name = %s" \
% (self.customPK, self.base_name, self.derived_name)
@@ -120,15 +128,17 @@ class InternalCertificationAudit(CertificationAudit):
auditing_dept = models.CharField(max_length=20)
# Check that abstract classes don't get m2m tables autocreated.
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class AbstractEvent(models.Model):
name = models.CharField(max_length=100)
attendees = models.ManyToManyField(Person, related_name="%(class)s_set")
@@ -137,7 +147,7 @@ class AbstractEvent(models.Model):
abstract = True
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
class BirthdayParty(AbstractEvent):
diff --git a/tests/regressiontests/model_inheritance_select_related/models.py b/tests/regressiontests/model_inheritance_select_related/models.py
index f810531bff..6b28772620 100644
--- a/tests/regressiontests/model_inheritance_select_related/models.py
+++ b/tests/regressiontests/model_inheritance_select_related/models.py
@@ -5,27 +5,31 @@ select_related().
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return "%s the place" % self.name
+@python_2_unicode_compatible
class Restaurant(Place):
serves_sushi = models.BooleanField()
serves_steak = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the restaurant" % self.name
+@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=50)
favorite_restaurant = models.ForeignKey(Restaurant)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py
index aca6d44837..82efb9c783 100644
--- a/tests/regressiontests/model_regress/models.py
+++ b/tests/regressiontests/model_regress/models.py
@@ -1,5 +1,6 @@
# coding: utf-8
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
CHOICES = (
@@ -8,6 +9,7 @@ CHOICES = (
)
+@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100, default='Default headline')
pub_date = models.DateTimeField()
@@ -20,7 +22,7 @@ class Article(models.Model):
# A utf-8 verbose name (Ångström's Articles) to test they are valid.
verbose_name = "\xc3\x85ngstr\xc3\xb6m's Articles"
- def __unicode__(self):
+ def __str__(self):
return self.headline
@@ -38,29 +40,31 @@ class Event(models.Model):
when = models.DateTimeField()
+@python_2_unicode_compatible
class Department(models.Model):
id = models.PositiveIntegerField(primary_key=True)
name = models.CharField(max_length=200)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Worker(models.Model):
department = models.ForeignKey(Department)
name = models.CharField(max_length=200)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class BrokenUnicodeMethod(models.Model):
name = models.CharField(max_length=7)
- def __unicode__(self):
- # Intentionally broken (trying to insert a unicode value into a str
- # object).
- return 'Názov: %s' % self.name
+ def __str__(self):
+ # Intentionally broken (invalid start byte in byte string).
+ return b'Name\xff: %s'.decode() % self.name
class NonAutoPK(models.Model):
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py
index 33202fad8f..fdbcabd187 100644
--- a/tests/regressiontests/modeladmin/models.py
+++ b/tests/regressiontests/modeladmin/models.py
@@ -1,8 +1,10 @@
# coding: utf-8
from django.contrib.auth.models import User
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Band(models.Model):
name = models.CharField(max_length=100)
bio = models.TextField()
@@ -11,7 +13,7 @@ class Band(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Concert(models.Model):
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py
index c2a1ca05ba..d55d50d0a5 100644
--- a/tests/regressiontests/modeladmin/tests.py
+++ b/tests/regressiontests/modeladmin/tests.py
@@ -5,7 +5,7 @@ from datetime import date
from django import forms
from django.conf import settings
from django.contrib.admin.options import (ModelAdmin, TabularInline,
- InlineModelAdmin, HORIZONTAL, VERTICAL)
+ HORIZONTAL, VERTICAL)
from django.contrib.admin.sites import AdminSite
from django.contrib.admin.validation import validate
from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect
@@ -15,7 +15,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.forms.models import BaseModelFormSet
from django.forms.widgets import Select
from django.test import TestCase
-from django.test.utils import override_settings, str_prefix
+from django.test.utils import str_prefix
from django.utils import unittest
from .models import Band, Concert, ValidationTestModel, ValidationTestInlineModel
@@ -24,6 +24,7 @@ from .models import Band, Concert, ValidationTestModel, ValidationTestInlineMode
class MockRequest(object):
pass
+
class MockSuperUser(object):
def has_perm(self, perm):
return True
@@ -47,7 +48,7 @@ class ModelAdminTests(TestCase):
def test_default_fields(self):
ma = ModelAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'bio', 'sign_date'])
def test_default_fieldsets(self):
@@ -72,7 +73,7 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
- self.assertEqual( ma.get_fieldsets(request),
+ self.assertEqual(ma.get_fieldsets(request),
[(None, {'fields': ['name']})])
self.assertEqual(ma.get_fieldsets(request, self.band),
@@ -90,8 +91,8 @@ class ModelAdminTests(TestCase):
fields = ['name']
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(), ['name'])
- self.assertEqual(ma.get_form(request, self.band).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields), ['name'])
+ self.assertEqual(list(ma.get_form(request, self.band).base_fields),
['name'])
# Using `fieldsets`.
@@ -99,8 +100,8 @@ class ModelAdminTests(TestCase):
fieldsets = [(None, {'fields': ['name']})]
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(), ['name'])
- self.assertEqual(ma.get_form(request, self.band).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields), ['name'])
+ self.assertEqual(list(ma.get_form(request, self.band).base_fields),
['name'])
# Using `exclude`.
@@ -108,7 +109,7 @@ class ModelAdminTests(TestCase):
exclude = ['bio']
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'sign_date'])
# You can also pass a tuple to `exclude`.
@@ -116,7 +117,7 @@ class ModelAdminTests(TestCase):
exclude = ('bio',)
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'sign_date'])
# Using `fields` and `exclude`.
@@ -125,7 +126,7 @@ class ModelAdminTests(TestCase):
exclude = ['bio']
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['name'])
def test_custom_form_meta_exclude_with_readonly(self):
@@ -148,8 +149,8 @@ class ModelAdminTests(TestCase):
form = AdminBandForm
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
- ['sign_date',])
+ self.assertEqual(list(ma.get_form(request).base_fields),
+ ['sign_date'])
# Then, with `InlineModelAdmin` -----------------
@@ -172,8 +173,8 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
- ['main_band', 'opening_band', 'id', 'DELETE',])
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
+ ['main_band', 'opening_band', 'id', 'DELETE'])
def test_custom_form_meta_exclude(self):
"""
@@ -194,8 +195,8 @@ class ModelAdminTests(TestCase):
form = AdminBandForm
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
- ['bio', 'sign_date',])
+ self.assertEqual(list(ma.get_form(request).base_fields),
+ ['bio', 'sign_date'])
# Then, with `InlineModelAdmin` -----------------
@@ -218,8 +219,8 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
- ['main_band', 'opening_band', 'day', 'id', 'DELETE',])
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
+ ['main_band', 'opening_band', 'day', 'id', 'DELETE'])
def test_custom_form_validation(self):
# If we specify a form, it should use it allowing custom validation to work
@@ -235,7 +236,7 @@ class ModelAdminTests(TestCase):
form = AdminBandForm
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'bio', 'sign_date', 'delete'])
self.assertEqual(
@@ -255,7 +256,7 @@ class ModelAdminTests(TestCase):
exclude = ['name']
class BandAdmin(ModelAdmin):
- exclude = ['sign_date',]
+ exclude = ['sign_date']
form = AdminBandForm
def get_form(self, request, obj=None, **kwargs):
@@ -263,9 +264,8 @@ class ModelAdminTests(TestCase):
return super(BandAdmin, self).get_form(request, obj, **kwargs)
ma = BandAdmin(Band, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
- ['name', 'sign_date',])
-
+ self.assertEqual(list(ma.get_form(request).base_fields),
+ ['name', 'sign_date'])
def test_formset_exclude_kwarg_override(self):
"""
@@ -296,8 +296,8 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
- ['main_band', 'day', 'transport', 'id', 'DELETE',])
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
+ ['main_band', 'day', 'transport', 'id', 'DELETE'])
def test_queryset_override(self):
# If we need to override the queryset of a ModelChoiceField in our custom form
@@ -461,7 +461,7 @@ class ModelAdminTests(TestCase):
form = AdminConcertForm
ma = ConcertAdmin(Concert, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['main_band', 'opening_band', 'day'])
class AdminConcertForm(forms.ModelForm):
@@ -475,7 +475,7 @@ class ModelAdminTests(TestCase):
form = AdminConcertForm
ma = ConcertAdmin(Concert, self.site)
- self.assertEqual(ma.get_form(request).base_fields.keys(),
+ self.assertEqual(list(ma.get_form(request).base_fields),
['extra', 'transport'])
class ConcertInline(TabularInline):
@@ -491,7 +491,7 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
self.assertEqual(
- list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
+ list(list(ma.get_formsets(request))[0]().forms[0].fields),
['extra', 'transport', 'id', 'DELETE', 'main_band'])
diff --git a/tests/regressiontests/multiple_database/models.py b/tests/regressiontests/multiple_database/models.py
index 7d655fe3d6..e46438649b 100644
--- a/tests/regressiontests/multiple_database/models.py
+++ b/tests/regressiontests/multiple_database/models.py
@@ -4,15 +4,17 @@ from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Review(models.Model):
source = models.CharField(max_length=100)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
- def __unicode__(self):
+ def __str__(self):
return self.source
class Meta:
@@ -22,11 +24,12 @@ class PersonManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)
+@python_2_unicode_compatible
class Person(models.Model):
objects = PersonManager()
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
@@ -45,6 +48,7 @@ class BookManager(models.Manager):
kwargs.pop('extra_arg', None)
return super(BookManager, self).get_or_create(*args, **kwargs)
+@python_2_unicode_compatible
class Book(models.Model):
objects = BookManager()
title = models.CharField(max_length=100)
@@ -54,17 +58,18 @@ class Book(models.Model):
reviews = generic.GenericRelation(Review)
pages = models.IntegerField(default=100)
- def __unicode__(self):
+ def __str__(self):
return self.title
class Meta:
ordering = ('title',)
+@python_2_unicode_compatible
class Pet(models.Model):
name = models.CharField(max_length=100)
owner = models.ForeignKey(Person)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Meta:
diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py
index 74a5f2f550..782fe2bfc6 100644
--- a/tests/regressiontests/multiple_database/tests.py
+++ b/tests/regressiontests/multiple_database/tests.py
@@ -1546,6 +1546,21 @@ class RouterTestCase(TestCase):
# If you evaluate the query, it should work, running on 'other'
self.assertEqual(list(qs.values_list('title', flat=True)), ['Dive into Python'])
+ def test_deferred_models(self):
+ mark_def = Person.objects.using('default').create(name="Mark Pilgrim")
+ mark_other = Person.objects.using('other').create(name="Mark Pilgrim")
+ orig_b = Book.objects.using('other').create(title="Dive into Python",
+ published=datetime.date(2009, 5, 4),
+ editor=mark_other)
+ b = Book.objects.using('other').only('title').get(pk=orig_b.pk)
+ self.assertEqual(b.published, datetime.date(2009, 5, 4))
+ b = Book.objects.using('other').only('title').get(pk=orig_b.pk)
+ b.editor = mark_def
+ b.save(using='default')
+ self.assertEqual(Book.objects.using('default').get(pk=b.pk).published,
+ datetime.date(2009, 5, 4))
+
+
class AuthTestCase(TestCase):
multi_db = True
diff --git a/tests/regressiontests/nested_foreign_keys/__init__.py b/tests/regressiontests/nested_foreign_keys/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/nested_foreign_keys/__init__.py
diff --git a/tests/regressiontests/nested_foreign_keys/models.py b/tests/regressiontests/nested_foreign_keys/models.py
new file mode 100644
index 0000000000..50d447951b
--- /dev/null
+++ b/tests/regressiontests/nested_foreign_keys/models.py
@@ -0,0 +1,28 @@
+from django.db import models
+
+
+class Person(models.Model):
+ name = models.CharField(max_length=200)
+
+
+class Movie(models.Model):
+ title = models.CharField(max_length=200)
+ director = models.ForeignKey(Person)
+
+
+class Event(models.Model):
+ pass
+
+
+class Screening(Event):
+ movie = models.ForeignKey(Movie)
+
+class ScreeningNullFK(Event):
+ movie = models.ForeignKey(Movie, null=True)
+
+
+class Package(models.Model):
+ screening = models.ForeignKey(Screening, null=True)
+
+class PackageNullFK(models.Model):
+ screening = models.ForeignKey(ScreeningNullFK, null=True)
diff --git a/tests/regressiontests/nested_foreign_keys/tests.py b/tests/regressiontests/nested_foreign_keys/tests.py
new file mode 100644
index 0000000000..a976d12453
--- /dev/null
+++ b/tests/regressiontests/nested_foreign_keys/tests.py
@@ -0,0 +1,166 @@
+from __future__ import absolute_import
+from django.test import TestCase
+
+from .models import Person, Movie, Event, Screening, ScreeningNullFK, Package, PackageNullFK
+
+
+# These are tests for #16715. The basic scheme is always the same: 3 models with
+# 2 relations. The first relation may be null, while the second is non-nullable.
+# In some cases, Django would pick the wrong join type for the second relation,
+# resulting in missing objects in the queryset.
+#
+# Model A
+# | (Relation A/B : nullable)
+# Model B
+# | (Relation B/C : non-nullable)
+# Model C
+#
+# Because of the possibility of NULL rows resulting from the LEFT OUTER JOIN
+# between Model A and Model B (i.e. instances of A without reference to B),
+# the second join must also be LEFT OUTER JOIN, so that we do not ignore
+# instances of A that do not reference B.
+#
+# Relation A/B can either be an explicit foreign key or an implicit reverse
+# relation such as introduced by one-to-one relations (through multi-table
+# inheritance).
+class NestedForeignKeysTests(TestCase):
+ def setUp(self):
+ self.director = Person.objects.create(name='Terry Gilliam / Terry Jones')
+ self.movie = Movie.objects.create(title='Monty Python and the Holy Grail', director=self.director)
+
+
+ # This test failed in #16715 because in some cases INNER JOIN was selected
+ # for the second foreign key relation instead of LEFT OUTER JOIN.
+ def testInheritance(self):
+ some_event = Event.objects.create()
+ screening = Screening.objects.create(movie=self.movie)
+
+ self.assertEqual(len(Event.objects.all()), 2)
+ self.assertEqual(len(Event.objects.select_related('screening')), 2)
+ # This failed.
+ self.assertEqual(len(Event.objects.select_related('screening__movie')), 2)
+
+ self.assertEqual(len(Event.objects.values()), 2)
+ self.assertEqual(len(Event.objects.values('screening__pk')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__pk')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__title')), 2)
+ # This failed.
+ self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__title')), 2)
+
+ # Simple filter/exclude queries for good measure.
+ self.assertEqual(Event.objects.filter(screening__movie=self.movie).count(), 1)
+ self.assertEqual(Event.objects.exclude(screening__movie=self.movie).count(), 1)
+
+
+ # These all work because the second foreign key in the chain has null=True.
+ def testInheritanceNullFK(self):
+ some_event = Event.objects.create()
+ screening = ScreeningNullFK.objects.create(movie=None)
+ screening_with_movie = ScreeningNullFK.objects.create(movie=self.movie)
+
+ self.assertEqual(len(Event.objects.all()), 3)
+ self.assertEqual(len(Event.objects.select_related('screeningnullfk')), 3)
+ self.assertEqual(len(Event.objects.select_related('screeningnullfk__movie')), 3)
+
+ self.assertEqual(len(Event.objects.values()), 3)
+ self.assertEqual(len(Event.objects.values('screeningnullfk__pk')), 3)
+ self.assertEqual(len(Event.objects.values('screeningnullfk__movie__pk')), 3)
+ self.assertEqual(len(Event.objects.values('screeningnullfk__movie__title')), 3)
+ self.assertEqual(len(Event.objects.values('screeningnullfk__movie__pk', 'screeningnullfk__movie__title')), 3)
+
+ self.assertEqual(Event.objects.filter(screeningnullfk__movie=self.movie).count(), 1)
+ self.assertEqual(Event.objects.exclude(screeningnullfk__movie=self.movie).count(), 2)
+
+
+ # This test failed in #16715 because in some cases INNER JOIN was selected
+ # for the second foreign key relation instead of LEFT OUTER JOIN.
+ def testExplicitForeignKey(self):
+ package = Package.objects.create()
+ screening = Screening.objects.create(movie=self.movie)
+ package_with_screening = Package.objects.create(screening=screening)
+
+ self.assertEqual(len(Package.objects.all()), 2)
+ self.assertEqual(len(Package.objects.select_related('screening')), 2)
+ self.assertEqual(len(Package.objects.select_related('screening__movie')), 2)
+
+ self.assertEqual(len(Package.objects.values()), 2)
+ self.assertEqual(len(Package.objects.values('screening__pk')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__pk')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__title')), 2)
+ # This failed.
+ self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__title')), 2)
+
+ self.assertEqual(Package.objects.filter(screening__movie=self.movie).count(), 1)
+ self.assertEqual(Package.objects.exclude(screening__movie=self.movie).count(), 1)
+
+
+ # These all work because the second foreign key in the chain has null=True.
+ def testExplicitForeignKeyNullFK(self):
+ package = PackageNullFK.objects.create()
+ screening = ScreeningNullFK.objects.create(movie=None)
+ screening_with_movie = ScreeningNullFK.objects.create(movie=self.movie)
+ package_with_screening = PackageNullFK.objects.create(screening=screening)
+ package_with_screening_with_movie = PackageNullFK.objects.create(screening=screening_with_movie)
+
+ self.assertEqual(len(PackageNullFK.objects.all()), 3)
+ self.assertEqual(len(PackageNullFK.objects.select_related('screening')), 3)
+ self.assertEqual(len(PackageNullFK.objects.select_related('screening__movie')), 3)
+
+ self.assertEqual(len(PackageNullFK.objects.values()), 3)
+ self.assertEqual(len(PackageNullFK.objects.values('screening__pk')), 3)
+ self.assertEqual(len(PackageNullFK.objects.values('screening__movie__pk')), 3)
+ self.assertEqual(len(PackageNullFK.objects.values('screening__movie__title')), 3)
+ self.assertEqual(len(PackageNullFK.objects.values('screening__movie__pk', 'screening__movie__title')), 3)
+
+ self.assertEqual(PackageNullFK.objects.filter(screening__movie=self.movie).count(), 1)
+ self.assertEqual(PackageNullFK.objects.exclude(screening__movie=self.movie).count(), 2)
+
+
+# Some additional tests for #16715. The only difference is the depth of the
+# nesting as we now use 4 models instead of 3 (and thus 3 relations). This
+# checks if promotion of join types works for deeper nesting too.
+class DeeplyNestedForeignKeysTests(TestCase):
+ def setUp(self):
+ self.director = Person.objects.create(name='Terry Gilliam / Terry Jones')
+ self.movie = Movie.objects.create(title='Monty Python and the Holy Grail', director=self.director)
+
+
+ def testInheritance(self):
+ some_event = Event.objects.create()
+ screening = Screening.objects.create(movie=self.movie)
+
+ self.assertEqual(len(Event.objects.all()), 2)
+ self.assertEqual(len(Event.objects.select_related('screening__movie__director')), 2)
+
+ self.assertEqual(len(Event.objects.values()), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__director__pk')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__director__name')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__director__pk', 'screening__movie__director__name')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2)
+ self.assertEqual(len(Event.objects.values('screening__movie__title', 'screening__movie__director__name')), 2)
+
+ self.assertEqual(Event.objects.filter(screening__movie__director=self.director).count(), 1)
+ self.assertEqual(Event.objects.exclude(screening__movie__director=self.director).count(), 1)
+
+
+ def testExplicitForeignKey(self):
+ package = Package.objects.create()
+ screening = Screening.objects.create(movie=self.movie)
+ package_with_screening = Package.objects.create(screening=screening)
+
+ self.assertEqual(len(Package.objects.all()), 2)
+ self.assertEqual(len(Package.objects.select_related('screening__movie__director')), 2)
+
+ self.assertEqual(len(Package.objects.values()), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__director__pk')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__director__name')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__director__pk', 'screening__movie__director__name')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2)
+ self.assertEqual(len(Package.objects.values('screening__movie__title', 'screening__movie__director__name')), 2)
+
+ self.assertEqual(Package.objects.filter(screening__movie__director=self.director).count(), 1)
+ self.assertEqual(Package.objects.exclude(screening__movie__director=self.director).count(), 1)
diff --git a/tests/regressiontests/null_fk/models.py b/tests/regressiontests/null_fk/models.py
index e32ff542a0..c86ee8a5a9 100644
--- a/tests/regressiontests/null_fk/models.py
+++ b/tests/regressiontests/null_fk/models.py
@@ -3,6 +3,7 @@ Regression tests for proper working of ForeignKey(null=True).
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
class SystemDetails(models.Model):
@@ -16,13 +17,15 @@ class Forum(models.Model):
system_info = models.ForeignKey(SystemInfo)
forum_name = models.CharField(max_length=32)
+@python_2_unicode_compatible
class Post(models.Model):
forum = models.ForeignKey(Forum, null=True)
title = models.CharField(max_length=32)
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Comment(models.Model):
post = models.ForeignKey(Post, null=True)
comment_text = models.CharField(max_length=250)
@@ -30,7 +33,7 @@ class Comment(models.Model):
class Meta:
ordering = ('comment_text',)
- def __unicode__(self):
+ def __str__(self):
return self.comment_text
# Ticket 15823
diff --git a/tests/regressiontests/null_fk_ordering/models.py b/tests/regressiontests/null_fk_ordering/models.py
index e4a19f1512..3caff0d594 100644
--- a/tests/regressiontests/null_fk_ordering/models.py
+++ b/tests/regressiontests/null_fk_ordering/models.py
@@ -8,17 +8,19 @@ xpected results
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
# The first two models represent a very simple null FK ordering case.
class Author(models.Model):
name = models.CharField(max_length=150)
+@python_2_unicode_compatible
class Article(models.Model):
title = models.CharField(max_length=150)
author = models.ForeignKey(Author, null=True)
- def __unicode__(self):
+ def __str__(self):
return 'Article titled: %s' % (self.title, )
class Meta:
@@ -33,13 +35,15 @@ class Forum(models.Model):
system_info = models.ForeignKey(SystemInfo)
forum_name = models.CharField(max_length=32)
+@python_2_unicode_compatible
class Post(models.Model):
forum = models.ForeignKey(Forum, null=True)
title = models.CharField(max_length=32)
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Comment(models.Model):
post = models.ForeignKey(Post, null=True)
comment_text = models.CharField(max_length=250)
@@ -47,5 +51,5 @@ class Comment(models.Model):
class Meta:
ordering = ['post__forum__system_info__system_name', 'comment_text']
- def __unicode__(self):
+ def __str__(self):
return self.comment_text
diff --git a/tests/regressiontests/null_queries/models.py b/tests/regressiontests/null_queries/models.py
index 886bd75276..25560fbab7 100644
--- a/tests/regressiontests/null_queries/models.py
+++ b/tests/regressiontests/null_queries/models.py
@@ -1,19 +1,22 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Poll(models.Model):
question = models.CharField(max_length=200)
- def __unicode__(self):
+ def __str__(self):
return "Q: %s " % self.question
+@python_2_unicode_compatible
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
- def __unicode__(self):
+ def __str__(self):
return "Choice: %s in poll %s" % (self.choice, self.poll)
# A set of models with an inner one pointing to two outer ones.
diff --git a/tests/regressiontests/one_to_one_regress/models.py b/tests/regressiontests/one_to_one_regress/models.py
index 5d32bf03f8..38b801f40e 100644
--- a/tests/regressiontests/one_to_one_regress/models.py
+++ b/tests/regressiontests/one_to_one_regress/models.py
@@ -1,39 +1,44 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
- def __unicode__(self):
+ def __str__(self):
return "%s the place" % self.name
+@python_2_unicode_compatible
class Restaurant(models.Model):
place = models.OneToOneField(Place)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the restaurant" % self.place.name
+@python_2_unicode_compatible
class Bar(models.Model):
place = models.OneToOneField(Place)
serves_cocktails = models.BooleanField()
- def __unicode__(self):
+ def __str__(self):
return "%s the bar" % self.place.name
class UndergroundBar(models.Model):
place = models.OneToOneField(Place, null=True)
serves_cocktails = models.BooleanField()
+@python_2_unicode_compatible
class Favorites(models.Model):
name = models.CharField(max_length = 50)
restaurants = models.ManyToManyField(Restaurant)
- def __unicode__(self):
+ def __str__(self):
return "Favorites for %s" % self.name
class Target(models.Model):
diff --git a/tests/regressiontests/pagination_regress/tests.py b/tests/regressiontests/pagination_regress/tests.py
index 59ac41e062..e98352e006 100644
--- a/tests/regressiontests/pagination_regress/tests.py
+++ b/tests/regressiontests/pagination_regress/tests.py
@@ -17,14 +17,16 @@ class PaginatorTests(TestCase):
paginator = Paginator(*params)
self.check_attribute('count', paginator, count, params)
self.check_attribute('num_pages', paginator, num_pages, params)
- self.check_attribute('page_range', paginator, page_range, params)
+ self.check_attribute('page_range', paginator, page_range, params, coerce=list)
- def check_attribute(self, name, paginator, expected, params):
+ def check_attribute(self, name, paginator, expected, params, coerce=None):
"""
Helper method that checks a single attribute and gives a nice error
message upon test failure.
"""
got = getattr(paginator, name)
+ if coerce is not None:
+ got = coerce(got)
self.assertEqual(expected, got,
"For '%s', expected %s but got %s. Paginator parameters were: %s"
% (name, expected, got, params))
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index 6328776e91..f0178a0256 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -7,6 +7,7 @@ import threading
from django.db import models
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class DumbCategory(models.Model):
@@ -19,6 +20,7 @@ class ProxyCategory(DumbCategory):
class NamedCategory(DumbCategory):
name = models.CharField(max_length=10)
+@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=10)
parent = models.ForeignKey('self', blank=True, null=True,
@@ -28,9 +30,10 @@ class Tag(models.Model):
class Meta:
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Note(models.Model):
note = models.CharField(max_length=100)
misc = models.CharField(max_length=10)
@@ -38,7 +41,7 @@ class Note(models.Model):
class Meta:
ordering = ['note']
- def __unicode__(self):
+ def __str__(self):
return self.note
def __init__(self, *args, **kwargs):
@@ -48,14 +51,16 @@ class Note(models.Model):
# that use objects of that type as an argument.
self.lock = threading.Lock()
+@python_2_unicode_compatible
class Annotation(models.Model):
name = models.CharField(max_length=10)
tag = models.ForeignKey(Tag)
notes = models.ManyToManyField(Note)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class ExtraInfo(models.Model):
info = models.CharField(max_length=100)
note = models.ForeignKey(Note)
@@ -63,9 +68,10 @@ class ExtraInfo(models.Model):
class Meta:
ordering = ['info']
- def __unicode__(self):
+ def __str__(self):
return self.info
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=10)
num = models.IntegerField(unique=True)
@@ -74,9 +80,10 @@ class Author(models.Model):
class Meta:
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Item(models.Model):
name = models.CharField(max_length=10)
created = models.DateTimeField()
@@ -88,16 +95,18 @@ class Item(models.Model):
class Meta:
ordering = ['-note', 'name']
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Report(models.Model):
name = models.CharField(max_length=10)
creator = models.ForeignKey(Author, to_field='num', null=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Ranking(models.Model):
rank = models.IntegerField()
author = models.ForeignKey(Author)
@@ -106,9 +115,10 @@ class Ranking(models.Model):
# A complex ordering specification. Should stress the system a bit.
ordering = ('author__extra__note', 'author__name', 'rank')
- def __unicode__(self):
+ def __str__(self):
return '%d: %s' % (self.rank, self.author.name)
+@python_2_unicode_compatible
class Cover(models.Model):
title = models.CharField(max_length=50)
item = models.ForeignKey(Item)
@@ -116,13 +126,14 @@ class Cover(models.Model):
class Meta:
ordering = ['item']
- def __unicode__(self):
+ def __str__(self):
return self.title
+@python_2_unicode_compatible
class Number(models.Model):
num = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return six.text_type(self.num)
# Symmetrical m2m field with a normal field using the reverse accesor name
@@ -168,6 +179,7 @@ class CustomManager(models.Manager):
qs = super(CustomManager, self).get_query_set()
return qs.filter(public=True, tag__name='t1')
+@python_2_unicode_compatible
class ManagedModel(models.Model):
data = models.CharField(max_length=10)
tag = models.ForeignKey(Tag)
@@ -176,7 +188,7 @@ class ManagedModel(models.Model):
objects = CustomManager()
normal_manager = models.Manager()
- def __unicode__(self):
+ def __str__(self):
return self.data
# An inter-related setup with multiple paths from Child to Detail.
@@ -211,11 +223,12 @@ class Related(models.Model):
# An inter-related setup with a model subclass that has a nullable
# path to another model, and a return path from that model.
+@python_2_unicode_compatible
class Celebrity(models.Model):
name = models.CharField("Name", max_length=20)
greatest_fan = models.ForeignKey("Fan", null=True, unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
class TvChef(Celebrity):
@@ -225,10 +238,11 @@ class Fan(models.Model):
fan_of = models.ForeignKey(Celebrity)
# Multiple foreign keys
+@python_2_unicode_compatible
class LeafA(models.Model):
data = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return self.data
class LeafB(models.Model):
@@ -238,11 +252,12 @@ class Join(models.Model):
a = models.ForeignKey(LeafA)
b = models.ForeignKey(LeafB)
+@python_2_unicode_compatible
class ReservedName(models.Model):
name = models.CharField(max_length=20)
order = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
# A simpler shared-foreign-key setup that can expose some problems.
@@ -256,13 +271,14 @@ class PointerB(models.Model):
connection = models.ForeignKey(SharedConnection)
# Multi-layer ordering
+@python_2_unicode_compatible
class SingleObject(models.Model):
name = models.CharField(max_length=10)
class Meta:
ordering = ['name']
- def __unicode__(self):
+ def __str__(self):
return self.name
class RelatedObject(models.Model):
@@ -271,6 +287,7 @@ class RelatedObject(models.Model):
class Meta:
ordering = ['single']
+@python_2_unicode_compatible
class Plaything(models.Model):
name = models.CharField(max_length=10)
others = models.ForeignKey(RelatedObject, null=True)
@@ -278,79 +295,89 @@ class Plaything(models.Model):
class Meta:
ordering = ['others']
- def __unicode__(self):
+ def __str__(self):
return self.name
class Article(models.Model):
name = models.CharField(max_length=20)
created = models.DateTimeField()
+@python_2_unicode_compatible
class Food(models.Model):
name = models.CharField(max_length=20, unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Eaten(models.Model):
food = models.ForeignKey(Food, to_field="name")
meal = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return "%s at %s" % (self.food, self.meal)
+@python_2_unicode_compatible
class Node(models.Model):
num = models.IntegerField(unique=True)
parent = models.ForeignKey("self", to_field="num", null=True)
- def __unicode__(self):
+ def __str__(self):
return "%s" % self.num
# Bug #12252
+@python_2_unicode_compatible
class ObjectA(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class ObjectB(models.Model):
name = models.CharField(max_length=50)
objecta = models.ForeignKey(ObjectA)
num = models.PositiveSmallIntegerField()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class ObjectC(models.Model):
name = models.CharField(max_length=50)
objecta = models.ForeignKey(ObjectA)
objectb = models.ForeignKey(ObjectB)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class SimpleCategory(models.Model):
name = models.CharField(max_length=15)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class SpecialCategory(SimpleCategory):
special_name = models.CharField(max_length=15)
- def __unicode__(self):
+ def __str__(self):
return self.name + " " + self.special_name
+@python_2_unicode_compatible
class CategoryItem(models.Model):
category = models.ForeignKey(SimpleCategory)
- def __unicode__(self):
+ def __str__(self):
return "category item: " + str(self.category)
+@python_2_unicode_compatible
class OneToOneCategory(models.Model):
new_name = models.CharField(max_length=15)
category = models.OneToOneField(SimpleCategory)
- def __unicode__(self):
+ def __str__(self):
return "one2one " + self.new_name
class NullableName(models.Model):
@@ -358,3 +385,18 @@ class NullableName(models.Model):
class Meta:
ordering = ['id']
+
+class ModelD(models.Model):
+ name = models.TextField()
+
+class ModelC(models.Model):
+ name = models.TextField()
+
+class ModelB(models.Model):
+ name = models.TextField()
+ c = models.ForeignKey(ModelC)
+
+class ModelA(models.Model):
+ name = models.TextField()
+ b = models.ForeignKey(ModelB, null=True)
+ d = models.ForeignKey(ModelD)
diff --git a/tests/regressiontests/queries/tests.py b/tests/regressiontests/queries/tests.py
index 1582993dfc..005aa9650b 100644
--- a/tests/regressiontests/queries/tests.py
+++ b/tests/regressiontests/queries/tests.py
@@ -23,7 +23,7 @@ from .models import (Annotation, Article, Author, Celebrity, Child, Cover,
Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten,
Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory,
SpecialCategory, OneToOneCategory, NullableName, ProxyCategory,
- SingleObject, RelatedObject)
+ SingleObject, RelatedObject, ModelA, ModelD)
class BaseQuerysetTest(TestCase):
@@ -806,7 +806,7 @@ class Queries1Tests(BaseQuerysetTest):
qs = Tag.objects.values_list('id', flat=True).order_by('id')
qs.query.bump_prefix()
first = qs[0]
- self.assertEqual(list(qs), range(first, first+5))
+ self.assertEqual(list(qs), list(range(first, first+5)))
def test_ticket8439(self):
# Complex combinations of conjunctions, disjunctions and nullable
@@ -1272,8 +1272,8 @@ class Queries5Tests(TestCase):
# them in a values() query.
dicts = qs.values('id', 'rank').order_by('id')
self.assertEqual(
- [d.items()[1] for d in dicts],
- [('rank', 2), ('rank', 1), ('rank', 3)]
+ [d['rank'] for d in dicts],
+ [2, 1, 3]
)
def test_ticket7256(self):
@@ -2043,65 +2043,88 @@ class WhereNodeTest(TestCase):
def test_empty_full_handling_conjunction(self):
qn = connection.ops.quote_name
w = WhereNode(children=[EverythingNode()])
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w.negate()
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w = WhereNode(children=[NothingNode()])
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w = WhereNode(children=[EverythingNode(), EverythingNode()])
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w.negate()
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w = WhereNode(children=[EverythingNode(), self.DummyNode()])
- self.assertEquals(w.as_sql(qn, connection), ('dummy', []))
+ self.assertEqual(w.as_sql(qn, connection), ('dummy', []))
w = WhereNode(children=[self.DummyNode(), self.DummyNode()])
- self.assertEquals(w.as_sql(qn, connection), ('(dummy AND dummy)', []))
+ self.assertEqual(w.as_sql(qn, connection), ('(dummy AND dummy)', []))
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy AND dummy)', []))
+ self.assertEqual(w.as_sql(qn, connection), ('NOT (dummy AND dummy)', []))
w = WhereNode(children=[NothingNode(), self.DummyNode()])
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
def test_empty_full_handling_disjunction(self):
qn = connection.ops.quote_name
w = WhereNode(children=[EverythingNode()], connector='OR')
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w.negate()
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w = WhereNode(children=[NothingNode()], connector='OR')
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w = WhereNode(children=[EverythingNode(), EverythingNode()], connector='OR')
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w.negate()
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w = WhereNode(children=[EverythingNode(), self.DummyNode()], connector='OR')
- self.assertEquals(w.as_sql(qn, connection), ('', []))
+ self.assertEqual(w.as_sql(qn, connection), ('', []))
w.negate()
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
w = WhereNode(children=[self.DummyNode(), self.DummyNode()], connector='OR')
- self.assertEquals(w.as_sql(qn, connection), ('(dummy OR dummy)', []))
+ self.assertEqual(w.as_sql(qn, connection), ('(dummy OR dummy)', []))
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy OR dummy)', []))
+ self.assertEqual(w.as_sql(qn, connection), ('NOT (dummy OR dummy)', []))
w = WhereNode(children=[NothingNode(), self.DummyNode()], connector='OR')
- self.assertEquals(w.as_sql(qn, connection), ('dummy', []))
+ self.assertEqual(w.as_sql(qn, connection), ('dummy', []))
w.negate()
- self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy)', []))
+ self.assertEqual(w.as_sql(qn, connection), ('NOT (dummy)', []))
def test_empty_nodes(self):
qn = connection.ops.quote_name
empty_w = WhereNode()
w = WhereNode(children=[empty_w, empty_w])
- self.assertEquals(w.as_sql(qn, connection), (None, []))
+ self.assertEqual(w.as_sql(qn, connection), (None, []))
w.negate()
- self.assertEquals(w.as_sql(qn, connection), (None, []))
+ self.assertEqual(w.as_sql(qn, connection), (None, []))
w.connector = 'OR'
- self.assertEquals(w.as_sql(qn, connection), (None, []))
+ self.assertEqual(w.as_sql(qn, connection), (None, []))
w.negate()
- self.assertEquals(w.as_sql(qn, connection), (None, []))
+ self.assertEqual(w.as_sql(qn, connection), (None, []))
w = WhereNode(children=[empty_w, NothingNode()], connector='OR')
self.assertRaises(EmptyResultSet, w.as_sql, qn, connection)
+
+class NullJoinPromotionOrTest(TestCase):
+ def setUp(self):
+ d = ModelD.objects.create(name='foo')
+ ModelA.objects.create(name='bar', d=d)
+
+ def test_ticket_17886(self):
+ # The first Q-object is generating the match, the rest of the filters
+ # should not remove the match even if they do not match anything. The
+ # problem here was that b__name generates a LOUTER JOIN, then
+ # b__c__name generates join to c, which the ORM tried to promote but
+ # failed as that join isn't nullable.
+ q_obj = (
+ Q(d__name='foo')|
+ Q(b__name='foo')|
+ Q(b__c__name='foo')
+ )
+ qset = ModelA.objects.filter(q_obj)
+ self.assertEqual(len(qset), 1)
+ # We generate one INNER JOIN to D. The join is direct and not nullable
+ # so we can use INNER JOIN for it. However, we can NOT use INNER JOIN
+ # for the b->c join, as a->b is nullable.
+ self.assertEqual(str(qset.query).count('INNER JOIN'), 1)
diff --git a/tests/regressiontests/requests/tests.py b/tests/regressiontests/requests/tests.py
index f192459246..f9e1112b2e 100644
--- a/tests/regressiontests/requests/tests.py
+++ b/tests/regressiontests/requests/tests.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
import time
import warnings
from datetime import datetime, timedelta
+from io import BytesIO
from django.conf import settings
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
@@ -10,17 +11,16 @@ from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_r
from django.test.utils import str_prefix
from django.utils import unittest
from django.utils.http import cookie_date
-from django.utils.six import StringIO
from django.utils.timezone import utc
class RequestsTests(unittest.TestCase):
def test_httprequest(self):
request = HttpRequest()
- self.assertEqual(request.GET.keys(), [])
- self.assertEqual(request.POST.keys(), [])
- self.assertEqual(request.COOKIES.keys(), [])
- self.assertEqual(request.META.keys(), [])
+ self.assertEqual(list(request.GET.keys()), [])
+ self.assertEqual(list(request.POST.keys()), [])
+ self.assertEqual(list(request.COOKIES.keys()), [])
+ self.assertEqual(list(request.META.keys()), [])
def test_httprequest_repr(self):
request = HttpRequest()
@@ -35,17 +35,17 @@ class RequestsTests(unittest.TestCase):
str_prefix("<HttpRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"))
def test_wsgirequest(self):
- request = WSGIRequest({'PATH_INFO': 'bogus', 'REQUEST_METHOD': 'bogus', 'wsgi.input': StringIO('')})
- self.assertEqual(request.GET.keys(), [])
- self.assertEqual(request.POST.keys(), [])
- self.assertEqual(request.COOKIES.keys(), [])
+ request = WSGIRequest({'PATH_INFO': 'bogus', 'REQUEST_METHOD': 'bogus', 'wsgi.input': BytesIO(b'')})
+ self.assertEqual(list(request.GET.keys()), [])
+ self.assertEqual(list(request.POST.keys()), [])
+ self.assertEqual(list(request.COOKIES.keys()), [])
self.assertEqual(set(request.META.keys()), set(['PATH_INFO', 'REQUEST_METHOD', 'SCRIPT_NAME', 'wsgi.input']))
self.assertEqual(request.META['PATH_INFO'], 'bogus')
self.assertEqual(request.META['REQUEST_METHOD'], 'bogus')
self.assertEqual(request.META['SCRIPT_NAME'], '')
def test_wsgirequest_repr(self):
- request = WSGIRequest({'PATH_INFO': '/somepath/', 'REQUEST_METHOD': 'get', 'wsgi.input': StringIO('')})
+ request = WSGIRequest({'PATH_INFO': '/somepath/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
request.GET = {'get-key': 'get-value'}
request.POST = {'post-key': 'post-value'}
request.COOKIES = {'post-key': 'post-value'}
@@ -207,26 +207,26 @@ class RequestsTests(unittest.TestCase):
def test_limited_stream(self):
# Read all of a limited stream
- stream = LimitedStream(StringIO(b'test'), 2)
+ stream = LimitedStream(BytesIO(b'test'), 2)
self.assertEqual(stream.read(), b'te')
# Reading again returns nothing.
self.assertEqual(stream.read(), b'')
# Read a number of characters greater than the stream has to offer
- stream = LimitedStream(StringIO(b'test'), 2)
+ stream = LimitedStream(BytesIO(b'test'), 2)
self.assertEqual(stream.read(5), b'te')
# Reading again returns nothing.
self.assertEqual(stream.readline(5), b'')
# Read sequentially from a stream
- stream = LimitedStream(StringIO(b'12345678'), 8)
+ stream = LimitedStream(BytesIO(b'12345678'), 8)
self.assertEqual(stream.read(5), b'12345')
self.assertEqual(stream.read(5), b'678')
# Reading again returns nothing.
self.assertEqual(stream.readline(5), b'')
# Read lines from a stream
- stream = LimitedStream(StringIO(b'1234\n5678\nabcd\nefgh\nijkl'), 24)
+ stream = LimitedStream(BytesIO(b'1234\n5678\nabcd\nefgh\nijkl'), 24)
# Read a full line, unconditionally
self.assertEqual(stream.readline(), b'1234\n')
# Read a number of characters less than a line
@@ -246,7 +246,7 @@ class RequestsTests(unittest.TestCase):
# If a stream contains a newline, but the provided length
# is less than the number of provided characters, the newline
# doesn't reset the available character count
- stream = LimitedStream(StringIO(b'1234\nabcdef'), 9)
+ stream = LimitedStream(BytesIO(b'1234\nabcdef'), 9)
self.assertEqual(stream.readline(10), b'1234\n')
self.assertEqual(stream.readline(3), b'abc')
# Now expire the available characters
@@ -255,7 +255,7 @@ class RequestsTests(unittest.TestCase):
self.assertEqual(stream.readline(2), b'')
# Same test, but with read, not readline.
- stream = LimitedStream(StringIO(b'1234\nabcdef'), 9)
+ stream = LimitedStream(BytesIO(b'1234\nabcdef'), 9)
self.assertEqual(stream.read(6), b'1234\na')
self.assertEqual(stream.read(2), b'bc')
self.assertEqual(stream.read(2), b'd')
@@ -266,7 +266,7 @@ class RequestsTests(unittest.TestCase):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(request.read(), b'name=value')
def test_read_after_value(self):
@@ -277,7 +277,7 @@ class RequestsTests(unittest.TestCase):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(request.POST, {'name': ['value']})
self.assertEqual(request.body, b'name=value')
self.assertEqual(request.read(), b'name=value')
@@ -290,7 +290,7 @@ class RequestsTests(unittest.TestCase):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(request.read(2), b'na')
self.assertRaises(Exception, lambda: request.body)
self.assertEqual(request.POST, {})
@@ -312,7 +312,7 @@ class RequestsTests(unittest.TestCase):
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(request.POST, {'name': ['value']})
self.assertRaises(Exception, lambda: request.body)
@@ -334,14 +334,14 @@ class RequestsTests(unittest.TestCase):
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
'CONTENT_LENGTH': 0,
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(request.POST, {})
def test_read_by_lines(self):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
self.assertEqual(list(request), [b'name=value'])
def test_POST_after_body_read(self):
@@ -351,7 +351,7 @@ class RequestsTests(unittest.TestCase):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
raw_data = request.body
self.assertEqual(request.POST, {'name': ['value']})
@@ -363,7 +363,7 @@ class RequestsTests(unittest.TestCase):
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
raw_data = request.body
self.assertEqual(request.read(1), b'n')
self.assertEqual(request.POST, {'name': ['value']})
@@ -383,7 +383,7 @@ class RequestsTests(unittest.TestCase):
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)})
+ 'wsgi.input': BytesIO(payload)})
raw_data = request.body
# Consume enough data to mess up the parsing:
self.assertEqual(request.read(13), b'--boundary\r\nC')
@@ -397,7 +397,7 @@ class RequestsTests(unittest.TestCase):
request = WSGIRequest({
'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': StringIO(payload)
+ 'wsgi.input': BytesIO(payload)
})
with warnings.catch_warnings(record=True):
@@ -408,14 +408,14 @@ class RequestsTests(unittest.TestCase):
If wsgi.input.read() raises an exception while trying to read() the
POST, the exception should be identifiable (not a generic IOError).
"""
- class ExplodingStringIO(StringIO):
+ class ExplodingBytesIO(BytesIO):
def read(self, len=0):
raise IOError("kaboom!")
payload = b'name=value'
request = WSGIRequest({'REQUEST_METHOD': 'POST',
'CONTENT_LENGTH': len(payload),
- 'wsgi.input': ExplodingStringIO(payload)})
+ 'wsgi.input': ExplodingBytesIO(payload)})
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
diff --git a/tests/regressiontests/select_related_onetoone/models.py b/tests/regressiontests/select_related_onetoone/models.py
index 3d6da9b4c5..3284defb11 100644
--- a/tests/regressiontests/select_related_onetoone/models.py
+++ b/tests/regressiontests/select_related_onetoone/models.py
@@ -1,44 +1,50 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class User(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField()
- def __unicode__(self):
+ def __str__(self):
return self.username
+@python_2_unicode_compatible
class UserProfile(models.Model):
user = models.OneToOneField(User)
city = models.CharField(max_length=100)
state = models.CharField(max_length=2)
- def __unicode__(self):
+ def __str__(self):
return "%s, %s" % (self.city, self.state)
+@python_2_unicode_compatible
class UserStatResult(models.Model):
results = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return 'UserStatResults, results = %s' % (self.results,)
+@python_2_unicode_compatible
class UserStat(models.Model):
user = models.OneToOneField(User, primary_key=True)
posts = models.IntegerField()
results = models.ForeignKey(UserStatResult)
- def __unicode__(self):
+ def __str__(self):
return 'UserStat, posts = %s' % (self.posts,)
+@python_2_unicode_compatible
class StatDetails(models.Model):
base_stats = models.OneToOneField(UserStat)
comments = models.IntegerField()
- def __unicode__(self):
+ def __str__(self):
return 'StatDetails, comments = %s' % (self.comments,)
diff --git a/tests/regressiontests/select_related_regress/models.py b/tests/regressiontests/select_related_regress/models.py
index 1af9ff4bca..a291a547f7 100644
--- a/tests/regressiontests/select_related_regress/models.py
+++ b/tests/regressiontests/select_related_regress/models.py
@@ -1,34 +1,39 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Building(models.Model):
name = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return "Building: %s" % self.name
+@python_2_unicode_compatible
class Device(models.Model):
building = models.ForeignKey('Building')
name = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return "device '%s' in building %s" % (self.name, self.building)
+@python_2_unicode_compatible
class Port(models.Model):
device = models.ForeignKey('Device')
port_number = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return "%s/%s" % (self.device.name, self.port_number)
+@python_2_unicode_compatible
class Connection(models.Model):
start = models.ForeignKey(Port, related_name='connection_start',
unique=True)
end = models.ForeignKey(Port, related_name='connection_end', unique=True)
- def __unicode__(self):
+ def __str__(self):
return "%s to %s" % (self.start, self.end)
# Another non-tree hierarchy that exercises code paths similar to the above
@@ -72,18 +77,20 @@ class SpecialClient(Client):
value = models.IntegerField()
# Some model inheritance exercises
+@python_2_unicode_compatible
class Parent(models.Model):
name = models.CharField(max_length=10)
- def __unicode__(self):
+ def __str__(self):
return self.name
class Child(Parent):
value = models.IntegerField()
+@python_2_unicode_compatible
class Item(models.Model):
name = models.CharField(max_length=10)
child = models.ForeignKey(Child, null=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
index 4e73be015c..f4b3adaa5e 100644
--- a/tests/regressiontests/serializers_regress/tests.py
+++ b/tests/regressiontests/serializers_regress/tests.py
@@ -10,7 +10,6 @@ from __future__ import absolute_import, unicode_literals
import datetime
import decimal
-from io import BytesIO
try:
import yaml
@@ -23,6 +22,7 @@ from django.core.serializers.base import DeserializationError
from django.db import connection, models
from django.http import HttpResponse
from django.test import TestCase
+from django.utils import six
from django.utils.functional import curry
from django.utils.unittest import skipUnless
@@ -502,17 +502,17 @@ def streamTest(format, self):
obj.save_base(raw=True)
# Serialize the test database to a stream
- for stream in (BytesIO(), HttpResponse()):
+ for stream in (six.StringIO(), HttpResponse()):
serializers.serialize(format, [obj], indent=2, stream=stream)
# Serialize normally for a comparison
string_data = serializers.serialize(format, [obj], indent=2)
# Check that the two are the same
- if isinstance(stream, BytesIO):
+ if isinstance(stream, six.StringIO):
self.assertEqual(string_data, stream.getvalue())
else:
- self.assertEqual(string_data, stream.content)
+ self.assertEqual(string_data, stream.content.decode('utf-8'))
stream.close()
for format in serializers.get_serializer_formats():
diff --git a/tests/regressiontests/servers/tests.py b/tests/regressiontests/servers/tests.py
index b98b4b73c2..c90c785a6e 100644
--- a/tests/regressiontests/servers/tests.py
+++ b/tests/regressiontests/servers/tests.py
@@ -144,7 +144,7 @@ class LiveServerDatabase(LiveServerBase):
Refs #2879.
"""
f = self.urlopen('/model_view/')
- self.assertEqual(f.read().splitlines(), ['jane', 'robert'])
+ self.assertEqual(f.read().splitlines(), [b'jane', b'robert'])
def test_database_writes(self):
"""
diff --git a/tests/regressiontests/settings_tests/tests.py b/tests/regressiontests/settings_tests/tests.py
index ffcb79eb09..7225fb03ef 100644
--- a/tests/regressiontests/settings_tests/tests.py
+++ b/tests/regressiontests/settings_tests/tests.py
@@ -148,6 +148,16 @@ class SettingsTests(TestCase):
def test_settings_delete_wrapped(self):
self.assertRaises(TypeError, delattr, settings, '_wrapped')
+ def test_override_settings_delete(self):
+ """
+ Allow deletion of a setting in an overriden settings set (#18824)
+ """
+ previous_i18n = settings.USE_I18N
+ with self.settings(USE_I18N=False):
+ del settings.USE_I18N
+ self.assertRaises(AttributeError, getattr, settings, 'USE_I18N')
+ self.assertEqual(settings.USE_I18N, previous_i18n)
+
def test_allowed_include_roots_string(self):
"""
ALLOWED_INCLUDE_ROOTS is not allowed to be incorrectly set to a string
diff --git a/tests/regressiontests/signals_regress/models.py b/tests/regressiontests/signals_regress/models.py
index bf64f69e8c..829314c06c 100644
--- a/tests/regressiontests/signals_regress/models.py
+++ b/tests/regressiontests/signals_regress/models.py
@@ -1,15 +1,18 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=20)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=20)
authors = models.ManyToManyField(Author)
- def __unicode__(self):
+ def __str__(self):
return self.name
diff --git a/tests/regressiontests/signing/tests.py b/tests/regressiontests/signing/tests.py
index 2368405060..05c8b3dc74 100644
--- a/tests/regressiontests/signing/tests.py
+++ b/tests/regressiontests/signing/tests.py
@@ -4,7 +4,8 @@ import time
from django.core import signing
from django.test import TestCase
-from django.utils.encoding import force_text
+from django.utils.encoding import force_str
+from django.utils import six
class TestSigner(TestCase):
@@ -21,7 +22,7 @@ class TestSigner(TestCase):
self.assertEqual(
signer.signature(s),
signing.base64_hmac(signer.salt + 'signer', s,
- 'predictable-secret')
+ 'predictable-secret').decode()
)
self.assertNotEqual(signer.signature(s), signer2.signature(s))
@@ -31,7 +32,8 @@ class TestSigner(TestCase):
self.assertEqual(
signer.signature('hello'),
signing.base64_hmac('extra-salt' + 'signer',
- 'hello', 'predictable-secret'))
+ 'hello', 'predictable-secret').decode()
+ )
self.assertNotEqual(
signing.Signer('predictable-secret', salt='one').signature('hello'),
signing.Signer('predictable-secret', salt='two').signature('hello'))
@@ -39,17 +41,20 @@ class TestSigner(TestCase):
def test_sign_unsign(self):
"sign/unsign should be reversible"
signer = signing.Signer('predictable-secret')
- examples = (
+ examples = [
'q;wjmbk;wkmb',
'3098247529087',
'3098247:529:087:',
'jkw osanteuh ,rcuh nthu aou oauh ,ud du',
'\u2019',
- )
+ ]
+ if not six.PY3:
+ examples.append(b'a byte string')
for example in examples:
- self.assertNotEqual(
- force_text(example), force_text(signer.sign(example)))
- self.assertEqual(example, signer.unsign(signer.sign(example)))
+ signed = signer.sign(example)
+ self.assertIsInstance(signed, str)
+ self.assertNotEqual(force_str(example), signed)
+ self.assertEqual(example, signer.unsign(signed))
def unsign_detects_tampering(self):
"unsign should raise an exception if the value has been tampered with"
@@ -69,15 +74,18 @@ class TestSigner(TestCase):
def test_dumps_loads(self):
"dumps and loads be reversible for any JSON serializable object"
- objects = (
+ objects = [
['a', 'list'],
- b'a string',
'a unicode string \u2019',
{'a': 'dictionary'},
- )
+ ]
+ if not six.PY3:
+ objects.append(b'a byte string')
for o in objects:
self.assertNotEqual(o, signing.dumps(o))
self.assertEqual(o, signing.loads(signing.dumps(o)))
+ self.assertNotEqual(o, signing.dumps(o, compress=True))
+ self.assertEqual(o, signing.loads(signing.dumps(o, compress=True)))
def test_decode_detects_tampering(self):
"loads should raise exception for tampered objects"
diff --git a/tests/regressiontests/sites_framework/models.py b/tests/regressiontests/sites_framework/models.py
index 9ecc3e6660..55c4f4992e 100644
--- a/tests/regressiontests/sites_framework/models.py
+++ b/tests/regressiontests/sites_framework/models.py
@@ -1,7 +1,9 @@
from django.contrib.sites.managers import CurrentSiteManager
from django.contrib.sites.models import Site
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class AbstractArticle(models.Model):
title = models.CharField(max_length=50)
@@ -11,7 +13,7 @@ class AbstractArticle(models.Model):
class Meta:
abstract = True
- def __unicode__(self):
+ def __str__(self):
return self.title
class SyndicatedArticle(AbstractArticle):
diff --git a/tests/regressiontests/staticfiles_tests/tests.py b/tests/regressiontests/staticfiles_tests/tests.py
index 19951f100b..078788a6a9 100644
--- a/tests/regressiontests/staticfiles_tests/tests.py
+++ b/tests/regressiontests/staticfiles_tests/tests.py
@@ -7,7 +7,6 @@ import posixpath
import shutil
import sys
import tempfile
-from io import BytesIO
from django.template import loader, Context
from django.conf import settings
@@ -194,19 +193,18 @@ class TestFindStatic(CollectionTestCase, TestDefaults):
Test ``findstatic`` management command.
"""
def _get_file(self, filepath):
- out = BytesIO()
+ out = six.StringIO()
call_command('findstatic', filepath, all=False, verbosity=0, stdout=out)
out.seek(0)
lines = [l.strip() for l in out.readlines()]
- contents = codecs.open(
- smart_text(lines[1].strip()), "r", "utf-8").read()
- return contents
+ with codecs.open(smart_text(lines[1].strip()), "r", "utf-8") as f:
+ return f.read()
def test_all_files(self):
"""
Test that findstatic returns all candidate files if run without --first.
"""
- out = BytesIO()
+ out = six.StringIO()
call_command('findstatic', 'test/file.txt', verbosity=0, stdout=out)
out.seek(0)
lines = [l.strip() for l in out.readlines()]
@@ -528,11 +526,11 @@ class TestCollectionCachedStorage(BaseCollectionTestCase,
"""
Handle cache key creation correctly, see #17861.
"""
- name = b"/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/" + chr(22) + chr(180)
+ name = "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff/some crazy/" + "\x16" + "\xb4"
cache_key = storage.staticfiles_storage.cache_key(name)
cache_validator = BaseCache({})
cache_validator.validate_key(cache_key)
- self.assertEqual(cache_key, 'staticfiles:e95bbc36387084582df2a70750d7b351')
+ self.assertEqual(cache_key, 'staticfiles:821ea71ef36f95b3922a77f7364670e7')
# we set DEBUG to False here since the template tag wouldn't work otherwise
@@ -570,8 +568,8 @@ class TestCollectionSimpleCachedStorage(BaseCollectionTestCase,
self.assertEqual(relpath, "cached/styles.deploy12345.css")
with storage.staticfiles_storage.open(relpath) as relfile:
content = relfile.read()
- self.assertNotIn("cached/other.css", content)
- self.assertIn("other.deploy12345.css", content)
+ self.assertNotIn(b"cached/other.css", content)
+ self.assertIn(b"other.deploy12345.css", content)
if sys.platform != 'win32':
diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py
index 53687a22cb..a2d64cd0b2 100644
--- a/tests/regressiontests/string_lookup/models.py
+++ b/tests/regressiontests/string_lookup/models.py
@@ -1,42 +1,51 @@
# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Foo(models.Model):
name = models.CharField(max_length=50)
friend = models.CharField(max_length=50, blank=True)
- def __unicode__(self):
+ def __str__(self):
return "Foo %s" % self.name
+@python_2_unicode_compatible
class Bar(models.Model):
name = models.CharField(max_length=50)
normal = models.ForeignKey(Foo, related_name='normal_foo')
fwd = models.ForeignKey("Whiz")
back = models.ForeignKey("Foo")
- def __unicode__(self):
+ def __str__(self):
return "Bar %s" % self.place.name
+@python_2_unicode_compatible
class Whiz(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "Whiz %s" % self.name
+@python_2_unicode_compatible
class Child(models.Model):
parent = models.OneToOneField('Base')
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "Child %s" % self.name
+@python_2_unicode_compatible
class Base(models.Model):
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return "Base %s" % self.name
+@python_2_unicode_compatible
class Article(models.Model):
name = models.CharField(max_length=50)
text = models.TextField()
diff --git a/tests/regressiontests/syndication/models.py b/tests/regressiontests/syndication/models.py
index a2c504e57f..10b3fe3a0c 100644
--- a/tests/regressiontests/syndication/models.py
+++ b/tests/regressiontests/syndication/models.py
@@ -1,6 +1,8 @@
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Entry(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField()
@@ -8,17 +10,18 @@ class Entry(models.Model):
class Meta:
ordering = ('date',)
- def __unicode__(self):
+ def __str__(self):
return self.title
def get_absolute_url(self):
return "/blog/%s/" % self.pk
+@python_2_unicode_compatible
class Article(models.Model):
title = models.CharField(max_length=200)
entry = models.ForeignKey(Entry)
- def __unicode__(self):
+ def __str__(self):
return self.title
diff --git a/tests/regressiontests/templates/filters.py b/tests/regressiontests/templates/filters.py
index fd570700af..8b4aebbf22 100644
--- a/tests/regressiontests/templates/filters.py
+++ b/tests/regressiontests/templates/filters.py
@@ -13,14 +13,17 @@ from datetime import date, datetime, timedelta
from django.test.utils import str_prefix
from django.utils.tzinfo import LocalTimezone, FixedOffset
from django.utils.safestring import mark_safe
+from django.utils.encoding import python_2_unicode_compatible
# These two classes are used to test auto-escaping of __unicode__ output.
+@python_2_unicode_compatible
class UnsafeClass:
- def __unicode__(self):
+ def __str__(self):
return 'you & me'
+@python_2_unicode_compatible
class SafeClass:
- def __unicode__(self):
+ def __str__(self):
return mark_safe('you &gt; me')
# RESULT SYNTAX --
@@ -111,7 +114,7 @@ def get_filter_tests():
# The make_list filter can destroy existing escaping, so the results are
# escaped.
'filter-make_list01': ("{% autoescape off %}{{ a|make_list }}{% endautoescape %}", {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
- 'filter-make_list02': ("{{ a|make_list }}", {"a": mark_safe("&")}, "[u&#39;&amp;&#39;]"),
+ 'filter-make_list02': ("{{ a|make_list }}", {"a": mark_safe("&")}, str_prefix("[%(_)s&#39;&amp;&#39;]")),
'filter-make_list03': ('{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
'filter-make_list04': ('{{ a|make_list|stringformat:"s"|safe }}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
@@ -338,11 +341,11 @@ def get_filter_tests():
'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'),
# Test that joining with unsafe joiners don't result in unsafe strings (#11377)
- 'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
- 'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
- 'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha &amp; beta &amp; me'),
- 'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
-
+ 'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
+ 'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
+ 'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha &amp; beta &amp; me'),
+ 'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
+
'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
#Ticket 9520: Make sure |date doesn't blow up on non-dates
diff --git a/tests/regressiontests/templates/response.py b/tests/regressiontests/templates/response.py
index 3c45b7a9d4..93919b95cd 100644
--- a/tests/regressiontests/templates/response.py
+++ b/tests/regressiontests/templates/response.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import os
import pickle
import time
@@ -29,16 +31,16 @@ class SimpleTemplateResponseTest(TestCase):
def test_template_resolving(self):
response = SimpleTemplateResponse('first/test.html')
response.render()
- self.assertEqual('First template\n', response.content)
+ self.assertEqual(response.content, b'First template\n')
templates = ['foo.html', 'second/test.html', 'first/test.html']
response = SimpleTemplateResponse(templates)
response.render()
- self.assertEqual('Second template\n', response.content)
+ self.assertEqual(response.content, b'Second template\n')
response = self._response()
response.render()
- self.assertEqual(response.content, 'foo')
+ self.assertEqual(response.content, b'foo')
def test_explicit_baking(self):
# explicit baking
@@ -50,17 +52,17 @@ class SimpleTemplateResponseTest(TestCase):
def test_render(self):
# response is not re-rendered without the render call
response = self._response().render()
- self.assertEqual(response.content, 'foo')
+ self.assertEqual(response.content, b'foo')
# rebaking doesn't change the rendered content
response.template_name = Template('bar{{ baz }}')
response.render()
- self.assertEqual(response.content, 'foo')
+ self.assertEqual(response.content, b'foo')
# but rendered content can be overridden by manually
# setting content
response.content = 'bar'
- self.assertEqual(response.content, 'bar')
+ self.assertEqual(response.content, b'bar')
def test_iteration_unrendered(self):
# unrendered response raises an exception on iteration
@@ -77,7 +79,7 @@ class SimpleTemplateResponseTest(TestCase):
# iteration works for rendered responses
response = self._response().render()
res = [x for x in response]
- self.assertEqual(res, ['foo'])
+ self.assertEqual(res, [b'foo'])
def test_content_access_unrendered(self):
# unrendered response raises an exception when content is accessed
@@ -89,7 +91,7 @@ class SimpleTemplateResponseTest(TestCase):
def test_content_access_rendered(self):
# rendered response content can be accessed
response = self._response().render()
- self.assertEqual(response.content, 'foo')
+ self.assertEqual(response.content, b'foo')
def test_set_content(self):
# content can be overriden
@@ -97,23 +99,23 @@ class SimpleTemplateResponseTest(TestCase):
self.assertFalse(response.is_rendered)
response.content = 'spam'
self.assertTrue(response.is_rendered)
- self.assertEqual(response.content, 'spam')
+ self.assertEqual(response.content, b'spam')
response.content = 'baz'
- self.assertEqual(response.content, 'baz')
+ self.assertEqual(response.content, b'baz')
def test_dict_context(self):
response = self._response('{{ foo }}{{ processors }}',
{'foo': 'bar'})
self.assertEqual(response.context_data, {'foo': 'bar'})
response.render()
- self.assertEqual(response.content, 'bar')
+ self.assertEqual(response.content, b'bar')
def test_context_instance(self):
response = self._response('{{ foo }}{{ processors }}',
Context({'foo': 'bar'}))
self.assertEqual(response.context_data.__class__, Context)
response.render()
- self.assertEqual(response.content, 'bar')
+ self.assertEqual(response.content, b'bar')
def test_kwargs(self):
response = self._response(content_type = 'application/json', status=504)
@@ -140,7 +142,7 @@ class SimpleTemplateResponseTest(TestCase):
# When the content is rendered, all the callbacks are invoked, too.
response.render()
- self.assertEqual('First template\n', response.content)
+ self.assertEqual(response.content, b'First template\n')
self.assertEqual(post, ['post1','post2'])
@@ -202,17 +204,17 @@ class TemplateResponseTest(TestCase):
def test_render(self):
response = self._response('{{ foo }}{{ processors }}').render()
- self.assertEqual(response.content, 'yes')
+ self.assertEqual(response.content, b'yes')
def test_render_with_requestcontext(self):
response = self._response('{{ foo }}{{ processors }}',
{'foo': 'bar'}).render()
- self.assertEqual(response.content, 'baryes')
+ self.assertEqual(response.content, b'baryes')
def test_render_with_context(self):
response = self._response('{{ foo }}{{ processors }}',
Context({'foo': 'bar'})).render()
- self.assertEqual(response.content, 'bar')
+ self.assertEqual(response.content, b'bar')
def test_kwargs(self):
response = self._response(content_type = 'application/json',
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index edbb21b6bd..41f40e7467 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -27,6 +27,7 @@ from django.test import RequestFactory
from django.test.utils import (setup_test_template_loader,
restore_template_loaders, override_settings)
from django.utils import unittest
+from django.utils.encoding import python_2_unicode_compatible
from django.utils.formats import date_format
from django.utils.translation import activate, deactivate, ugettext as _
from django.utils.safestring import mark_safe
@@ -46,7 +47,7 @@ from .response import (TemplateResponseTest, CacheMiddlewareTest,
try:
from .loaders import RenderToStringTest, EggLoaderTest
except ImportError as e:
- if "pkg_resources" in e.message:
+ if "pkg_resources" in e.args[0]:
pass # If setuptools isn't installed, that's fine. Just move on.
else:
raise
@@ -148,10 +149,11 @@ class SilentAttrClass(object):
raise SomeException
b = property(b)
+@python_2_unicode_compatible
class UTF8Class:
- "Class whose __str__ returns non-ASCII data"
+ "Class whose __str__ returns non-ASCII data on Python 2"
def __str__(self):
- return 'ŠĐĆŽćžšđ'.encode('utf-8')
+ return 'ŠĐĆŽćžšđ'
class Templates(unittest.TestCase):
def setUp(self):
@@ -408,8 +410,7 @@ class Templates(unittest.TestCase):
)
failures = []
- tests = template_tests.items()
- tests.sort()
+ tests = sorted(template_tests.items())
# Turn TEMPLATE_DEBUG off, because tests assume that.
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
@@ -418,7 +419,7 @@ class Templates(unittest.TestCase):
old_invalid = settings.TEMPLATE_STRING_IF_INVALID
expected_invalid_str = 'INVALID'
- #Set ALLOWED_INCLUDE_ROOTS so that ssi works.
+ # Set ALLOWED_INCLUDE_ROOTS so that ssi works.
old_allowed_include_roots = settings.ALLOWED_INCLUDE_ROOTS
settings.ALLOWED_INCLUDE_ROOTS = (
os.path.dirname(os.path.abspath(__file__)),
@@ -1452,8 +1453,9 @@ class Templates(unittest.TestCase):
'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'),
'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'),
- # 62.5 should round to 63
- 'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'),
+ # 62.5 should round to 63 on Python 2 and 62 on Python 3
+ # See http://docs.python.org/py3k/whatsnew/3.0.html
+ 'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '62' if six.PY3 else '63'),
# 71.4 should round to 71
'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'),
@@ -1466,6 +1468,14 @@ class Templates(unittest.TestCase):
# #10043: widthratio should allow max_width to be a variable
'widthratio11': ('{% widthratio a b c %}', {'a':50,'b':100, 'c': 100}, '50'),
+ # #18739: widthratio should handle None args consistently with non-numerics
+ 'widthratio12a': ('{% widthratio a b c %}', {'a':'a','b':100,'c':100}, ''),
+ 'widthratio12b': ('{% widthratio a b c %}', {'a':None,'b':100,'c':100}, ''),
+ 'widthratio13a': ('{% widthratio a b c %}', {'a':0,'b':'b','c':100}, ''),
+ 'widthratio13b': ('{% widthratio a b c %}', {'a':0,'b':None,'c':100}, ''),
+ 'widthratio14a': ('{% widthratio a b c %}', {'a':0,'b':100,'c':'c'}, template.TemplateSyntaxError),
+ 'widthratio14b': ('{% widthratio a b c %}', {'a':0,'b':100,'c':None}, template.TemplateSyntaxError),
+
### WITH TAG ########################################################
'with01': ('{% with key=dict.key %}{{ key }}{% endwith %}', {'dict': {'key': 50}}, '50'),
'legacywith01': ('{% with dict.key as key %}{{ key }}{% endwith %}', {'dict': {'key': 50}}, '50'),
diff --git a/tests/regressiontests/test_client_regress/tests.py b/tests/regressiontests/test_client_regress/tests.py
index 59f8f423dd..d80293b358 100644
--- a/tests/regressiontests/test_client_regress/tests.py
+++ b/tests/regressiontests/test_client_regress/tests.py
@@ -858,7 +858,7 @@ class UnicodePayloadTests(TestCase):
json = '{"english": "mountain pass"}'
response = self.client.post("/test_client_regress/parse_unicode_json/", json,
content_type="application/json")
- self.assertEqual(response.content, json)
+ self.assertEqual(response.content, json.encode())
def test_unicode_payload_utf8(self):
"A non-ASCII unicode data encoded as UTF-8 can be POSTed"
@@ -888,7 +888,7 @@ class DummyFile(object):
def __init__(self, filename):
self.name = filename
def read(self):
- return 'TEST_FILE_CONTENT'
+ return b'TEST_FILE_CONTENT'
class UploadedFileEncodingTest(TestCase):
def test_file_encoding(self):
diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py
index 8792a97dc0..9b0654806b 100644
--- a/tests/regressiontests/test_client_regress/views.py
+++ b/tests/regressiontests/test_client_regress/views.py
@@ -80,9 +80,7 @@ def return_json_file(request):
# This just checks that the uploaded data is JSON
obj_dict = json.loads(request.body.decode(charset))
- obj_json = json.dumps(obj_dict, encoding=charset,
- cls=DjangoJSONEncoder,
- ensure_ascii=False)
+ obj_json = json.dumps(obj_dict, cls=DjangoJSONEncoder, ensure_ascii=False)
response = HttpResponse(obj_json.encode(charset), status=200,
content_type='application/json; charset=%s' % charset)
response['Content-Disposition'] = 'attachment; filename=testfile.json'
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py
index f43a855a59..3749014372 100644
--- a/tests/regressiontests/test_utils/tests.py
+++ b/tests/regressiontests/test_utils/tests.py
@@ -5,6 +5,7 @@ from django.forms import EmailField, IntegerField
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
+from django.utils import six
from django.utils.unittest import skip
from .models import Person
@@ -495,12 +496,6 @@ __test__ = {"API_TEST": r"""
>>> from django.utils.xmlutils import SimplerXMLGenerator
>>> from django.utils.six import StringIO
->>> def produce_long():
-... return 42L
-
->>> def produce_int():
-... return 42
-
>>> def produce_json():
... return json.dumps(['foo', {'bar': ('baz', None, 1.0, 2), 'whiz': 42}])
@@ -529,14 +524,6 @@ __test__ = {"API_TEST": r"""
... xml.endElement("bar")
... return stream.getvalue()
-# Long values are normalized and are comparable to normal integers ...
->>> produce_long()
-42
-
-# ... and vice versa
->>> produce_int()
-42L
-
# JSON output is normalized for field order, so it doesn't matter
# which order json dictionary attributes are listed in output
>>> produce_json()
@@ -560,3 +547,21 @@ __test__ = {"API_TEST": r"""
'<foo bbb="2.0" aaa="1.0">Hello</foo><bar ddd="4.0" ccc="3.0"></bar>'
"""}
+
+if not six.PY3:
+ __test__["API_TEST"] += """
+>>> def produce_long():
+... return 42L
+
+>>> def produce_int():
+... return 42
+
+# Long values are normalized and are comparable to normal integers ...
+>>> produce_long()
+42
+
+# ... and vice versa
+>>> produce_int()
+42L
+
+"""
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
index 500a0e0327..168892719a 100644
--- a/tests/regressiontests/urlpatterns_reverse/tests.py
+++ b/tests/regressiontests/urlpatterns_reverse/tests.py
@@ -1,12 +1,13 @@
"""
Unit tests for reverse URL lookups.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
-from django.core.urlresolvers import (reverse, resolve, NoReverseMatch,
- Resolver404, ResolverMatch, RegexURLResolver, RegexURLPattern)
+from django.core.urlresolvers import (reverse, resolve, get_callable,
+ get_resolver, NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver,
+ RegexURLPattern)
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect
from django.test import TestCase
@@ -171,6 +172,16 @@ class URLPatternReverse(TestCase):
self.assertRaises(NoReverseMatch, reverse, None)
class ResolverTests(unittest.TestCase):
+ def test_resolver_repr(self):
+ """
+ Test repr of RegexURLResolver, especially when urlconf_name is a list
+ (#17892).
+ """
+ # Pick a resolver from a namespaced urlconf
+ resolver = get_resolver('regressiontests.urlpatterns_reverse.namespace_urls')
+ sub_resolver = resolver.namespace_dict['test-ns1'][1]
+ self.assertIn('<RegexURLPattern list>', repr(sub_resolver))
+
def test_non_regex(self):
"""
Verifies that we raise a Resolver404 if what we are resolving doesn't
@@ -405,8 +416,8 @@ class RequestURLconfTests(TestCase):
def test_urlconf(self):
response = self.client.get('/test/me/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'outer:/test/me/,'
- 'inner:/inner_urlconf/second_test/')
+ self.assertEqual(response.content, b'outer:/test/me/,'
+ b'inner:/inner_urlconf/second_test/')
response = self.client.get('/inner_urlconf/second_test/')
self.assertEqual(response.status_code, 200)
response = self.client.get('/second_test/')
@@ -422,7 +433,7 @@ class RequestURLconfTests(TestCase):
self.assertEqual(response.status_code, 404)
response = self.client.get('/second_test/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'outer:,inner:/second_test/')
+ self.assertEqual(response.content, b'outer:,inner:/second_test/')
def test_urlconf_overridden_with_null(self):
settings.MIDDLEWARE_CLASSES += (
@@ -519,3 +530,16 @@ class ErroneousViewTests(TestCase):
"""
# The regex error will be hit before NoReverseMatch can be raised
self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah')
+
+class ViewLoadingTests(TestCase):
+ def test_view_loading(self):
+ # A missing view (identified by an AttributeError) should raise
+ # ViewDoesNotExist, ...
+ self.assertRaisesRegexp(ViewDoesNotExist, ".*View does not exist in.*",
+ get_callable,
+ 'regressiontests.urlpatterns_reverse.views.i_should_not_exist')
+ # ... but if the AttributeError is caused by something else don't
+ # swallow it.
+ self.assertRaises(AttributeError, get_callable,
+ 'regressiontests.urlpatterns_reverse.views_broken.i_am_broken')
+
diff --git a/tests/regressiontests/urlpatterns_reverse/views_broken.py b/tests/regressiontests/urlpatterns_reverse/views_broken.py
new file mode 100644
index 0000000000..4953aab239
--- /dev/null
+++ b/tests/regressiontests/urlpatterns_reverse/views_broken.py
@@ -0,0 +1,2 @@
+# I just raise an AttributeError to confuse the view loading mechanism
+raise AttributeError('I am here to confuse django.core.urlresolvers.get_callable')
diff --git a/tests/regressiontests/utils/archive.py b/tests/regressiontests/utils/archive.py
index 0927c624f3..5575f340f6 100644
--- a/tests/regressiontests/utils/archive.py
+++ b/tests/regressiontests/utils/archive.py
@@ -27,12 +27,14 @@ class ArchiveTester(object):
os.chdir(self.old_cwd)
def test_extract_method(self):
- Archive(self.archive).extract(self.tmpdir)
+ with Archive(self.archive) as archive:
+ archive.extract(self.tmpdir)
self.check_files(self.tmpdir)
def test_extract_method_no_to_path(self):
os.chdir(self.tmpdir)
- Archive(self.archive_path).extract()
+ with Archive(self.archive_path) as archive:
+ archive.extract()
self.check_files(self.tmpdir)
def test_extract_function(self):
diff --git a/tests/regressiontests/utils/crypto.py b/tests/regressiontests/utils/crypto.py
index 52a286cb27..4c6b722ca9 100644
--- a/tests/regressiontests/utils/crypto.py
+++ b/tests/regressiontests/utils/crypto.py
@@ -6,7 +6,17 @@ import timeit
import hashlib
from django.utils import unittest
-from django.utils.crypto import pbkdf2
+from django.utils.crypto import constant_time_compare, pbkdf2
+
+
+class TestUtilsCryptoMisc(unittest.TestCase):
+
+ def test_constant_time_compare(self):
+ # It's hard to test for constant time, just test the result.
+ self.assertTrue(constant_time_compare(b'spam', b'spam'))
+ self.assertFalse(constant_time_compare(b'spam', b'eggs'))
+ self.assertTrue(constant_time_compare('spam', 'spam'))
+ self.assertFalse(constant_time_compare('spam', 'eggs'))
class TestUtilsCryptoPBKDF2(unittest.TestCase):
diff --git a/tests/regressiontests/utils/dateparse.py b/tests/regressiontests/utils/dateparse.py
new file mode 100644
index 0000000000..1a6ca646b8
--- /dev/null
+++ b/tests/regressiontests/utils/dateparse.py
@@ -0,0 +1,44 @@
+from __future__ import unicode_literals
+
+from datetime import date, time, datetime
+
+from django.utils.dateparse import parse_date, parse_time, parse_datetime
+from django.utils import unittest
+from django.utils.tzinfo import FixedOffset
+
+
+class DateParseTests(unittest.TestCase):
+
+ def test_parse_date(self):
+ # Valid inputs
+ self.assertEqual(parse_date('2012-04-23'), date(2012, 4, 23))
+ self.assertEqual(parse_date('2012-4-9'), date(2012, 4, 9))
+ # Invalid inputs
+ self.assertEqual(parse_date('20120423'), None)
+ self.assertRaises(ValueError, parse_date, '2012-04-56')
+
+ def test_parse_time(self):
+ # Valid inputs
+ self.assertEqual(parse_time('09:15:00'), time(9, 15))
+ self.assertEqual(parse_time('10:10'), time(10, 10))
+ self.assertEqual(parse_time('10:20:30.400'), time(10, 20, 30, 400000))
+ self.assertEqual(parse_time('4:8:16'), time(4, 8, 16))
+ # Invalid inputs
+ self.assertEqual(parse_time('091500'), None)
+ self.assertRaises(ValueError, parse_time, '09:15:90')
+
+ def test_parse_datetime(self):
+ # Valid inputs
+ self.assertEqual(parse_datetime('2012-04-23T09:15:00'),
+ datetime(2012, 4, 23, 9, 15))
+ self.assertEqual(parse_datetime('2012-4-9 4:8:16'),
+ datetime(2012, 4, 9, 4, 8, 16))
+ self.assertEqual(parse_datetime('2012-04-23T09:15:00Z'),
+ datetime(2012, 4, 23, 9, 15, 0, 0, FixedOffset(0)))
+ self.assertEqual(parse_datetime('2012-4-9 4:8:16-0320'),
+ datetime(2012, 4, 9, 4, 8, 16, 0, FixedOffset(-200)))
+ self.assertEqual(parse_datetime('2012-04-23T10:20:30.400+02:30'),
+ datetime(2012, 4, 23, 10, 20, 30, 400000, FixedOffset(150)))
+ # Invalid inputs
+ self.assertEqual(parse_datetime('20120423091500'), None)
+ self.assertRaises(ValueError, parse_datetime, '2012-04-56T09:15:90')
diff --git a/tests/regressiontests/utils/encoding.py b/tests/regressiontests/utils/encoding.py
new file mode 100644
index 0000000000..d191845518
--- /dev/null
+++ b/tests/regressiontests/utils/encoding.py
@@ -0,0 +1,17 @@
+# -*- encoding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.utils import unittest
+from django.utils.encoding import force_bytes
+
+
+class TestEncodingUtils(unittest.TestCase):
+ def test_force_bytes_exception(self):
+ """
+ Test that force_bytes knows how to convert to bytes an exception
+ containing non-ASCII characters in its args.
+ """
+ error_msg = "This is an exception, voilà"
+ exc = ValueError(error_msg)
+ result = force_bytes(exc)
+ self.assertEqual(result, error_msg.encode('utf-8'))
diff --git a/tests/regressiontests/utils/html.py b/tests/regressiontests/utils/html.py
index fe40d4eaae..98df80a5e2 100644
--- a/tests/regressiontests/utils/html.py
+++ b/tests/regressiontests/utils/html.py
@@ -146,3 +146,12 @@ class TestUtilsHtml(unittest.TestCase):
)
for value, output in items:
self.check_output(f, value, output)
+
+ def test_remove_tags(self):
+ f = html.remove_tags
+ items = (
+ ("<b><i>Yes</i></b>", "b i", "Yes"),
+ ("<a>x</a> <p><b>y</b></p>", "a b", "x <p>y</p>"),
+ )
+ for value, tags, output in items:
+ self.assertEquals(f(value, tags), output)
diff --git a/tests/regressiontests/utils/module_loading.py b/tests/regressiontests/utils/module_loading.py
index cbd81c7294..dffb51966c 100644
--- a/tests/regressiontests/utils/module_loading.py
+++ b/tests/regressiontests/utils/module_loading.py
@@ -109,7 +109,12 @@ class ProxyFinder(object):
def find_module(self, fullname, path=None):
tail = fullname.rsplit('.', 1)[-1]
try:
- self._cache[fullname] = imp.find_module(tail, path)
+ fd, fn, info = imp.find_module(tail, path)
+ if fullname in self._cache:
+ old_fd = self._cache[fullname][0]
+ if old_fd:
+ old_fd.close()
+ self._cache[fullname] = (fd, fn, info)
except ImportError:
return None
else:
@@ -119,7 +124,11 @@ class ProxyFinder(object):
if fullname in sys.modules:
return sys.modules[fullname]
fd, fn, info = self._cache[fullname]
- return imp.load_module(fullname, fd, fn, info)
+ try:
+ return imp.load_module(fullname, fd, fn, info)
+ finally:
+ if fd:
+ fd.close()
class TestFinder(object):
def __init__(self, *args, **kwargs):
diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py
index a7deeeefae..f4fa75b177 100644
--- a/tests/regressiontests/utils/tests.py
+++ b/tests/regressiontests/utils/tests.py
@@ -3,26 +3,28 @@ Tests for django.utils.
"""
from __future__ import absolute_import
+from .archive import TestBzip2Tar, TestGzipTar, TestTar, TestZip
+from .baseconv import TestBaseConv
+from .checksums import TestUtilsChecksums
+from .crypto import TestUtilsCryptoMisc, TestUtilsCryptoPBKDF2
+from .datastructures import (DictWrapperTests, ImmutableListTests,
+ MergeDictTests, MultiValueDictTests, SortedDictTests)
from .dateformat import DateFormatTests
+from .dateparse import DateParseTests
+from .datetime_safe import DatetimeTests
+from .decorators import DecoratorFromMiddlewareTests
+from .encoding import TestEncodingUtils
from .feedgenerator import FeedgeneratorTest
-from .module_loading import DefaultLoader, EggLoader, CustomLoader
-from .termcolors import TermColorTests
+from .functional import FunctionalTestCase
from .html import TestUtilsHtml
from .http import TestUtilsHttp
-from .checksums import TestUtilsChecksums
-from .text import TestUtilsText
+from .ipv6 import TestUtilsIPv6
+from .jslex import JsToCForGettextTest, JsTokensTest
+from .module_loading import CustomLoader, DefaultLoader, EggLoader
+from .regex_helper import NormalizeTests
from .simplelazyobject import TestUtilsSimpleLazyObject
-from .decorators import DecoratorFromMiddlewareTests
-from .functional import FunctionalTestCase
+from .termcolors import TermColorTests
+from .text import TestUtilsText
from .timesince import TimesinceTests
-from .datastructures import (MultiValueDictTests, SortedDictTests,
- DictWrapperTests, ImmutableListTests, MergeDictTests)
-from .tzinfo import TzinfoTests
-from .datetime_safe import DatetimeTests
-from .baseconv import TestBaseConv
-from .jslex import JsTokensTest, JsToCForGettextTest
-from .ipv6 import TestUtilsIPv6
from .timezone import TimezoneTests
-from .crypto import TestUtilsCryptoPBKDF2
-from .archive import TestZip, TestTar, TestGzipTar, TestBzip2Tar
-from .regex_helper import NormalizeTests
+from .tzinfo import TzinfoTests
diff --git a/tests/regressiontests/utils/text.py b/tests/regressiontests/utils/text.py
index dd6de63841..ebf67952f9 100644
--- a/tests/regressiontests/utils/text.py
+++ b/tests/regressiontests/utils/text.py
@@ -113,3 +113,11 @@ class TestUtilsText(SimpleTestCase):
self.assertEqual(text.wrap(long_word, 20), long_word)
self.assertEqual(text.wrap('a %s word' % long_word, 10),
'a\n%s\nword' % long_word)
+
+ def test_slugify(self):
+ items = (
+ ('Hello, World!', 'hello-world'),
+ ('spam & eggs', 'spam-eggs'),
+ )
+ for value, output in items:
+ self.assertEqual(text.slugify(value), output)
diff --git a/tests/regressiontests/views/models.py b/tests/regressiontests/views/models.py
index 54f5c1c1f0..461f98c028 100644
--- a/tests/regressiontests/views/models.py
+++ b/tests/regressiontests/views/models.py
@@ -3,16 +3,19 @@ Regression tests for Django built-in views.
"""
from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Author(models.Model):
name = models.CharField(max_length=100)
- def __unicode__(self):
+ def __str__(self):
return self.name
def get_absolute_url(self):
return '/views/authors/%s/' % self.id
+@python_2_unicode_compatible
class BaseArticle(models.Model):
"""
An abstract article Model so that we can create article models with and
@@ -25,7 +28,7 @@ class BaseArticle(models.Model):
class Meta:
abstract = True
- def __unicode__(self):
+ def __str__(self):
return self.title
class Article(BaseArticle):
diff --git a/tests/regressiontests/views/tests/debug.py b/tests/regressiontests/views/tests/debug.py
index e8a7d49e79..56383ac196 100644
--- a/tests/regressiontests/views/tests/debug.py
+++ b/tests/regressiontests/views/tests/debug.py
@@ -36,7 +36,7 @@ class DebugViewTests(TestCase):
self.assertEqual(response.status_code, 500)
data = {
- 'file_data.txt': SimpleUploadedFile('file_data.txt', 'haha'),
+ 'file_data.txt': SimpleUploadedFile('file_data.txt', b'haha'),
}
response = self.client.post('/raises/', data)
self.assertContains(response, 'file_data.txt', status_code=500)
diff --git a/tests/regressiontests/views/tests/i18n.py b/tests/regressiontests/views/tests/i18n.py
index cb580267d2..601df6d512 100644
--- a/tests/regressiontests/views/tests/i18n.py
+++ b/tests/regressiontests/views/tests/i18n.py
@@ -7,7 +7,8 @@ from os import path
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test import TestCase
-from django.utils.translation import override, activate, get_language
+from django.utils import six
+from django.utils.translation import override, get_language
from django.utils.text import javascript_quote
from ..urls import locale_dir
@@ -29,20 +30,21 @@ class I18NTests(TestCase):
def test_jsi18n(self):
"""The javascript_catalog can be deployed with language settings"""
- saved_lang = get_language()
for lang_code in ['es', 'fr', 'ru']:
- activate(lang_code)
- catalog = gettext.translation('djangojs', locale_dir, [lang_code])
- trans_txt = catalog.ugettext('this is to be translated')
- response = self.client.get('/views/jsi18n/')
- # in response content must to be a line like that:
- # catalog['this is to be translated'] = 'same_that_trans_txt'
- # javascript_quote is used to be able to check unicode strings
- self.assertContains(response, javascript_quote(trans_txt), 1)
- if lang_code == 'fr':
- # Message with context (msgctxt)
- self.assertContains(response, "['month name\x04May'] = 'mai';", 1)
- activate(saved_lang)
+ with override(lang_code):
+ catalog = gettext.translation('djangojs', locale_dir, [lang_code])
+ if six.PY3:
+ trans_txt = catalog.gettext('this is to be translated')
+ else:
+ trans_txt = catalog.ugettext('this is to be translated')
+ response = self.client.get('/views/jsi18n/')
+ # in response content must to be a line like that:
+ # catalog['this is to be translated'] = 'same_that_trans_txt'
+ # javascript_quote is used to be able to check unicode strings
+ self.assertContains(response, javascript_quote(trans_txt), 1)
+ if lang_code == 'fr':
+ # Message with context (msgctxt)
+ self.assertContains(response, "['month name\x04May'] = 'mai';", 1)
class JsI18NTests(TestCase):
diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py
index a48bb25d0b..62bd82f4a7 100644
--- a/tests/regressiontests/views/tests/shortcuts.py
+++ b/tests/regressiontests/views/tests/shortcuts.py
@@ -12,44 +12,44 @@ class ShortcutTests(TestCase):
def test_render_to_response(self):
response = self.client.get('/shortcuts/render_to_response/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR..\n')
+ self.assertEqual(response.content, b'FOO.BAR..\n')
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_to_response_with_request_context(self):
response = self.client.get('/shortcuts/render_to_response/request_context/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR../path/to/static/media/\n')
+ self.assertEqual(response.content, b'FOO.BAR../path/to/static/media/\n')
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_to_response_with_mimetype(self):
response = self.client.get('/shortcuts/render_to_response/mimetype/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR..\n')
+ self.assertEqual(response.content, b'FOO.BAR..\n')
self.assertEqual(response['Content-Type'], 'application/x-rendertest')
def test_render(self):
response = self.client.get('/shortcuts/render/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR../path/to/static/media/\n')
+ self.assertEqual(response.content, b'FOO.BAR../path/to/static/media/\n')
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
self.assertEqual(response.context.current_app, None)
def test_render_with_base_context(self):
response = self.client.get('/shortcuts/render/base_context/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR..\n')
+ self.assertEqual(response.content, b'FOO.BAR..\n')
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_with_content_type(self):
response = self.client.get('/shortcuts/render/content_type/')
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.content, 'FOO.BAR../path/to/static/media/\n')
+ self.assertEqual(response.content, b'FOO.BAR../path/to/static/media/\n')
self.assertEqual(response['Content-Type'], 'application/x-rendertest')
def test_render_with_status(self):
response = self.client.get('/shortcuts/render/status/')
self.assertEqual(response.status_code, 403)
- self.assertEqual(response.content, 'FOO.BAR../path/to/static/media/\n')
+ self.assertEqual(response.content, b'FOO.BAR../path/to/static/media/\n')
def test_render_with_current_app(self):
response = self.client.get('/shortcuts/render/current_app/')
diff --git a/tests/regressiontests/wsgi/tests.py b/tests/regressiontests/wsgi/tests.py
index a482a5c1eb..5a40bd88e2 100644
--- a/tests/regressiontests/wsgi/tests.py
+++ b/tests/regressiontests/wsgi/tests.py
@@ -40,8 +40,8 @@ class WSGITest(TestCase):
response_data["headers"],
[('Content-Type', 'text/html; charset=utf-8')])
self.assertEqual(
- six.text_type(response),
- "Content-Type: text/html; charset=utf-8\n\nHello World!")
+ bytes(response),
+ b"Content-Type: text/html; charset=utf-8\r\n\r\nHello World!")
class GetInternalWSGIApplicationTest(unittest.TestCase):