summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2013-08-09 14:17:30 +0100
committerAndrew Godwin <andrew@aeracode.org>2013-08-09 14:17:30 +0100
commitde64c4d6e97c980fb4c0ace045fc4070b3f763d9 (patch)
tree045c8af6a88fa964cf7e284970a6e93d53941a79 /tests
parentfddc5957c53bd654312c4a238a8cdcfe5f4ef4cc (diff)
parentb575d690bbc1c4cd7f575346132c09fca8c736a7 (diff)
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts: django/core/management/commands/flush.py django/core/management/commands/syncdb.py django/db/models/loading.py docs/internals/deprecation.txt docs/ref/django-admin.txt docs/releases/1.7.txt
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_changelist/admin.py9
-rw-r--r--tests/admin_changelist/tests.py18
-rw-r--r--tests/admin_custom_urls/tests.py2
-rw-r--r--tests/admin_docs/urls.py3
-rw-r--r--tests/admin_filters/tests.py2
-rw-r--r--tests/admin_inlines/admin.py2
-rw-r--r--tests/admin_inlines/tests.py2
-rw-r--r--tests/admin_inlines/urls.py2
-rw-r--r--tests/admin_ordering/tests.py2
-rw-r--r--tests/admin_registration/tests.py2
-rw-r--r--tests/admin_scripts/complex_app/admin/foo.py2
-rw-r--r--tests/admin_scripts/complex_app/models/bar.py2
-rw-r--r--tests/admin_scripts/management/commands/color_command.py9
-rw-r--r--tests/admin_scripts/simple_app/models.py2
-rw-r--r--tests/admin_scripts/tests.py55
-rw-r--r--tests/admin_util/tests.py6
-rw-r--r--tests/admin_validation/tests.py9
-rw-r--r--tests/admin_views/admin.py2
-rw-r--r--tests/admin_views/customadmin.py3
-rw-r--r--tests/admin_views/models.py4
-rw-r--r--tests/admin_views/tests.py89
-rw-r--r--tests/admin_views/urls.py2
-rw-r--r--tests/admin_widgets/models.py4
-rw-r--r--tests/admin_widgets/tests.py133
-rw-r--r--tests/admin_widgets/urls.py2
-rw-r--r--tests/admin_widgets/widgetadmin.py9
-rw-r--r--tests/aggregation/tests.py34
-rw-r--r--tests/aggregation_regress/tests.py9
-rw-r--r--tests/app_loading/tests.py32
-rw-r--r--tests/backends/models.py7
-rw-r--r--tests/backends/tests.py41
-rw-r--r--tests/basic/tests.py59
-rw-r--r--tests/bug639/tests.py2
-rw-r--r--tests/bug8245/admin.py2
-rw-r--r--tests/bulk_create/tests.py2
-rw-r--r--tests/cache/tests.py2
-rw-r--r--tests/choices/tests.py2
-rw-r--r--tests/comment_tests/tests/__init__.py2
-rw-r--r--tests/comment_tests/tests/test_app_api.py2
-rw-r--r--tests/comment_tests/tests/test_comment_form.py2
-rw-r--r--tests/comment_tests/tests/test_comment_utils_moderators.py2
-rw-r--r--tests/comment_tests/tests/test_comment_view.py2
-rw-r--r--tests/comment_tests/tests/test_feeds.py2
-rw-r--r--tests/comment_tests/tests/test_models.py2
-rw-r--r--tests/comment_tests/tests/test_moderation_views.py2
-rw-r--r--tests/comment_tests/tests/test_templatetags.py2
-rw-r--r--tests/comment_tests/urls.py2
-rw-r--r--tests/conditional_processing/views.py3
-rw-r--r--tests/contenttypes_tests/models.py2
-rw-r--r--tests/contenttypes_tests/tests.py2
-rw-r--r--tests/contenttypes_tests/urls.py2
-rw-r--r--tests/context_processors/urls.py2
-rw-r--r--tests/custom_columns/tests.py2
-rw-r--r--tests/custom_columns_regress/tests.py2
-rw-r--r--tests/custom_managers/models.py52
-rw-r--r--tests/custom_managers/tests.py44
-rw-r--r--tests/custom_managers_regress/tests.py2
-rw-r--r--tests/custom_methods/tests.py2
-rw-r--r--tests/custom_pk/models.py2
-rw-r--r--tests/custom_pk/tests.py2
-rw-r--r--tests/datatypes/tests.py2
-rw-r--r--tests/dates/tests.py2
-rw-r--r--tests/datetimes/tests.py2
-rw-r--r--tests/defaultfilters/tests.py7
-rw-r--r--tests/defer/tests.py2
-rw-r--r--tests/defer_regress/tests.py2
-rw-r--r--tests/delete/tests.py2
-rw-r--r--tests/delete_regress/tests.py2
-rw-r--r--tests/dispatch/tests/__init__.py2
-rw-r--r--tests/distinct_on_fields/tests.py2
-rw-r--r--tests/empty/tests.py2
-rw-r--r--tests/expressions/tests.py2
-rw-r--r--tests/expressions_regress/tests.py2
-rw-r--r--tests/extra_regress/tests.py40
-rw-r--r--tests/field_defaults/tests.py2
-rw-r--r--tests/field_subclassing/models.py2
-rw-r--r--tests/field_subclassing/tests.py2
-rw-r--r--tests/file_storage/tests.py2
-rw-r--r--tests/file_uploads/tests.py2
-rw-r--r--tests/file_uploads/urls.py2
-rw-r--r--tests/file_uploads/views.py2
-rw-r--r--tests/files/tests.py2
-rw-r--r--tests/fixtures/tests.py2
-rw-r--r--tests/fixtures_model_package/models/sql/book.sql2
-rw-r--r--tests/fixtures_model_package/sql/book.sql1
-rw-r--r--tests/fixtures_model_package/tests.py17
-rw-r--r--tests/fixtures_regress/models.py2
-rw-r--r--tests/fixtures_regress/tests.py41
-rw-r--r--tests/force_insert_update/tests.py2
-rw-r--r--tests/foreign_object/models.py34
-rw-r--r--tests/foreign_object/tests.py38
-rw-r--r--tests/forms_tests/models.py23
-rw-r--r--tests/forms_tests/tests/__init__.py2
-rw-r--r--tests/forms_tests/tests/test_error_messages.py2
-rw-r--r--tests/forms_tests/tests/test_extra.py33
-rw-r--r--tests/forms_tests/tests/test_forms.py82
-rw-r--r--tests/forms_tests/tests/test_widgets.py8
-rw-r--r--tests/forms_tests/tests/tests.py99
-rw-r--r--tests/generic_inline_admin/admin.py2
-rw-r--r--tests/generic_inline_admin/tests.py22
-rw-r--r--tests/generic_inline_admin/urls.py2
-rw-r--r--tests/generic_relations/tests.py2
-rw-r--r--tests/generic_views/test_base.py2
-rw-r--r--tests/generic_views/test_dates.py2
-rw-r--r--tests/generic_views/test_detail.py2
-rw-r--r--tests/generic_views/test_edit.py2
-rw-r--r--tests/generic_views/test_forms.py2
-rw-r--r--tests/generic_views/test_list.py2
-rw-r--r--tests/generic_views/urls.py2
-rw-r--r--tests/generic_views/views.py2
-rw-r--r--tests/get_earliest_or_latest/tests.py2
-rw-r--r--tests/get_object_or_404/tests.py4
-rw-r--r--tests/get_or_create/tests.py4
-rw-r--r--tests/get_or_create_regress/tests.py2
-rw-r--r--tests/httpwrappers/tests.py14
-rw-r--r--tests/i18n/forms.py2
-rw-r--r--tests/i18n/tests.py37
-rw-r--r--tests/inline_formsets/tests.py2
-rw-r--r--tests/introspection/tests.py2
-rw-r--r--tests/known_related_objects/tests.py2
-rw-r--r--tests/lookup/tests.py5
-rw-r--r--tests/m2m_and_m2o/tests.py2
-rw-r--r--tests/m2m_intermediary/tests.py2
-rw-r--r--tests/m2m_multiple/tests.py2
-rw-r--r--tests/m2m_recursive/tests.py2
-rw-r--r--tests/m2m_regress/tests.py2
-rw-r--r--tests/m2m_signals/tests.py2
-rw-r--r--tests/m2m_through/tests.py2
-rw-r--r--tests/m2m_through_regress/tests.py2
-rw-r--r--tests/m2o_recursive/tests.py2
-rw-r--r--tests/mail/tests.py28
-rw-r--r--tests/managers_regress/tests.py2
-rw-r--r--tests/many_to_many/tests.py2
-rw-r--r--tests/many_to_one/tests.py2
-rw-r--r--tests/many_to_one_null/tests.py2
-rw-r--r--tests/many_to_one_regress/tests.py2
-rw-r--r--tests/max_lengths/tests.py2
-rw-r--r--tests/middleware/tests.py2
-rw-r--r--tests/middleware_exceptions/urls.py3
-rw-r--r--tests/model_fields/test_imagefield.py2
-rw-r--r--tests/model_fields/tests.py197
-rw-r--r--tests/model_forms/models.py6
-rw-r--r--tests/model_forms/tests.py10
-rw-r--r--tests/model_forms_regress/tests.py2
-rw-r--r--tests/model_formsets/tests.py7
-rw-r--r--tests/model_formsets_regress/tests.py2
-rw-r--r--tests/model_inheritance/tests.py2
-rw-r--r--tests/model_inheritance_regress/tests.py2
-rw-r--r--tests/model_inheritance_same_model_name/models.py2
-rw-r--r--tests/model_inheritance_same_model_name/tests.py2
-rw-r--r--tests/model_inheritance_select_related/tests.py2
-rw-r--r--tests/model_package/models/__init__.py2
-rw-r--r--tests/model_package/tests.py2
-rw-r--r--tests/model_permalink/tests.py2
-rw-r--r--tests/model_regress/tests.py2
-rw-r--r--tests/modeladmin/tests.py12
-rw-r--r--tests/multiple_database/models.py2
-rw-r--r--tests/multiple_database/tests.py2
-rw-r--r--tests/mutually_referential/tests.py2
-rw-r--r--tests/nested_foreign_keys/tests.py3
-rw-r--r--tests/null_fk/tests.py2
-rw-r--r--tests/null_fk_ordering/tests.py2
-rw-r--r--tests/null_queries/tests.py2
-rw-r--r--tests/one_to_one/tests.py2
-rw-r--r--tests/one_to_one_regress/tests.py2
-rw-r--r--tests/or_lookups/tests.py2
-rw-r--r--tests/order_with_respect_to/tests.py2
-rw-r--r--tests/ordering/tests.py2
-rw-r--r--tests/pagination/tests.py2
-rw-r--r--tests/prefetch_related/tests.py2
-rw-r--r--tests/properties/tests.py2
-rw-r--r--tests/proxy_model_inheritance/app1/models.py2
-rw-r--r--tests/proxy_model_inheritance/tests.py2
-rw-r--r--tests/proxy_models/tests.py2
-rw-r--r--tests/queries/tests.py49
-rw-r--r--tests/queryset_pickle/models.py2
-rw-r--r--tests/queryset_pickle/tests.py8
-rw-r--r--tests/raw_query/tests.py2
-rw-r--r--tests/requests/tests.py16
-rw-r--r--tests/reserved_names/tests.py2
-rw-r--r--tests/reverse_lookup/tests.py2
-rw-r--r--tests/reverse_single_related/tests.py2
-rwxr-xr-xtests/runtests.py20
-rw-r--r--tests/save_delete_hooks/tests.py2
-rw-r--r--tests/select_for_update/tests.py16
-rw-r--r--tests/select_related/tests.py2
-rw-r--r--tests/select_related_onetoone/tests.py2
-rw-r--r--tests/select_related_regress/tests.py2
-rw-r--r--tests/serializers/tests.py4
-rw-r--r--tests/serializers_regress/tests.py2
-rw-r--r--tests/servers/tests.py2
-rw-r--r--tests/servers/urls.py2
-rw-r--r--tests/settings_tests/tests.py23
-rw-r--r--tests/signals/tests.py2
-rw-r--r--tests/signals_regress/tests.py2
-rw-r--r--tests/sites_framework/tests.py2
-rw-r--r--tests/staticfiles_tests/tests.py33
-rw-r--r--tests/str/tests.py2
-rw-r--r--tests/string_lookup/tests.py4
-rw-r--r--tests/swappable_models/tests.py2
-rw-r--r--tests/syndication/feeds.py2
-rw-r--r--tests/syndication/tests.py2
-rw-r--r--tests/syndication/urls.py2
-rw-r--r--tests/tablespaces/tests.py2
-rw-r--r--tests/template_tests/alternate_urls.py4
-rw-r--r--tests/template_tests/test_custom.py2
-rw-r--r--tests/template_tests/test_loaders.py (renamed from tests/template_tests/loaders.py)43
-rw-r--r--tests/template_tests/test_response.py2
-rw-r--r--tests/template_tests/tests.py16
-rw-r--r--tests/template_tests/urls.py2
-rw-r--r--tests/templates/custom_admin/app_index.html6
-rw-r--r--tests/test_client/tests.py2
-rw-r--r--tests/test_client/urls.py2
-rw-r--r--tests/test_client_regress/urls.py2
-rw-r--r--tests/test_runner/tests.py4
-rw-r--r--tests/test_utils/tests.py2
-rw-r--r--tests/test_utils/urls.py2
-rw-r--r--tests/test_utils/views.py4
-rw-r--r--tests/timezones/admin.py2
-rw-r--r--tests/timezones/urls.py2
-rw-r--r--tests/transactions/tests.py2
-rw-r--r--tests/transactions_regress/tests.py2
-rw-r--r--tests/unmanaged_models/tests.py2
-rw-r--r--tests/update/tests.py15
-rw-r--r--tests/update_only_fields/tests.py2
-rw-r--r--tests/urlpatterns_reverse/extra_urls.py2
-rw-r--r--tests/urlpatterns_reverse/included_named_urls.py2
-rw-r--r--tests/urlpatterns_reverse/included_named_urls2.py2
-rw-r--r--tests/urlpatterns_reverse/included_namespace_urls.py2
-rw-r--r--tests/urlpatterns_reverse/included_urls.py2
-rw-r--r--tests/urlpatterns_reverse/included_urls2.py2
-rw-r--r--tests/urlpatterns_reverse/middleware.py2
-rw-r--r--tests/urlpatterns_reverse/named_urls.py2
-rw-r--r--tests/urlpatterns_reverse/namespace_urls.py2
-rw-r--r--tests/urlpatterns_reverse/reverse_lazy_urls.py2
-rw-r--r--tests/urlpatterns_reverse/tests.py2
-rw-r--r--tests/urlpatterns_reverse/urlconf_outer.py4
-rw-r--r--tests/urlpatterns_reverse/urls.py2
-rw-r--r--tests/urlpatterns_reverse/urls_error_handlers_callables.py2
-rw-r--r--tests/urlpatterns_reverse/urls_without_full_import.py2
-rw-r--r--tests/utils_tests/test_html.py11
-rw-r--r--tests/utils_tests/test_module_loading.py2
-rw-r--r--tests/utils_tests/test_safestring.py3
-rw-r--r--tests/validation/test_custom_messages.py2
-rw-r--r--tests/validation/test_unique.py2
-rw-r--r--tests/validation/test_validators.py2
-rw-r--r--tests/validation/tests.py2
-rw-r--r--tests/view_tests/generic_urls.py2
-rw-r--r--tests/view_tests/templatetags/debugtags.py2
-rw-r--r--tests/view_tests/tests/__init__.py2
-rw-r--r--tests/view_tests/tests/test_debug.py2
-rw-r--r--tests/view_tests/tests/test_defaults.py22
-rw-r--r--tests/view_tests/tests/test_i18n.py38
-rw-r--r--tests/view_tests/tests/test_static.py2
-rw-r--r--tests/view_tests/urls.py6
-rw-r--r--tests/view_tests/views.py13
256 files changed, 1600 insertions, 539 deletions
diff --git a/tests/admin_changelist/admin.py b/tests/admin_changelist/admin.py
index 175b1972c9..a63f2b60ce 100644
--- a/tests/admin_changelist/admin.py
+++ b/tests/admin_changelist/admin.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from django.core.paginator import Paginator
@@ -107,3 +105,10 @@ class DynamicListFilterChildAdmin(admin.ModelAdmin):
my_list_filter.remove('parent')
return my_list_filter
+class DynamicSearchFieldsChildAdmin(admin.ModelAdmin):
+ search_fields = ('name',)
+
+ def get_search_fields(self, request):
+ search_fields = super(DynamicSearchFieldsChildAdmin, self).get_search_fields(request)
+ search_fields += ('age',)
+ return search_fields
diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py
index 7f3f0d162e..cb1ac5039f 100644
--- a/tests/admin_changelist/tests.py
+++ b/tests/admin_changelist/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
@@ -18,7 +18,8 @@ from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin,
GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin,
DynamicListDisplayLinksChildAdmin, CustomPaginationAdmin,
FilteredChildAdmin, CustomPaginator, site as custom_site,
- SwallowAdmin, DynamicListFilterChildAdmin, InvitationAdmin)
+ SwallowAdmin, DynamicListFilterChildAdmin, InvitationAdmin,
+ DynamicSearchFieldsChildAdmin)
from .models import (Event, Child, Parent, Genre, Band, Musician, Group,
Quartet, Membership, ChordsMusician, ChordsBand, Invitation, Swallow,
UnorderedObject, OrderedObject, CustomIdUser)
@@ -91,7 +92,7 @@ class ChangeListTests(TestCase):
context = Context({'cl': cl})
table_output = template.render(context)
link = reverse('admin:admin_changelist_child_change', args=(new_child.id,))
- row_html = '<tbody><tr class="row1"><th><a href="%s">name</a></th><td class="nowrap">(None)</td></tr></tbody>' % link
+ row_html = '<tbody><tr class="row1"><th class="field-name"><a href="%s">name</a></th><td class="field-parent nowrap">(None)</td></tr></tbody>' % link
self.assertFalse(table_output.find(row_html) == -1,
'Failed to find expected row element: %s' % table_output)
@@ -114,7 +115,7 @@ class ChangeListTests(TestCase):
context = Context({'cl': cl})
table_output = template.render(context)
link = reverse('admin:admin_changelist_child_change', args=(new_child.id,))
- row_html = '<tbody><tr class="row1"><th><a href="%s">name</a></th><td class="nowrap">Parent object</td></tr></tbody>' % link
+ row_html = '<tbody><tr class="row1"><th class="field-name"><a href="%s">name</a></th><td class="field-parent nowrap">Parent object</td></tr></tbody>' % link
self.assertFalse(table_output.find(row_html) == -1,
'Failed to find expected row element: %s' % table_output)
@@ -150,7 +151,7 @@ class ChangeListTests(TestCase):
# make sure that list editable fields are rendered in divs correctly
editable_name_field = '<input name="form-0-name" value="name" class="vTextField" maxlength="30" type="text" id="id_form-0-name" />'
- self.assertInHTML('<td>%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field')
+ self.assertInHTML('<td class="field-name">%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field')
def test_result_list_editable(self):
"""
@@ -588,6 +589,13 @@ class ChangeListTests(TestCase):
response = m.changelist_view(request)
self.assertEqual(response.context_data['cl'].list_filter, ('parent', 'name', 'age'))
+ def test_dynamic_search_fields(self):
+ child = self._create_superuser('child')
+ m = DynamicSearchFieldsChildAdmin(Child, admin.site)
+ request = self._mocked_authenticated_request('/child/', child)
+ response = m.changelist_view(request)
+ self.assertEqual(response.context_data['cl'].search_fields, ('name', 'age'))
+
def test_pagination_page_range(self):
"""
Regression tests for ticket #15653: ensure the number of pages
diff --git a/tests/admin_custom_urls/tests.py b/tests/admin_custom_urls/tests.py
index 31c93410f4..257638afb1 100644
--- a/tests/admin_custom_urls/tests.py
+++ b/tests/admin_custom_urls/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import warnings
from django.contrib.admin.util import quote
diff --git a/tests/admin_docs/urls.py b/tests/admin_docs/urls.py
index 3c3a8fe5d8..914b4836e0 100644
--- a/tests/admin_docs/urls.py
+++ b/tests/admin_docs/urls.py
@@ -1,6 +1,3 @@
-# coding: utf-8
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from . import views
diff --git a/tests/admin_filters/tests.py b/tests/admin_filters/tests.py
index f05e8e2011..5e6b122fec 100644
--- a/tests/admin_filters/tests.py
+++ b/tests/admin_filters/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py
index 62f9e04e5b..c69800851a 100644
--- a/tests/admin_inlines/admin.py
+++ b/tests/admin_inlines/admin.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from django import forms
diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py
index 465b224d4f..f62a0c1e01 100644
--- a/tests/admin_inlines/tests.py
+++ b/tests/admin_inlines/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.contrib.admin.helpers import InlineAdminForm
diff --git a/tests/admin_inlines/urls.py b/tests/admin_inlines/urls.py
index cf18ef97cf..a5d927e20b 100644
--- a/tests/admin_inlines/urls.py
+++ b/tests/admin_inlines/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, include
from . import admin
diff --git a/tests/admin_ordering/tests.py b/tests/admin_ordering/tests.py
index 6655ad37ad..763e97bd72 100644
--- a/tests/admin_ordering/tests.py
+++ b/tests/admin_ordering/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.test import TestCase, RequestFactory
from django.contrib import admin
diff --git a/tests/admin_registration/tests.py b/tests/admin_registration/tests.py
index 1b2d291691..0e444fd2af 100644
--- a/tests/admin_registration/tests.py
+++ b/tests/admin_registration/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
diff --git a/tests/admin_scripts/complex_app/admin/foo.py b/tests/admin_scripts/complex_app/admin/foo.py
index 1ed704a66b..09ceba05aa 100644
--- a/tests/admin_scripts/complex_app/admin/foo.py
+++ b/tests/admin_scripts/complex_app/admin/foo.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from ..models.foo import Foo
diff --git a/tests/admin_scripts/complex_app/models/bar.py b/tests/admin_scripts/complex_app/models/bar.py
index 15956f7a50..92f1b98694 100644
--- a/tests/admin_scripts/complex_app/models/bar.py
+++ b/tests/admin_scripts/complex_app/models/bar.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.db import models
from ..admin import foo
diff --git a/tests/admin_scripts/management/commands/color_command.py b/tests/admin_scripts/management/commands/color_command.py
new file mode 100644
index 0000000000..02da0a14ab
--- /dev/null
+++ b/tests/admin_scripts/management/commands/color_command.py
@@ -0,0 +1,9 @@
+from django.core.management.base import NoArgsCommand
+
+
+class Command(NoArgsCommand):
+ help = "Test color output"
+ requires_model_validation = False
+
+ def handle_noargs(self, **options):
+ return self.style.SQL_KEYWORD('BEGIN')
diff --git a/tests/admin_scripts/simple_app/models.py b/tests/admin_scripts/simple_app/models.py
index b89f4b898b..e5b9e297c5 100644
--- a/tests/admin_scripts/simple_app/models.py
+++ b/tests/admin_scripts/simple_app/models.py
@@ -1,3 +1 @@
-from __future__ import absolute_import
-
from ..complex_app.models.bar import Bar
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index 28f2dcb841..810c90c53e 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -18,7 +18,7 @@ import unittest
import django
from django import conf, get_version
from django.conf import settings
-from django.core.management import BaseCommand, CommandError
+from django.core.management import BaseCommand, CommandError, call_command
from django.db import connection
from django.test.runner import DiscoverRunner
from django.utils.encoding import force_text
@@ -45,6 +45,7 @@ class AdminScriptTestCase(unittest.TestCase):
settings_file_path = os.path.join(test_dir, filename)
with open(settings_file_path, 'w') as settings_file:
+ settings_file.write('# -*- coding: utf-8 -*\n')
settings_file.write('# Settings file automatically generated by admin_scripts test case\n')
exports = [
'DATABASES',
@@ -921,14 +922,21 @@ class ManageAlternateSettings(AdminScriptTestCase):
"alternate: manage.py can execute user commands if settings are provided as argument"
args = ['noargs_command', '--settings=alternate_settings']
out, err = self.run_manage(args)
- self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
self.assertNoOutput(err)
def test_custom_command_with_environment(self):
"alternate: manage.py can execute user commands if settings are provided in environment"
args = ['noargs_command']
out, err = self.run_manage(args, 'alternate_settings')
- self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertNoOutput(err)
+
+ def test_custom_command_output_color(self):
+ "alternate: manage.py output syntax color can be deactivated with the `--no-color` option"
+ args = ['noargs_command', '--no-color', '--settings=alternate_settings']
+ out, err = self.run_manage(args)
+ self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', True), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
self.assertNoOutput(err)
@@ -1271,40 +1279,47 @@ class CommandTypes(AdminScriptTestCase):
self.assertNoOutput(err)
self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s).")
+ def test_no_color(self):
+ "--no-color prevent colorization of the output"
+ out = StringIO()
+
+ call_command('color_command', no_color=True, stdout=out)
+ self.assertEqual(out.getvalue(), 'BEGIN\n')
+
def test_base_command(self):
"User BaseCommands can execute when a label is provided"
args = ['base_command', 'testlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_command_no_label(self):
"User BaseCommands can execute when no labels are provided"
args = ['base_command']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_command_multiple_label(self):
"User BaseCommands can execute when no labels are provided"
args = ['base_command', 'testlabel', 'anotherlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_command_with_option(self):
"User BaseCommands can execute with options when a label is provided"
args = ['base_command', 'testlabel', '--option_a=x']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_command_with_options(self):
"User BaseCommands can execute with multiple options when a label is provided"
args = ['base_command', 'testlabel', '-a', 'x', '--option_b=y']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_run_from_argv(self):
"""
@@ -1350,7 +1365,7 @@ class CommandTypes(AdminScriptTestCase):
args = ['noargs_command']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_noargs_with_args(self):
"NoArg Commands raise an error if an argument is provided"
@@ -1365,7 +1380,7 @@ class CommandTypes(AdminScriptTestCase):
self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
self.assertOutput(out, os.sep.join(['django', 'contrib', 'auth', 'models.py']))
- self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_app_command_no_apps(self):
"User AppCommands raise an error when no app name is provided"
@@ -1380,10 +1395,10 @@ class CommandTypes(AdminScriptTestCase):
self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
self.assertOutput(out, os.sep.join(['django', 'contrib', 'auth', 'models.py']))
- self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.contenttypes.models'")
self.assertOutput(out, os.sep.join(['django', 'contrib', 'contenttypes', 'models.py']))
- self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_app_command_invalid_appname(self):
"User AppCommands can execute when a single app name is provided"
@@ -1402,7 +1417,7 @@ class CommandTypes(AdminScriptTestCase):
args = ['label_command', 'testlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_label_command_no_label(self):
"User LabelCommands raise an error if no label is provided"
@@ -1415,8 +1430,8 @@ class CommandTypes(AdminScriptTestCase):
args = ['label_command', 'testlabel', 'anotherlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
- self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
class ArgumentOrder(AdminScriptTestCase):
"""Tests for 2-stage argument parsing scheme.
@@ -1440,35 +1455,35 @@ class ArgumentOrder(AdminScriptTestCase):
args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
def test_setting_then_short_option(self):
"Short options passed after settings are correctly handled"
args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
def test_option_then_setting(self):
"Options passed before settings are correctly handled"
args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
def test_short_option_then_setting(self):
"Short options passed before settings are correctly handled"
args = ['base_command', 'testlabel', '-a', 'x', '--settings=alternate_settings']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
def test_option_then_setting_then_option(self):
"Options are correctly handled when they are passed before and after a setting"
args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings', '--option_b=y']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
class StartProject(LiveServerTestCase, AdminScriptTestCase):
diff --git a/tests/admin_util/tests.py b/tests/admin_util/tests.py
index 637f643261..8c63e90ce1 100644
--- a/tests/admin_util/tests.py
+++ b/tests/admin_util/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import datetime
@@ -301,7 +301,7 @@ class UtilTests(SimpleTestCase):
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
'<label for="id_text" class="required inline"><i>text</i>:</label>')
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
- '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i>:</label>')
+ '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>')
# normal strings needs to be escaped
class MyForm(forms.Form):
@@ -312,7 +312,7 @@ class UtilTests(SimpleTestCase):
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
'<label for="id_text" class="required inline">&amp;text:</label>')
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
- '<label for="id_cb" class="vCheckboxLabel required inline">&amp;cb:</label>')
+ '<label for="id_cb" class="vCheckboxLabel required inline">&amp;cb</label>')
def test_flatten_fieldsets(self):
"""
diff --git a/tests/admin_validation/tests.py b/tests/admin_validation/tests.py
index 5eee3e7105..39e74a945c 100644
--- a/tests/admin_validation/tests.py
+++ b/tests/admin_validation/tests.py
@@ -1,9 +1,10 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django import forms
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
+from django.test.utils import str_prefix
from .models import Song, Book, Album, TwoAlbumFKAndAnE, State, City
@@ -185,7 +186,8 @@ class ValidationTestCase(TestCase):
readonly_fields = ("title", "nonexistant")
self.assertRaisesMessage(ImproperlyConfigured,
- "SongAdmin.readonly_fields[1], 'nonexistant' is not a callable or an attribute of 'SongAdmin' or found in the model 'Song'.",
+ str_prefix("SongAdmin.readonly_fields[1], %(_)s'nonexistant' is not a callable "
+ "or an attribute of 'SongAdmin' or found in the model 'Song'."),
SongAdmin.validate,
Song)
@@ -195,7 +197,8 @@ class ValidationTestCase(TestCase):
readonly_fields=['i_dont_exist'] # Missing attribute
self.assertRaisesMessage(ImproperlyConfigured,
- "CityInline.readonly_fields[0], 'i_dont_exist' is not a callable or an attribute of 'CityInline' or found in the model 'City'.",
+ str_prefix("CityInline.readonly_fields[0], %(_)s'i_dont_exist' is not a callable "
+ "or an attribute of 'CityInline' or found in the model 'City'."),
CityInline.validate,
City)
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 039abb819b..df8ced949e 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import tempfile
import os
diff --git a/tests/admin_views/customadmin.py b/tests/admin_views/customadmin.py
index c204b81edd..f964d6cffb 100644
--- a/tests/admin_views/customadmin.py
+++ b/tests/admin_views/customadmin.py
@@ -1,7 +1,7 @@
"""
A second, custom AdminSite -- see tests.CustomAdminSiteTests.
"""
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.conf.urls import patterns
from django.contrib import admin
@@ -13,6 +13,7 @@ from . import models, forms, admin as base_admin
class Admin2(admin.AdminSite):
+ app_index_template = 'custom_admin/app_index.html'
login_form = forms.CustomAdminAuthenticationForm
login_template = 'custom_admin/login.html'
logout_template = 'custom_admin/logout.html'
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index 5ec4fbb544..a1131210d7 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -644,8 +644,8 @@ class MainPrepopulated(models.Model):
max_length=20,
choices=(('option one', 'Option One'),
('option two', 'Option Two')))
- slug1 = models.SlugField()
- slug2 = models.SlugField()
+ slug1 = models.SlugField(blank=True)
+ slug2 = models.SlugField(blank=True)
class RelatedPrepopulated(models.Model):
parent = models.ForeignKey(MainPrepopulated)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 7decf6f471..3ee06751fb 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -1,5 +1,5 @@
# coding: utf-8
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import os
import re
@@ -806,6 +806,12 @@ class CustomModelAdminTest(AdminViewBasicTestCase):
self.assertTemplateUsed(response, 'custom_admin/index.html')
self.assertContains(response, 'Hello from a custom index template *bar*')
+ def testCustomAdminSiteAppIndexViewandTemplate(self):
+ response = self.client.get('/test_admin/admin2/admin_views/')
+ self.assertIsInstance(response, TemplateResponse)
+ self.assertTemplateUsed(response, 'custom_admin/app_index.html')
+ self.assertContains(response, 'Hello from a custom app_index template')
+
def testCustomAdminSitePasswordChangeTemplate(self):
response = self.client.get('/test_admin/admin2/password_change/')
self.assertIsInstance(response, TemplateResponse)
@@ -1496,7 +1502,7 @@ class AdminViewStringPrimaryKeyTest(TestCase):
response = self.client.get(prefix)
# this URL now comes through reverse(), thus url quoting and iri_to_uri encoding
pk_final_url = escape(iri_to_uri(urlquote(quote(self.pk))))
- should_contain = """<th><a href="%s%s/">%s</a></th>""" % (prefix, pk_final_url, escape(self.pk))
+ should_contain = """<th class="field-__str__"><a href="%s%s/">%s</a></th>""" % (prefix, pk_final_url, escape(self.pk))
self.assertContains(response, should_contain)
def test_recentactions_link(self):
@@ -1527,6 +1533,17 @@ class AdminViewStringPrimaryKeyTest(TestCase):
self.assertEqual(counted_presence_before - 1,
counted_presence_after)
+ def test_logentry_get_admin_url(self):
+ "LogEntry.get_admin_url returns a URL to edit the entry's object or None for non-existent (possibly deleted) models"
+ log_entry_name = "Model with string primary key" # capitalized in Recent Actions
+ logentry = LogEntry.objects.get(content_type__name__iexact=log_entry_name)
+ model = "modelwithstringprimarykey"
+ desired_admin_url = "/test_admin/admin/admin_views/%s/%s/" % (model, escape(iri_to_uri(urlquote(quote(self.pk)))))
+ self.assertEqual(logentry.get_admin_url(), desired_admin_url)
+
+ logentry.content_type.model = "non-existent"
+ self.assertEqual(logentry.get_admin_url(), None)
+
def test_deleteconfirmation_link(self):
"The link from the delete confirmation page referring back to the changeform of the object should be quoted"
response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk))
@@ -2151,8 +2168,8 @@ class AdminViewListEditable(TestCase):
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
self.assertContains(response, 'id="id_form-1-id"', 1)
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True)
- self.assertContains(response, '<td>%d</td>' % story1.id, 1)
- self.assertContains(response, '<td>%d</td>' % story2.id, 1)
+ self.assertContains(response, '<td class="field-id">%d</td>' % story1.id, 1)
+ self.assertContains(response, '<td class="field-id">%d</td>' % story2.id, 1)
def test_pk_hidden_fields_with_list_display_links(self):
""" Similarly as test_pk_hidden_fields, but when the hidden pk fields are
@@ -2167,8 +2184,8 @@ class AdminViewListEditable(TestCase):
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
self.assertContains(response, 'id="id_form-1-id"', 1)
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True)
- self.assertContains(response, '<th><a href="%s">%d</a></th>' % (link1, story1.id), 1)
- self.assertContains(response, '<th><a href="%s">%d</a></th>' % (link2, story2.id), 1)
+ self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link1, story1.id), 1)
+ self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link2, story2.id), 1)
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
@@ -3438,6 +3455,50 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
slug2='option-one-tabular-inline-ignored-characters',
)
+ def test_populate_existing_object(self):
+ """
+ Ensure that the prepopulation works for existing objects too, as long
+ as the original field is empty.
+ Refs #19082.
+ """
+ # Slugs are empty to start with.
+ item = MainPrepopulated.objects.create(
+ name=' this is the mAin nÀMë',
+ pubdate='2012-02-18',
+ status='option two',
+ slug1='',
+ slug2='',
+ )
+ self.admin_login(username='super',
+ password='secret',
+ login_url='/test_admin/admin/')
+
+ object_url = '%s%s' % (
+ self.live_server_url,
+ '/test_admin/admin/admin_views/mainprepopulated/{}/'.format(item.id))
+
+ self.selenium.get(object_url)
+ self.selenium.find_element_by_css_selector('#id_name').send_keys(' the best')
+
+ # The slugs got prepopulated since they were originally empty
+ slug1 = self.selenium.find_element_by_css_selector('#id_slug1').get_attribute('value')
+ slug2 = self.selenium.find_element_by_css_selector('#id_slug2').get_attribute('value')
+ self.assertEqual(slug1, 'main-name-best-2012-02-18')
+ self.assertEqual(slug2, 'option-two-main-name-best')
+
+ # Save the object
+ self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
+ self.wait_page_loaded()
+
+ self.selenium.get(object_url)
+ self.selenium.find_element_by_css_selector('#id_name').send_keys(' hello')
+
+ # The slugs got prepopulated didn't change since they were originally not empty
+ slug1 = self.selenium.find_element_by_css_selector('#id_slug1').get_attribute('value')
+ slug2 = self.selenium.find_element_by_css_selector('#id_slug2').get_attribute('value')
+ self.assertEqual(slug1, 'main-name-best-2012-02-18')
+ self.assertEqual(slug2, 'option-two-main-name-best')
+
def test_collapsible_fieldset(self):
"""
Test that the 'collapse' class in fieldsets definition allows to
@@ -3877,6 +3938,22 @@ class CSSTest(TestCase):
self.assertContains(response,
'<body class="app-admin_views model-section ')
+ def test_changelist_field_classes(self):
+ """
+ Cells of the change list table should contain the field name in their class attribute
+ Refs #11195.
+ """
+ Podcast.objects.create(name="Django Dose",
+ release_date=datetime.date.today())
+ response = self.client.get('/test_admin/admin/admin_views/podcast/')
+ self.assertContains(
+ response, '<th class="field-name">')
+ self.assertContains(
+ response, '<td class="field-release_date nowrap">')
+ self.assertContains(
+ response, '<td class="action-checkbox">')
+
+
try:
import docutils
except ImportError:
diff --git a/tests/admin_views/urls.py b/tests/admin_views/urls.py
index 763c83a450..d934173234 100644
--- a/tests/admin_views/urls.py
+++ b/tests/admin_views/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, include
from . import views, customadmin, admin
diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py
index ae19d58cc4..cb97242e03 100644
--- a/tests/admin_widgets/models.py
+++ b/tests/admin_widgets/models.py
@@ -13,6 +13,7 @@ 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')])
+ email = models.EmailField(blank=True)
def __str__(self):
return self.name
@@ -55,7 +56,8 @@ class Inventory(models.Model):
return self.name
class Event(models.Model):
- band = models.ForeignKey(Band, limit_choices_to=models.Q(pk__gt=0))
+ main_band = models.ForeignKey(Band, limit_choices_to=models.Q(pk__gt=0), related_name='events_main_band_at')
+ supporting_bands = models.ManyToManyField(Band, null=True, blank=True, related_name='events_supporting_band_at')
start_date = models.DateField(blank=True, null=True)
start_time = models.TimeField(blank=True, null=True)
description = models.TextField(blank=True)
diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py
index 870aa6d455..5a88df1e57 100644
--- a/tests/admin_widgets/tests.py
+++ b/tests/admin_widgets/tests.py
@@ -1,5 +1,5 @@
# encoding: utf-8
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import datetime, timedelta
from unittest import TestCase
@@ -83,19 +83,22 @@ class AdminFormfieldForDBFieldTests(TestCase):
def testCharField(self):
self.assertFormfield(models.Member, 'name', widgets.AdminTextInputWidget)
+ def testEmailField(self):
+ self.assertFormfield(models.Member, 'email', widgets.AdminEmailInputWidget)
+
def testFileField(self):
self.assertFormfield(models.Album, 'cover_art', widgets.AdminFileWidget)
def testForeignKey(self):
- self.assertFormfield(models.Event, 'band', forms.Select)
+ self.assertFormfield(models.Event, 'main_band', forms.Select)
def testRawIDForeignKey(self):
- self.assertFormfield(models.Event, 'band', widgets.ForeignKeyRawIdWidget,
- raw_id_fields=['band'])
+ self.assertFormfield(models.Event, 'main_band', widgets.ForeignKeyRawIdWidget,
+ raw_id_fields=['main_band'])
def testRadioFieldsForeignKey(self):
- ff = self.assertFormfield(models.Event, 'band', widgets.AdminRadioSelect,
- radio_fields={'band':admin.VERTICAL})
+ ff = self.assertFormfield(models.Event, 'main_band', widgets.AdminRadioSelect,
+ radio_fields={'main_band':admin.VERTICAL})
self.assertEqual(ff.empty_label, None)
def testManyToMany(self):
@@ -198,7 +201,7 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
pk = band.pk
band.delete()
post_data = {
- "band": '%s' % pk,
+ "main_band": '%s' % pk,
}
# Try posting with a non-existent pk in a raw id field: this
# should result in an error message, not a server exception.
@@ -212,7 +215,7 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
for test_str in ('Iñtërnâtiônàlizætiøn', "1234'", -1234):
# This should result in an error message, not a server exception.
response = self.client.post('%s/admin_widgets/event/add/' % self.admin_root,
- {"band": test_str})
+ {"main_band": test_str})
self.assertContains(response,
'Select a valid choice. That choice is not one of the available choices.')
@@ -223,6 +226,13 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
self.assertEqual(lookup1, {'color__in': 'red,blue'})
self.assertEqual(lookup1, lookup2)
+ def test_url_params_from_lookup_dict_callable(self):
+ def my_callable():
+ return 'works'
+ lookup1 = widgets.url_params_from_lookup_dict({'myfield': my_callable})
+ lookup2 = widgets.url_params_from_lookup_dict({'myfield': my_callable()})
+ self.assertEqual(lookup1, lookup2)
+
class FilteredSelectMultipleWidgetTest(DjangoTestCase):
def test_render(self):
@@ -300,29 +310,29 @@ class AdminURLWidgetTest(DjangoTestCase):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', '')),
- '<input class="vURLField" name="test" type="text" />'
+ '<input class="vURLField" name="test" type="url" />'
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com')),
- '<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /></p>'
+ '<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com" /></p>'
)
def test_render_idn(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-äüö.com')),
- '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com" /></p>'
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com" /></p>'
)
def test_render_quoting(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com/<sometag>some text</sometag>')),
- '<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some text</sometag>" /></p>'
+ '<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com/<sometag>some text</sometag>" /></p>'
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>')),
- '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
)
@@ -816,3 +826,100 @@ class HorizontalVerticalFilterSeleniumChromeTests(HorizontalVerticalFilterSeleni
class HorizontalVerticalFilterSeleniumIETests(HorizontalVerticalFilterSeleniumFirefoxTests):
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
+
+
+@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
+class AdminRawIdWidgetSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
+ available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
+ fixtures = ['admin-widgets-users.xml']
+ urls = "admin_widgets.urls"
+ webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
+
+ def setUp(self):
+ models.Band.objects.create(id=42, name='Bogey Blues')
+ models.Band.objects.create(id=98, name='Green Potatoes')
+ super(AdminRawIdWidgetSeleniumFirefoxTests, self).setUp()
+
+ def test_foreignkey(self):
+ self.admin_login(username='super', password='secret', login_url='/')
+ self.selenium.get(
+ '%s%s' % (self.live_server_url, '/admin_widgets/event/add/'))
+ main_window = self.selenium.current_window_handle
+
+ # No value has been selected yet
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
+ '')
+
+ # Open the popup window and click on a band
+ self.selenium.find_element_by_id('lookup_id_main_band').click()
+ self.selenium.switch_to_window('id_main_band')
+ self.wait_page_loaded()
+ link = self.selenium.find_element_by_link_text('Bogey Blues')
+ self.assertTrue('/band/42/' in link.get_attribute('href'))
+ link.click()
+
+ # The field now contains the selected band's id
+ self.selenium.switch_to_window(main_window)
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
+ '42')
+
+ # Reopen the popup window and click on another band
+ self.selenium.find_element_by_id('lookup_id_main_band').click()
+ self.selenium.switch_to_window('id_main_band')
+ self.wait_page_loaded()
+ link = self.selenium.find_element_by_link_text('Green Potatoes')
+ self.assertTrue('/band/98/' in link.get_attribute('href'))
+ link.click()
+
+ # The field now contains the other selected band's id
+ self.selenium.switch_to_window(main_window)
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
+ '98')
+
+ def test_many_to_many(self):
+ self.admin_login(username='super', password='secret', login_url='/')
+ self.selenium.get(
+ '%s%s' % (self.live_server_url, '/admin_widgets/event/add/'))
+ main_window = self.selenium.current_window_handle
+
+ # No value has been selected yet
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
+ '')
+
+ # Open the popup window and click on a band
+ self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
+ self.selenium.switch_to_window('id_supporting_bands')
+ self.wait_page_loaded()
+ link = self.selenium.find_element_by_link_text('Bogey Blues')
+ self.assertTrue('/band/42/' in link.get_attribute('href'))
+ link.click()
+
+ # The field now contains the selected band's id
+ self.selenium.switch_to_window(main_window)
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
+ '42')
+
+ # Reopen the popup window and click on another band
+ self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
+ self.selenium.switch_to_window('id_supporting_bands')
+ self.wait_page_loaded()
+ link = self.selenium.find_element_by_link_text('Green Potatoes')
+ self.assertTrue('/band/98/' in link.get_attribute('href'))
+ link.click()
+
+ # The field now contains the two selected bands' ids
+ self.selenium.switch_to_window(main_window)
+ self.assertEqual(
+ self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
+ '42,98')
+
+class AdminRawIdWidgetSeleniumChromeTests(AdminRawIdWidgetSeleniumFirefoxTests):
+ webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
+
+class AdminRawIdWidgetSeleniumIETests(AdminRawIdWidgetSeleniumFirefoxTests):
+ webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
diff --git a/tests/admin_widgets/urls.py b/tests/admin_widgets/urls.py
index aecee90b7f..3da5d25bc8 100644
--- a/tests/admin_widgets/urls.py
+++ b/tests/admin_widgets/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, include
from . import widgetadmin
diff --git a/tests/admin_widgets/widgetadmin.py b/tests/admin_widgets/widgetadmin.py
index 1cdeeb9f67..4894f92afb 100644
--- a/tests/admin_widgets/widgetadmin.py
+++ b/tests/admin_widgets/widgetadmin.py
@@ -1,8 +1,3 @@
-"""
-
-"""
-from __future__ import absolute_import
-
from django.contrib import admin
from . import models
@@ -23,7 +18,7 @@ class CarTireAdmin(admin.ModelAdmin):
return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
class EventAdmin(admin.ModelAdmin):
- raw_id_fields = ['band']
+ raw_id_fields = ['main_band', 'supporting_bands']
class SchoolAdmin(admin.ModelAdmin):
@@ -47,4 +42,4 @@ site.register(models.Bee)
site.register(models.Advisor)
-site.register(models.School, SchoolAdmin) \ No newline at end of file
+site.register(models.School, SchoolAdmin)
diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py
index c635e6ebb6..4d46cae766 100644
--- a/tests/aggregation/tests.py
+++ b/tests/aggregation/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
from decimal import Decimal
@@ -585,3 +585,35 @@ class BaseAggregateTestCase(TestCase):
"datetime.date(2008, 1, 1)"
]
)
+
+ def test_values_aggregation(self):
+ # Refs #20782
+ max_rating = Book.objects.values('rating').aggregate(max_rating=Max('rating'))
+ self.assertEqual(max_rating['max_rating'], 5)
+ max_books_per_rating = Book.objects.values('rating').annotate(
+ books_per_rating=Count('id')
+ ).aggregate(Max('books_per_rating'))
+ self.assertEqual(
+ max_books_per_rating,
+ {'books_per_rating__max': 3})
+
+ def test_ticket17424(self):
+ """
+ Check that doing exclude() on a foreign model after annotate()
+ doesn't crash.
+ """
+ all_books = list(Book.objects.values_list('pk', flat=True).order_by('pk'))
+ annotated_books = Book.objects.order_by('pk').annotate(one=Count("id"))
+
+ # The value doesn't matter, we just need any negative
+ # constraint on a related model that's a noop.
+ excluded_books = annotated_books.exclude(publisher__name="__UNLIKELY_VALUE__")
+
+ # Try to generate query tree
+ str(excluded_books.query)
+
+ self.assertQuerysetEqual(excluded_books, all_books, lambda x: x.pk)
+
+ # Check internal state
+ self.assertIsNone(annotated_books.query.alias_map["aggregation_book"].join_type)
+ self.assertIsNone(excluded_books.query.alias_map["aggregation_book"].join_type)
diff --git a/tests/aggregation_regress/tests.py b/tests/aggregation_regress/tests.py
index 35ac57d9be..8388e78dbe 100644
--- a/tests/aggregation_regress/tests.py
+++ b/tests/aggregation_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import pickle
@@ -250,6 +250,13 @@ class AggregationTests(TestCase):
'price__max': Decimal("82.80")
})
+ # Regression for #15624 - Missing SELECT columns when using values, annotate
+ # and aggregate in a single query
+ self.assertEqual(
+ Book.objects.annotate(c=Count('authors')).values('c').aggregate(Max('c')),
+ {'c__max': 3}
+ )
+
def test_field_error(self):
# Bad field requests in aggregates are caught and reported
self.assertRaises(
diff --git a/tests/app_loading/tests.py b/tests/app_loading/tests.py
index e0c7cbd78c..dc25899646 100644
--- a/tests/app_loading/tests.py
+++ b/tests/app_loading/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import copy
import os
@@ -7,7 +7,8 @@ import time
from unittest import TestCase
from django.conf import Settings
-from django.db.models.loading import cache, load_app, get_model, get_models
+from django.db.models.loading import cache, load_app, get_model, get_models, AppCache
+from django.test.utils import override_settings
from django.utils._os import upath
@@ -61,12 +62,33 @@ class EggLoadingTest(TestCase):
egg_name = '%s/brokenapp.egg' % self.egg_dir
sys.path.append(egg_name)
self.assertRaises(ImportError, load_app, 'broken_app')
+ raised = None
try:
load_app('broken_app')
except ImportError as e:
- # Make sure the message is indicating the actual
- # problem in the broken app.
- self.assertTrue("modelz" in e.args[0])
+ raised = e
+
+ # Make sure the message is indicating the actual
+ # problem in the broken app.
+ self.assertTrue(raised is not None)
+ self.assertTrue("modelz" in raised.args[0])
+
+ def test_missing_app(self):
+ """
+ Test that repeated app loading doesn't succeed in case there is an
+ error. Refs #17667.
+ """
+ # AppCache is a Borg, so we can instantiate one and change its
+ # loaded to False to force the following code to actually try to
+ # populate the cache.
+ a = AppCache()
+ a.loaded = False
+ try:
+ with override_settings(INSTALLED_APPS=('notexists',)):
+ self.assertRaises(ImportError, get_model, 'notexists', 'nomodel', seed_cache=True)
+ self.assertRaises(ImportError, get_model, 'notexists', 'nomodel', seed_cache=True)
+ finally:
+ a.loaded = True
class GetModelsTest(TestCase):
diff --git a/tests/backends/models.py b/tests/backends/models.py
index 4f03ddeacc..1508af4354 100644
--- a/tests/backends/models.py
+++ b/tests/backends/models.py
@@ -68,11 +68,18 @@ class Reporter(models.Model):
return "%s %s" % (self.first_name, self.last_name)
+class ReporterProxy(Reporter):
+ class Meta:
+ proxy = True
+
+
@python_2_unicode_compatible
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
+ reporter_proxy = models.ForeignKey(ReporterProxy, null=True,
+ related_name='reporter_proxy')
def __str__(self):
return self.headline
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index ec592f0188..d6e3f5c78e 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Unit and doctests for specific database backends.
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
from decimal import Decimal
@@ -614,12 +614,19 @@ class FkConstraintsTests(TransactionTestCase):
Try to create a model instance that violates a FK constraint. If it
fails it should fail with IntegrityError.
"""
- a = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
+ a1 = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
try:
- a.save()
+ a1.save()
except IntegrityError:
- return
- self.skipTest("This backend does not support integrity checks.")
+ pass
+ else:
+ self.skipTest("This backend does not support integrity checks.")
+ # Now that we know this backend supports integrity checks we make sure
+ # constraints are also enforced for proxy models. Refs #17519
+ a2 = models.Article(headline='This is another test', reporter=self.r,
+ pub_date=datetime.datetime(2012, 8, 3),
+ reporter_proxy_id=30)
+ self.assertRaises(IntegrityError, a2.save)
def test_integrity_checks_on_update(self):
"""
@@ -628,14 +635,26 @@ class FkConstraintsTests(TransactionTestCase):
"""
# Create an Article.
models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
- # Retrive it from the DB
- a = models.Article.objects.get(headline="Test article")
- a.reporter_id = 30
+ # Retrieve it from the DB
+ a1 = models.Article.objects.get(headline="Test article")
+ a1.reporter_id = 30
try:
- a.save()
+ a1.save()
except IntegrityError:
- return
- self.skipTest("This backend does not support integrity checks.")
+ pass
+ else:
+ self.skipTest("This backend does not support integrity checks.")
+ # Now that we know this backend supports integrity checks we make sure
+ # constraints are also enforced for proxy models. Refs #17519
+ # Create another article
+ r_proxy = models.ReporterProxy.objects.get(pk=self.r.pk)
+ models.Article.objects.create(headline='Another article',
+ pub_date=datetime.datetime(1988, 5, 15),
+ reporter=self.r, reporter_proxy=r_proxy)
+ # Retreive the second article from the DB
+ a2 = models.Article.objects.get(headline='Another article')
+ a2.reporter_proxy_id = 30
+ self.assertRaises(IntegrityError, a2.save)
def test_disable_constraint_checks_manually(self):
"""
diff --git a/tests/basic/tests.py b/tests/basic/tests.py
index fb21b11279..55ed6a436f 100644
--- a/tests/basic/tests.py
+++ b/tests/basic/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import datetime
import threading
@@ -6,6 +6,7 @@ import threading
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db import connections, DEFAULT_DB_ALIAS
from django.db.models.fields import Field, FieldDoesNotExist
+from django.db.models.manager import BaseManager
from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet, MAX_GET_RESULTS
from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import six
@@ -734,3 +735,59 @@ class ConcurrentSaveTests(TransactionTestCase):
t.join()
a.save()
self.assertEqual(Article.objects.get(pk=a.pk).headline, 'foo')
+
+
+class ManagerTest(TestCase):
+ QUERYSET_PROXY_METHODS = [
+ 'none',
+ 'count',
+ 'dates',
+ 'datetimes',
+ 'distinct',
+ 'extra',
+ 'get',
+ 'get_or_create',
+ 'update_or_create',
+ 'create',
+ 'bulk_create',
+ 'filter',
+ 'aggregate',
+ 'annotate',
+ 'complex_filter',
+ 'exclude',
+ 'in_bulk',
+ 'iterator',
+ 'earliest',
+ 'latest',
+ 'first',
+ 'last',
+ 'order_by',
+ 'select_for_update',
+ 'select_related',
+ 'prefetch_related',
+ 'values',
+ 'values_list',
+ 'update',
+ 'reverse',
+ 'defer',
+ 'only',
+ 'using',
+ 'exists',
+ '_insert',
+ '_update',
+ 'raw',
+ ]
+
+ def test_manager_methods(self):
+ """
+ This test ensures that the correct set of methods from `QuerySet`
+ are copied onto `Manager`.
+
+ It's particularly useful to prevent accidentally leaking new methods
+ into `Manager`. New `QuerySet` methods that should also be copied onto
+ `Manager` will need to be added to `ManagerTest.QUERYSET_PROXY_METHODS`.
+ """
+ self.assertEqual(
+ sorted(BaseManager._get_queryset_methods(QuerySet).keys()),
+ sorted(self.QUERYSET_PROXY_METHODS),
+ )
diff --git a/tests/bug639/tests.py b/tests/bug639/tests.py
index 71c50e14aa..769d27d2f0 100644
--- a/tests/bug639/tests.py
+++ b/tests/bug639/tests.py
@@ -4,8 +4,6 @@ gets called *again* for each FileField. This test will fail if calling a
ModelForm's save() method causes Model.save() to be called more than once.
"""
-from __future__ import absolute_import
-
import os
import shutil
import unittest
diff --git a/tests/bug8245/admin.py b/tests/bug8245/admin.py
index d821190763..e7d1a080c2 100644
--- a/tests/bug8245/admin.py
+++ b/tests/bug8245/admin.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from .models import Story
diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py
index d4772934a1..94258ca711 100644
--- a/tests/bulk_create/tests.py
+++ b/tests/bulk_create/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index 5cf199794c..287a078617 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -2,7 +2,7 @@
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import hashlib
import os
diff --git a/tests/choices/tests.py b/tests/choices/tests.py
index 03a7d3340d..2d612626c2 100644
--- a/tests/choices/tests.py
+++ b/tests/choices/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.test import TestCase
from .models import Person
diff --git a/tests/comment_tests/tests/__init__.py b/tests/comment_tests/tests/__init__.py
index ae4585e187..6cbddbe82b 100644
--- a/tests/comment_tests/tests/__init__.py
+++ b/tests/comment_tests/tests/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib.auth.models import User
from django.contrib.comments.forms import CommentForm
from django.contrib.comments.models import Comment
diff --git a/tests/comment_tests/tests/test_app_api.py b/tests/comment_tests/tests/test_app_api.py
index ed23ba39cc..83ee868a02 100644
--- a/tests/comment_tests/tests/test_app_api.py
+++ b/tests/comment_tests/tests/test_app_api.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf import settings
from django.contrib import comments
from django.contrib.comments.models import Comment
diff --git a/tests/comment_tests/tests/test_comment_form.py b/tests/comment_tests/tests/test_comment_form.py
index a30f13a073..bca339fd3d 100644
--- a/tests/comment_tests/tests/test_comment_form.py
+++ b/tests/comment_tests/tests/test_comment_form.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
import time
from django.conf import settings
diff --git a/tests/comment_tests/tests/test_comment_utils_moderators.py b/tests/comment_tests/tests/test_comment_utils_moderators.py
index 6c7a882e25..e61be48d8b 100644
--- a/tests/comment_tests/tests/test_comment_utils_moderators.py
+++ b/tests/comment_tests/tests/test_comment_utils_moderators.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib.comments.models import Comment
from django.contrib.comments.moderation import (moderator, CommentModerator,
AlreadyModerated)
diff --git a/tests/comment_tests/tests/test_comment_view.py b/tests/comment_tests/tests/test_comment_view.py
index 0d994d3af8..19d7c1d16b 100644
--- a/tests/comment_tests/tests/test_comment_view.py
+++ b/tests/comment_tests/tests/test_comment_view.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import re
diff --git a/tests/comment_tests/tests/test_feeds.py b/tests/comment_tests/tests/test_feeds.py
index 941ffb6bf2..e6652afa28 100644
--- a/tests/comment_tests/tests/test_feeds.py
+++ b/tests/comment_tests/tests/test_feeds.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from xml.etree import ElementTree as ET
from django.conf import settings
diff --git a/tests/comment_tests/tests/test_models.py b/tests/comment_tests/tests/test_models.py
index 69c1a8118f..4303fda852 100644
--- a/tests/comment_tests/tests/test_models.py
+++ b/tests/comment_tests/tests/test_models.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib.comments.models import Comment
from . import CommentTestCase
diff --git a/tests/comment_tests/tests/test_moderation_views.py b/tests/comment_tests/tests/test_moderation_views.py
index 02af35cfe4..9f826f5866 100644
--- a/tests/comment_tests/tests/test_moderation_views.py
+++ b/tests/comment_tests/tests/test_moderation_views.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.auth.models import User, Permission
from django.contrib.comments import signals
diff --git a/tests/comment_tests/tests/test_templatetags.py b/tests/comment_tests/tests/test_templatetags.py
index 1971c21a58..d24859eb55 100644
--- a/tests/comment_tests/tests/test_templatetags.py
+++ b/tests/comment_tests/tests/test_templatetags.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib.comments.forms import CommentForm
from django.contrib.comments.models import Comment
from django.contrib.contenttypes.models import ContentType
diff --git a/tests/comment_tests/urls.py b/tests/comment_tests/urls.py
index 0a7e8b5fdf..32106106b5 100644
--- a/tests/comment_tests/urls.py
+++ b/tests/comment_tests/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from django.contrib.comments.feeds import LatestCommentFeed
diff --git a/tests/conditional_processing/views.py b/tests/conditional_processing/views.py
index 14a5a83a45..d4dc4b8cf6 100644
--- a/tests/conditional_processing/views.py
+++ b/tests/conditional_processing/views.py
@@ -1,6 +1,3 @@
-# -*- coding:utf-8 -*-
-from __future__ import absolute_import
-
from django.views.decorators.http import condition, etag, last_modified
from django.http import HttpResponse
diff --git a/tests/contenttypes_tests/models.py b/tests/contenttypes_tests/models.py
index 3c6685687a..5d21ad5b96 100644
--- a/tests/contenttypes_tests/models.py
+++ b/tests/contenttypes_tests/models.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py
index b39e118ec6..63f02697df 100644
--- a/tests/contenttypes_tests/tests.py
+++ b/tests/contenttypes_tests/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
diff --git a/tests/contenttypes_tests/urls.py b/tests/contenttypes_tests/urls.py
index 2cfc90b024..626b3ae8f7 100644
--- a/tests/contenttypes_tests/urls.py
+++ b/tests/contenttypes_tests/urls.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf.urls import patterns
diff --git a/tests/context_processors/urls.py b/tests/context_processors/urls.py
index 757017c9ca..9340cdfc38 100644
--- a/tests/context_processors/urls.py
+++ b/tests/context_processors/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from . import views
diff --git a/tests/custom_columns/tests.py b/tests/custom_columns/tests.py
index 51028b0c46..155279297f 100644
--- a/tests/custom_columns/tests.py
+++ b/tests/custom_columns/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import FieldError
from django.test import TestCase
diff --git a/tests/custom_columns_regress/tests.py b/tests/custom_columns_regress/tests.py
index 7cc66ca2a6..034de08d45 100644
--- a/tests/custom_columns_regress/tests.py
+++ b/tests/custom_columns_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import FieldError
from django.test import TestCase
diff --git a/tests/custom_managers/models.py b/tests/custom_managers/models.py
index 2f5e62fc7a..44d5eb70da 100644
--- a/tests/custom_managers/models.py
+++ b/tests/custom_managers/models.py
@@ -20,6 +20,49 @@ class PersonManager(models.Manager):
def get_fun_people(self):
return self.filter(fun=True)
+# An example of a custom manager that sets get_queryset().
+
+class PublishedBookManager(models.Manager):
+ def get_queryset(self):
+ return super(PublishedBookManager, self).get_queryset().filter(is_published=True)
+
+# An example of a custom queryset that copies its methods onto the manager.
+
+class CustomQuerySet(models.QuerySet):
+ def filter(self, *args, **kwargs):
+ queryset = super(CustomQuerySet, self).filter(fun=True)
+ queryset._filter_CustomQuerySet = True
+ return queryset
+
+ def public_method(self, *args, **kwargs):
+ return self.all()
+
+ def _private_method(self, *args, **kwargs):
+ return self.all()
+
+ def optout_public_method(self, *args, **kwargs):
+ return self.all()
+ optout_public_method.queryset_only = True
+
+ def _optin_private_method(self, *args, **kwargs):
+ return self.all()
+ _optin_private_method.queryset_only = False
+
+class BaseCustomManager(models.Manager):
+ def __init__(self, arg):
+ super(BaseCustomManager, self).__init__()
+ self.init_arg = arg
+
+ def filter(self, *args, **kwargs):
+ queryset = super(BaseCustomManager, self).filter(fun=True)
+ queryset._filter_CustomManager = True
+ return queryset
+
+ def manager_only(self):
+ return self.all()
+
+CustomManager = BaseCustomManager.from_queryset(CustomQuerySet)
+
@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=30)
@@ -27,15 +70,12 @@ class Person(models.Model):
fun = models.BooleanField()
objects = PersonManager()
+ custom_queryset_default_manager = CustomQuerySet.as_manager()
+ custom_queryset_custom_manager = CustomManager('hello')
+
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
-# An example of a custom manager that sets get_queryset().
-
-class PublishedBookManager(models.Manager):
- def get_queryset(self):
- return super(PublishedBookManager, self).get_queryset().filter(is_published=True)
-
@python_2_unicode_compatible
class Book(models.Model):
title = models.CharField(max_length=50)
diff --git a/tests/custom_managers/tests.py b/tests/custom_managers/tests.py
index 4fe79fe3fb..87e5a721bc 100644
--- a/tests/custom_managers/tests.py
+++ b/tests/custom_managers/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
@@ -11,12 +11,54 @@ class CustomManagerTests(TestCase):
p1 = Person.objects.create(first_name="Bugs", last_name="Bunny", fun=True)
p2 = Person.objects.create(first_name="Droopy", last_name="Dog", fun=False)
+ # Test a custom `Manager` method.
self.assertQuerysetEqual(
Person.objects.get_fun_people(), [
"Bugs Bunny"
],
six.text_type
)
+
+ # Test that the methods of a custom `QuerySet` are properly
+ # copied onto the default `Manager`.
+ for manager in ['custom_queryset_default_manager',
+ 'custom_queryset_custom_manager']:
+ manager = getattr(Person, manager)
+
+ # Copy public methods.
+ manager.public_method()
+ # Don't copy private methods.
+ with self.assertRaises(AttributeError):
+ manager._private_method()
+ # Copy methods with `manager=True` even if they are private.
+ manager._optin_private_method()
+ # Don't copy methods with `manager=False` even if they are public.
+ with self.assertRaises(AttributeError):
+ manager.optout_public_method()
+
+ # Test that the overridden method is called.
+ queryset = manager.filter()
+ self.assertQuerysetEqual(queryset, ["Bugs Bunny"], six.text_type)
+ self.assertEqual(queryset._filter_CustomQuerySet, True)
+
+ # Test that specialized querysets inherit from our custom queryset.
+ queryset = manager.values_list('first_name', flat=True).filter()
+ self.assertEqual(list(queryset), [six.text_type("Bugs")])
+ self.assertEqual(queryset._filter_CustomQuerySet, True)
+
+ # Test that the custom manager `__init__()` argument has been set.
+ self.assertEqual(Person.custom_queryset_custom_manager.init_arg, 'hello')
+
+ # Test that the custom manager method is only available on the manager.
+ Person.custom_queryset_custom_manager.manager_only()
+ with self.assertRaises(AttributeError):
+ Person.custom_queryset_custom_manager.all().manager_only()
+
+ # Test that the queryset method doesn't override the custom manager method.
+ queryset = Person.custom_queryset_custom_manager.filter()
+ self.assertQuerysetEqual(queryset, ["Bugs Bunny"], six.text_type)
+ self.assertEqual(queryset._filter_CustomManager, True)
+
# The RelatedManager used on the 'books' descriptor extends the default
# manager
self.assertIsInstance(p2.books, PublishedBookManager)
diff --git a/tests/custom_managers_regress/tests.py b/tests/custom_managers_regress/tests.py
index 5a9cd91d59..8462e526c9 100644
--- a/tests/custom_managers_regress/tests.py
+++ b/tests/custom_managers_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/custom_methods/tests.py b/tests/custom_methods/tests.py
index 9d7444ba62..addb61d4c1 100644
--- a/tests/custom_methods/tests.py
+++ b/tests/custom_methods/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import date
diff --git a/tests/custom_pk/models.py b/tests/custom_pk/models.py
index 5ef9b69f0c..8d5065aed8 100644
--- a/tests/custom_pk/models.py
+++ b/tests/custom_pk/models.py
@@ -6,7 +6,7 @@ By default, Django adds an ``"id"`` field to each model. But you can override
this behavior by explicitly adding ``primary_key=True`` to a field.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.db import models
diff --git a/tests/custom_pk/tests.py b/tests/custom_pk/tests.py
index 3f562f0bed..59bc64754f 100644
--- a/tests/custom_pk/tests.py
+++ b/tests/custom_pk/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.db import transaction, IntegrityError
from django.test import TestCase, skipIfDBFeature
diff --git a/tests/datatypes/tests.py b/tests/datatypes/tests.py
index b6b52dedf2..a2bb0c110a 100644
--- a/tests/datatypes/tests.py
+++ b/tests/datatypes/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
diff --git a/tests/dates/tests.py b/tests/dates/tests.py
index 6c02d597de..c2a8d82e37 100644
--- a/tests/dates/tests.py
+++ b/tests/dates/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
diff --git a/tests/datetimes/tests.py b/tests/datetimes/tests.py
index 58cb060f6b..f54b30d967 100644
--- a/tests/datetimes/tests.py
+++ b/tests/datetimes/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py
index 15b96be881..725b673903 100644
--- a/tests/defaultfilters/tests.py
+++ b/tests/defaultfilters/tests.py
@@ -249,9 +249,10 @@ class DefaultFiltersTests(TestCase):
'<a href="https://google.com" rel="nofollow">https://google.com</a>')
# Check urlize doesn't overquote already quoted urls - see #9655
- self.assertEqual(urlize('http://hi.baidu.com/%D6%D8%D0%C2%BF'),
- '<a href="http://hi.baidu.com/%D6%D8%D0%C2%BF" rel="nofollow">'
- 'http://hi.baidu.com/%D6%D8%D0%C2%BF</a>')
+ # The teststring is the urlquoted version of 'http://hi.baidu.com/重新开始'
+ self.assertEqual(urlize('http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B'),
+ '<a href="http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B" rel="nofollow">'
+ 'http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B</a>')
self.assertEqual(urlize('www.mystore.com/30%OffCoupons!'),
'<a href="http://www.mystore.com/30%25OffCoupons!" rel="nofollow">'
'www.mystore.com/30%OffCoupons!</a>')
diff --git a/tests/defer/tests.py b/tests/defer/tests.py
index 50db5a76b4..1df312e1bf 100644
--- a/tests/defer/tests.py
+++ b/tests/defer/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db.models.query_utils import DeferredAttribute, InvalidQuery
from django.test import TestCase
diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py
index ad2546794c..619f65163c 100644
--- a/tests/defer_regress/tests.py
+++ b/tests/defer_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/delete/tests.py b/tests/delete/tests.py
index 66173078a0..8fb16f5a2d 100644
--- a/tests/delete/tests.py
+++ b/tests/delete/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import models, IntegrityError, connection
from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature
diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py
index a4908b2121..22e15baf8e 100644
--- a/tests/delete_regress/tests.py
+++ b/tests/delete_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
diff --git a/tests/dispatch/tests/__init__.py b/tests/dispatch/tests/__init__.py
index b6d26217e1..4c4d4fea8a 100644
--- a/tests/dispatch/tests/__init__.py
+++ b/tests/dispatch/tests/__init__.py
@@ -2,7 +2,5 @@
Unit-tests for the dispatch project
"""
-from __future__ import absolute_import
-
from .test_dispatcher import DispatcherTests, ReceiverTestCase
from .test_saferef import SaferefTests
diff --git a/tests/distinct_on_fields/tests.py b/tests/distinct_on_fields/tests.py
index f62a32e58d..7bc06f0da2 100644
--- a/tests/distinct_on_fields/tests.py
+++ b/tests/distinct_on_fields/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db.models import Max
from django.test import TestCase, skipUnlessDBFeature
diff --git a/tests/empty/tests.py b/tests/empty/tests.py
index 6dd9f7c75d..007d04c363 100644
--- a/tests/empty/tests.py
+++ b/tests/empty/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.core.exceptions import ImproperlyConfigured
from django.db.models.loading import get_app
from django.test import TestCase
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index a351496442..9801d0acbb 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.core.exceptions import FieldError
from django.db.models import F
diff --git a/tests/expressions_regress/tests.py b/tests/expressions_regress/tests.py
index ddb2c83b4f..c4f8085804 100644
--- a/tests/expressions_regress/tests.py
+++ b/tests/expressions_regress/tests.py
@@ -1,7 +1,7 @@
"""
Spanning tests for all the operations that F() expressions can perform.
"""
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
diff --git a/tests/extra_regress/tests.py b/tests/extra_regress/tests.py
index 194b250c99..ae8f1b4423 100644
--- a/tests/extra_regress/tests.py
+++ b/tests/extra_regress/tests.py
@@ -1,10 +1,10 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
+from collections import OrderedDict
import datetime
from django.contrib.auth.models import User
from django.test import TestCase
-from django.utils.datastructures import SortedDict
from .models import TestObject, Order, RevisionableModel
@@ -74,7 +74,7 @@ class ExtraRegressTests(TestCase):
# select portions. Applies when portions are updated or otherwise
# moved around.
qs = User.objects.extra(
- select=SortedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))),
+ select=OrderedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))),
select_params=(1, 3)
)
qs = qs.extra(select={"beta": 4})
@@ -180,100 +180,100 @@ class ExtraRegressTests(TestCase):
obj.save()
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values()),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values()),
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}]
)
# Extra clauses after an empty values clause are still included
self.assertEqual(
- list(TestObject.objects.values().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
+ list(TestObject.objects.values().extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}]
)
# Extra columns are ignored if not mentioned in the values() clause
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second')),
[{'second': 'second', 'first': 'first'}]
)
# Extra columns after a non-empty values() clause are ignored
self.assertEqual(
- list(TestObject.objects.values('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
+ list(TestObject.objects.values('first', 'second').extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
[{'second': 'second', 'first': 'first'}]
)
# Extra columns can be partially returned
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second', 'foo')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second', 'foo')),
[{'second': 'second', 'foo': 'first', 'first': 'first'}]
)
# Also works if only extra columns are included
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('foo', 'whiz')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('foo', 'whiz')),
[{'foo': 'first', 'whiz': 'third'}]
)
# Values list works the same way
# All columns are returned for an empty values_list()
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list()),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list()),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
)
# Extra columns after an empty values_list() are still included
self.assertEqual(
- list(TestObject.objects.values_list().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
+ list(TestObject.objects.values_list().extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
)
# Extra columns ignored completely if not mentioned in values_list()
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second')),
[('first', 'second')]
)
# Extra columns after a non-empty values_list() clause are ignored completely
self.assertEqual(
- list(TestObject.objects.values_list('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
+ list(TestObject.objects.values_list('first', 'second').extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
[('first', 'second')]
)
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('second', flat=True)),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('second', flat=True)),
['second']
)
# Only the extra columns specified in the values_list() are returned
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second', 'whiz')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second', 'whiz')),
[('first', 'second', 'third')]
)
# ...also works if only extra columns are included
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('foo','whiz')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('foo','whiz')),
[('first', 'third')]
)
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', flat=True)),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', flat=True)),
['third']
)
# ... and values are returned in the order they are specified
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz','foo')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz','foo')),
[('third', 'first')]
)
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first','id')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first','id')),
[('first', obj.pk)]
)
self.assertEqual(
- list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')),
+ list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')),
[('third', 'first', 'second', obj.pk)]
)
diff --git a/tests/field_defaults/tests.py b/tests/field_defaults/tests.py
index 69dabb5168..d9f28d8c5c 100644
--- a/tests/field_defaults/tests.py
+++ b/tests/field_defaults/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from datetime import datetime
from django.test import TestCase
diff --git a/tests/field_subclassing/models.py b/tests/field_subclassing/models.py
index 642573cc83..67a95b02f2 100644
--- a/tests/field_subclassing/models.py
+++ b/tests/field_subclassing/models.py
@@ -2,8 +2,6 @@
Tests for field subclassing.
"""
-from __future__ import absolute_import
-
from django.db import models
from django.utils.encoding import force_text
diff --git a/tests/field_subclassing/tests.py b/tests/field_subclassing/tests.py
index 4945cff1bf..d3b4d9e527 100644
--- a/tests/field_subclassing/tests.py
+++ b/tests/field_subclassing/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core import serializers
from django.test import TestCase
diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
index 8cf4c33091..cdd9720374 100644
--- a/tests/file_storage/tests.py
+++ b/tests/file_storage/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import errno
import os
diff --git a/tests/file_uploads/tests.py b/tests/file_uploads/tests.py
index f5a9c10be4..b0f00236d2 100644
--- a/tests/file_uploads/tests.py
+++ b/tests/file_uploads/tests.py
@@ -1,5 +1,5 @@
#! -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import base64
import errno
diff --git a/tests/file_uploads/urls.py b/tests/file_uploads/urls.py
index 96efaaa5d8..4782a0dab9 100644
--- a/tests/file_uploads/urls.py
+++ b/tests/file_uploads/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from . import views
diff --git a/tests/file_uploads/views.py b/tests/file_uploads/views.py
index d1bd2cf44e..8d20a9cb6e 100644
--- a/tests/file_uploads/views.py
+++ b/tests/file_uploads/views.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import hashlib
import json
diff --git a/tests/files/tests.py b/tests/files/tests.py
index 54eeee13e4..b353c1a213 100644
--- a/tests/files/tests.py
+++ b/tests/files/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import os
import gzip
diff --git a/tests/fixtures/tests.py b/tests/fixtures/tests.py
index 6f2218b19e..78653ffe5e 100644
--- a/tests/fixtures/tests.py
+++ b/tests/fixtures/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import warnings
diff --git a/tests/fixtures_model_package/models/sql/book.sql b/tests/fixtures_model_package/models/sql/book.sql
new file mode 100644
index 0000000000..9b3918f4d7
--- /dev/null
+++ b/tests/fixtures_model_package/models/sql/book.sql
@@ -0,0 +1,2 @@
+-- Deprecated search path for custom SQL -- remove in Django 1.9
+INSERT INTO fixtures_model_package_book (name) VALUES ('My Deprecated Book');
diff --git a/tests/fixtures_model_package/sql/book.sql b/tests/fixtures_model_package/sql/book.sql
new file mode 100644
index 0000000000..21b1d9465b
--- /dev/null
+++ b/tests/fixtures_model_package/sql/book.sql
@@ -0,0 +1 @@
+INSERT INTO fixtures_model_package_book (name) VALUES ('My Book');
diff --git a/tests/fixtures_model_package/tests.py b/tests/fixtures_model_package/tests.py
index ad82267da3..1e22ac9833 100644
--- a/tests/fixtures_model_package/tests.py
+++ b/tests/fixtures_model_package/tests.py
@@ -5,6 +5,7 @@ import warnings
from django.core import management
from django.db import transaction
from django.test import TestCase, TransactionTestCase
+from django.utils.six import StringIO
from .models import Article, Book
@@ -110,3 +111,19 @@ class FixtureTestCase(TestCase):
],
lambda a: a.headline,
)
+
+
+class InitialSQLTests(TestCase):
+
+ def test_custom_sql(self):
+ """
+ #14300 -- Verify that custom_sql_for_model searches `app/sql` and not
+ `app/models/sql` (the old location will work until Django 1.9)
+ """
+ out = StringIO()
+ management.call_command("sqlcustom", "fixtures_model_package", stdout=out)
+ output = out.getvalue()
+ self.assertTrue("INSERT INTO fixtures_model_package_book (name) "
+ "VALUES ('My Book')" in output)
+ # value from deprecated search path models/sql (remove in Django 1.9)
+ self.assertTrue("Deprecated Book" in output)
diff --git a/tests/fixtures_regress/models.py b/tests/fixtures_regress/models.py
index 1cc30d2e51..99096728a7 100644
--- a/tests/fixtures_regress/models.py
+++ b/tests/fixtures_regress/models.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db import models
diff --git a/tests/fixtures_regress/tests.py b/tests/fixtures_regress/tests.py
index a6bad5716d..f917b21642 100644
--- a/tests/fixtures_regress/tests.py
+++ b/tests/fixtures_regress/tests.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Unittests for fixtures.
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import os
import re
@@ -181,55 +181,68 @@ class TestFixtures(TestCase):
"""
Test for ticket #4371 -- Loading a fixture file with invalid data
using explicit filename.
- Validate that error conditions are caught correctly
+ Test for ticket #18213 -- warning conditions are caught correctly
"""
- with six.assertRaisesRegex(self, management.CommandError,
- "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
+ with warnings.catch_warnings(record=True) as warning_list:
+ warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2.xml',
verbosity=0,
)
+ warning = warning_list.pop()
+ self.assertEqual(warning.category, RuntimeWarning)
+ self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
def test_invalid_data_no_ext(self):
"""
Test for ticket #4371 -- Loading a fixture file with invalid data
without file extension.
- Validate that error conditions are caught correctly
+ Test for ticket #18213 -- warning conditions are caught correctly
"""
- with six.assertRaisesRegex(self, management.CommandError,
- "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
+ with warnings.catch_warnings(record=True) as warning_list:
+ warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2',
verbosity=0,
)
+ warning = warning_list.pop()
+ self.assertEqual(warning.category, RuntimeWarning)
+ self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
def test_empty(self):
"""
- Test for ticket #4371 -- Loading a fixture file with no data returns an error.
- Validate that error conditions are caught correctly
+ Test for ticket #18213 -- Loading a fixture file with no data output a warning.
+ Previously empty fixture raises an error exception, see ticket #4371.
"""
- with six.assertRaisesRegex(self, management.CommandError,
- "No fixture data found for 'empty'. \(File format may be invalid.\)"):
+ with warnings.catch_warnings(record=True) as warning_list:
+ warnings.simplefilter("always")
management.call_command(
'loaddata',
'empty',
verbosity=0,
)
+ warning = warning_list.pop()
+ self.assertEqual(warning.category, RuntimeWarning)
+ self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)")
def test_error_message(self):
"""
- (Regression for #9011 - error message is correct)
+ Regression for #9011 - error message is correct.
+ Change from error to warning for ticket #18213.
"""
- with six.assertRaisesRegex(self, management.CommandError,
- "^No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)$"):
+ with warnings.catch_warnings(record=True) as warning_list:
+ warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2',
'animal',
verbosity=0,
)
+ warning = warning_list.pop()
+ self.assertEqual(warning.category, RuntimeWarning)
+ self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
def test_pg_sequence_resetting_checks(self):
"""
diff --git a/tests/force_insert_update/tests.py b/tests/force_insert_update/tests.py
index a5b2dcebb5..706a099872 100644
--- a/tests/force_insert_update/tests.py
+++ b/tests/force_insert_update/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import transaction, IntegrityError, DatabaseError
from django.test import TestCase
diff --git a/tests/foreign_object/models.py b/tests/foreign_object/models.py
index eee8091a15..d8c3bc10d4 100644
--- a/tests/foreign_object/models.py
+++ b/tests/foreign_object/models.py
@@ -5,14 +5,15 @@ from django.db.models.fields.related import ReverseSingleRelatedObjectDescriptor
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import get_language
+@python_2_unicode_compatible
class Country(models.Model):
# Table Column Fields
name = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.name
-
+@python_2_unicode_compatible
class Person(models.Model):
# Table Column Fields
name = models.CharField(max_length=128)
@@ -26,9 +27,10 @@ class Person(models.Model):
class Meta:
ordering = ('name',)
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Group(models.Model):
# Table Column Fields
name = models.CharField(max_length=128)
@@ -38,10 +40,11 @@ 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):
# Table Column Fields
membership_country = models.ForeignKey(Country)
@@ -51,17 +54,19 @@ class Membership(models.Model):
group_id = models.IntegerField()
# Relation Fields
- person = models.ForeignObject(Person,
+ person = models.ForeignObject(
+ Person,
from_fields=['membership_country', 'person_id'],
to_fields=['person_country_id', 'id'])
- group = models.ForeignObject(Group,
+ group = models.ForeignObject(
+ Group,
from_fields=['membership_country', 'group_id'],
to_fields=['group_country', 'id'])
class Meta:
ordering = ('date_joined', 'invite_reason')
- def __unicode__(self):
+ def __str__(self):
return "%s is a member of %s" % (self.person.name, self.group.name)
@@ -73,17 +78,20 @@ class Friendship(models.Model):
to_friend_id = models.IntegerField()
# Relation Fields
- from_friend = models.ForeignObject(Person,
+ from_friend = models.ForeignObject(
+ Person,
from_fields=['from_friend_country', 'from_friend_id'],
to_fields=['person_country_id', 'id'],
related_name='from_friend')
- to_friend_country = models.ForeignObject(Country,
+ to_friend_country = models.ForeignObject(
+ Country,
from_fields=['to_friend_country_id'],
to_fields=['id'],
related_name='to_friend_country')
- to_friend = models.ForeignObject(Person,
+ to_friend = models.ForeignObject(
+ Person,
from_fields=['to_friend_country_id', 'to_friend_id'],
to_fields=['person_country_id', 'id'],
related_name='to_friend')
@@ -140,6 +148,9 @@ class Article(models.Model):
except ArticleTranslation.DoesNotExist:
return '[No translation found]'
+class NewsArticle(Article):
+ pass
+
class ArticleTranslation(models.Model):
article = models.ForeignKey(Article)
lang = models.CharField(max_length='2')
@@ -156,5 +167,6 @@ class ArticleTag(models.Model):
name = models.CharField(max_length=255)
class ArticleIdea(models.Model):
- articles = models.ManyToManyField(Article, related_name="ideas", related_query_name="idea_things")
+ articles = models.ManyToManyField(Article, related_name="ideas",
+ related_query_name="idea_things")
name = models.CharField(max_length=255)
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py
index 670fc94dc5..cd81cc68a2 100644
--- a/tests/foreign_object/tests.py
+++ b/tests/foreign_object/tests.py
@@ -1,12 +1,17 @@
import datetime
from operator import attrgetter
-from .models import Country, Person, Group, Membership, Friendship, Article, ArticleTranslation, ArticleTag, ArticleIdea
+from .models import (
+ Country, Person, Group, Membership, Friendship, Article,
+ ArticleTranslation, ArticleTag, ArticleIdea, NewsArticle)
from django.test import TestCase
from django.utils.translation import activate
from django.core.exceptions import FieldError
from django import forms
+# Note that these tests are testing internal implementation details.
+# ForeignObject is not part of public API.
+
class MultiColumnFKTests(TestCase):
def setUp(self):
# Creating countries
@@ -140,9 +145,9 @@ class MultiColumnFKTests(TestCase):
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
with self.assertNumQueries(1):
- people = [m.person for m in Membership.objects.select_related('person')]
+ people = [m.person for m in Membership.objects.select_related('person').order_by('pk')]
- normal_people = [m.person for m in Membership.objects.all()]
+ normal_people = [m.person for m in Membership.objects.all().order_by('pk')]
self.assertEqual(people, normal_people)
def test_prefetch_foreignkey_forward_works(self):
@@ -150,19 +155,22 @@ class MultiColumnFKTests(TestCase):
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
with self.assertNumQueries(2):
- people = [m.person for m in Membership.objects.prefetch_related('person')]
+ people = [
+ m.person for m in Membership.objects.prefetch_related('person').order_by('pk')]
- normal_people = [m.person for m in Membership.objects.all()]
+ normal_people = [m.person for m in Membership.objects.order_by('pk')]
self.assertEqual(people, normal_people)
def test_prefetch_foreignkey_reverse_works(self):
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
with self.assertNumQueries(2):
- membership_sets = [list(p.membership_set.all())
- for p in Person.objects.prefetch_related('membership_set')]
+ membership_sets = [
+ list(p.membership_set.all())
+ for p in Person.objects.prefetch_related('membership_set').order_by('pk')]
- normal_membership_sets = [list(p.membership_set.all()) for p in Person.objects.all()]
+ normal_membership_sets = [list(p.membership_set.all())
+ for p in Person.objects.order_by('pk')]
self.assertEqual(membership_sets, normal_membership_sets)
def test_m2m_through_forward_returns_valid_members(self):
@@ -339,6 +347,20 @@ class MultiColumnFKTests(TestCase):
with self.assertRaises(FieldError):
Article.objects.filter(ideas__name="idea1")
+ def test_inheritance(self):
+ activate("fi")
+ na = NewsArticle.objects.create(pub_date=datetime.date.today())
+ ArticleTranslation.objects.create(
+ article=na, lang="fi", title="foo", body="bar")
+ self.assertQuerysetEqual(
+ NewsArticle.objects.select_related('active_translation'),
+ [na], lambda x: x
+ )
+ with self.assertNumQueries(1):
+ self.assertEqual(
+ NewsArticle.objects.select_related(
+ 'active_translation')[0].active_translation.title,
+ "foo")
class FormsTests(TestCase):
# ForeignObjects should not have any form fields, currently the user needs
diff --git a/tests/forms_tests/models.py b/tests/forms_tests/models.py
index bec31d12d7..33898ffbb8 100644
--- a/tests/forms_tests/models.py
+++ b/tests/forms_tests/models.py
@@ -34,7 +34,30 @@ class Defaults(models.Model):
class ChoiceModel(models.Model):
"""For ModelChoiceField and ModelMultipleChoiceField tests."""
+ CHOICES = [
+ ('', 'No Preference'),
+ ('f', 'Foo'),
+ ('b', 'Bar'),
+ ]
+
+ INTEGER_CHOICES = [
+ (None, 'No Preference'),
+ (1, 'Foo'),
+ (2, 'Bar'),
+ ]
+
+ STRING_CHOICES_WITH_NONE = [
+ (None, 'No Preference'),
+ ('f', 'Foo'),
+ ('b', 'Bar'),
+ ]
+
name = models.CharField(max_length=10)
+ choice = models.CharField(max_length=2, blank=True, choices=CHOICES)
+ choice_string_w_none = models.CharField(
+ max_length=2, blank=True, null=True, choices=STRING_CHOICES_WITH_NONE)
+ choice_integer = models.IntegerField(choices=INTEGER_CHOICES, blank=True,
+ null=True)
@python_2_unicode_compatible
diff --git a/tests/forms_tests/tests/__init__.py b/tests/forms_tests/tests/__init__.py
index aea9418c05..39219f82be 100644
--- a/tests/forms_tests/tests/__init__.py
+++ b/tests/forms_tests/tests/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from .test_error_messages import (FormsErrorMessagesTestCase,
ModelChoiceFieldErrorMessagesTestCase)
from .test_extra import FormsExtraTestCase, FormsExtraL10NTestCase
diff --git a/tests/forms_tests/tests/test_error_messages.py b/tests/forms_tests/tests/test_error_messages.py
index 9d45a46a3d..f0638298e9 100644
--- a/tests/forms_tests/tests/test_error_messages.py
+++ b/tests/forms_tests/tests/test_error_messages.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.core.files.uploadedfile import SimpleUploadedFile
from django.forms import *
diff --git a/tests/forms_tests/tests/test_extra.py b/tests/forms_tests/tests/test_extra.py
index d439e2223c..3bc22243fb 100644
--- a/tests/forms_tests/tests/test_extra.py
+++ b/tests/forms_tests/tests/test_extra.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
@@ -620,6 +620,37 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
self.assertTrue(f.is_valid())
self.assertEqual(f.cleaned_data['username'], 'sirrobin')
+ def test_changing_cleaned_data_nothing_returned(self):
+ class UserForm(Form):
+ username = CharField(max_length=10)
+ password = CharField(widget=PasswordInput)
+
+ def clean(self):
+ self.cleaned_data['username'] = self.cleaned_data['username'].lower()
+ # don't return anything
+
+ f = UserForm({'username': 'SirRobin', 'password': 'blue'})
+ self.assertTrue(f.is_valid())
+ self.assertEqual(f.cleaned_data['username'], 'sirrobin')
+
+ def test_changing_cleaned_data_in_clean(self):
+ class UserForm(Form):
+ username = CharField(max_length=10)
+ password = CharField(widget=PasswordInput)
+
+ def clean(self):
+ data = self.cleaned_data
+
+ # Return a different dict. We have not changed self.cleaned_data.
+ return {
+ 'username': data['username'].lower(),
+ 'password': 'this_is_not_a_secret',
+ }
+
+ f = UserForm({'username': 'SirRobin', 'password': 'blue'})
+ self.assertTrue(f.is_valid())
+ self.assertEqual(f.cleaned_data['username'], 'sirrobin')
+
def test_overriding_errorlist(self):
@python_2_unicode_compatible
class DivErrorList(ErrorList):
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 633fde5026..1c72d17abe 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import datetime
from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core.validators import RegexValidator
from django.forms import *
from django.http import QueryDict
from django.template import Template, Context
@@ -1792,6 +1793,75 @@ class FormsTestCase(TestCase):
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data, {'name' : 'fname lname'})
+ def test_multivalue_optional_subfields(self):
+ class PhoneField(MultiValueField):
+ def __init__(self, *args, **kwargs):
+ fields = (
+ CharField(label='Country Code', validators=[
+ RegexValidator(r'^\+\d{1,2}$', message='Enter a valid country code.')]),
+ CharField(label='Phone Number'),
+ CharField(label='Extension', error_messages={'incomplete': 'Enter an extension.'}),
+ CharField(label='Label', required=False, help_text='E.g. home, work.'),
+ )
+ super(PhoneField, self).__init__(fields, *args, **kwargs)
+
+ def compress(self, data_list):
+ if data_list:
+ return '%s.%s ext. %s (label: %s)' % tuple(data_list)
+ return None
+
+ # An empty value for any field will raise a `required` error on a
+ # required `MultiValueField`.
+ f = PhoneField()
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ['+61'])
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ['+61', '287654321', '123'])
+ self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home']))
+ self.assertRaisesMessage(ValidationError,
+ "'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
+
+ # Empty values for fields will NOT raise a `required` error on an
+ # optional `MultiValueField`
+ f = PhoneField(required=False)
+ self.assertEqual(None, f.clean(''))
+ self.assertEqual(None, f.clean(None))
+ self.assertEqual(None, f.clean([]))
+ self.assertEqual('+61. ext. (label: )', f.clean(['+61']))
+ self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
+ self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home']))
+ self.assertRaisesMessage(ValidationError,
+ "'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
+
+ # For a required `MultiValueField` with `require_all_fields=False`, a
+ # `required` error will only be raised if all fields are empty. Fields
+ # can individually be required or optional. An empty value for any
+ # required field will raise an `incomplete` error.
+ f = PhoneField(require_all_fields=False)
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
+ self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
+ self.assertRaisesMessage(ValidationError, "'Enter a complete value.'", f.clean, ['+61'])
+ self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
+ six.assertRaisesRegex(self, ValidationError,
+ "'Enter a complete value\.', u?'Enter an extension\.'", f.clean, ['', '', '', 'Home'])
+ self.assertRaisesMessage(ValidationError,
+ "'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
+
+ # For an optional `MultiValueField` with `require_all_fields=False`, we
+ # don't get any `required` error but we still get `incomplete` errors.
+ f = PhoneField(required=False, require_all_fields=False)
+ self.assertEqual(None, f.clean(''))
+ self.assertEqual(None, f.clean(None))
+ self.assertEqual(None, f.clean([]))
+ self.assertRaisesMessage(ValidationError, "'Enter a complete value.'", f.clean, ['+61'])
+ self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
+ six.assertRaisesRegex(self, ValidationError,
+ "'Enter a complete value\.', u?'Enter an extension\.'", f.clean, ['', '', '', 'Home'])
+ self.assertRaisesMessage(ValidationError,
+ "'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
+
def test_custom_empty_values(self):
"""
Test that form fields can customize what is considered as an empty value
@@ -1824,7 +1894,7 @@ class FormsTestCase(TestCase):
# passing just one argument: overrides the field's label
(('custom',), {}, '<label for="id_field">custom:</label>'),
- # the overriden label is escaped
+ # the overridden label is escaped
(('custom&',), {}, '<label for="id_field">custom&amp;:</label>'),
((mark_safe('custom&'),), {}, '<label for="id_field">custom&:</label>'),
@@ -1870,3 +1940,13 @@ class FormsTestCase(TestCase):
boundfield = SomeForm()['field']
self.assertHTMLEqual(boundfield.label_tag(), '<label for="id_field"></label>')
+
+ def test_label_tag_override(self):
+ """
+ BoundField label_suffix (if provided) overrides Form label_suffix
+ """
+ class SomeForm(Form):
+ field = CharField()
+ boundfield = SomeForm(label_suffix='!')['field']
+
+ self.assertHTMLEqual(boundfield.label_tag(label_suffix='$'), '<label for="id_field">Field$</label>')
diff --git a/tests/forms_tests/tests/test_widgets.py b/tests/forms_tests/tests/test_widgets.py
index 4c566dc8e4..06ee2d6c53 100644
--- a/tests/forms_tests/tests/test_widgets.py
+++ b/tests/forms_tests/tests/test_widgets.py
@@ -849,6 +849,14 @@ beatle J R Ringo False""")
w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />')
+ # Test needs_multipart_form=True if any widget needs it
+ w = MyMultiWidget(widgets=(TextInput(), FileInput()))
+ self.assertTrue(w.needs_multipart_form)
+
+ # Test needs_multipart_form=False if no widget needs it
+ w = MyMultiWidget(widgets=(TextInput(), TextInput()))
+ self.assertFalse(w.needs_multipart_form)
+
def test_splitdatetime(self):
w = SplitDateTimeWidget()
self.assertHTMLEqual(w.render('date', ''), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py
index 99a67c320c..618ab8e07c 100644
--- a/tests/forms_tests/tests/tests.py
+++ b/tests/forms_tests/tests/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
@@ -10,8 +10,8 @@ from django.forms.models import ModelFormMetaclass
from django.test import TestCase
from django.utils import six
-from ..models import (ChoiceOptionModel, ChoiceFieldModel, FileModel, Group,
- BoundaryModel, Defaults, OptionalMultiChoiceModel)
+from ..models import (ChoiceModel, ChoiceOptionModel, ChoiceFieldModel,
+ FileModel, Group, BoundaryModel, Defaults, OptionalMultiChoiceModel)
class ChoiceFieldForm(ModelForm):
@@ -34,6 +34,24 @@ class ChoiceFieldExclusionForm(ModelForm):
model = ChoiceFieldModel
+class EmptyCharLabelChoiceForm(ModelForm):
+ class Meta:
+ model = ChoiceModel
+ fields = ['name', 'choice']
+
+
+class EmptyIntegerLabelChoiceForm(ModelForm):
+ class Meta:
+ model = ChoiceModel
+ fields = ['name', 'choice_integer']
+
+
+class EmptyCharLabelNoneChoiceForm(ModelForm):
+ class Meta:
+ model = ChoiceModel
+ fields = ['name', 'choice_string_w_none']
+
+
class FileForm(Form):
file1 = FileField()
@@ -259,3 +277,78 @@ class ManyToManyExclusionTestCase(TestCase):
self.assertEqual(form.instance.choice_int.pk, data['choice_int'])
self.assertEqual(list(form.instance.multi_choice.all()), [opt2, opt3])
self.assertEqual([obj.pk for obj in form.instance.multi_choice_int.all()], data['multi_choice_int'])
+
+
+class EmptyLabelTestCase(TestCase):
+ def test_empty_field_char(self):
+ f = EmptyCharLabelChoiceForm()
+ self.assertHTMLEqual(f.as_p(),
+ """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
+<p><label for="id_choice">Choice:</label> <select id="id_choice" name="choice">
+<option value="" selected="selected">No Preference</option>
+<option value="f">Foo</option>
+<option value="b">Bar</option>
+</select></p>""")
+
+ def test_empty_field_char_none(self):
+ f = EmptyCharLabelNoneChoiceForm()
+ self.assertHTMLEqual(f.as_p(),
+ """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
+<p><label for="id_choice_string_w_none">Choice string w none:</label> <select id="id_choice_string_w_none" name="choice_string_w_none">
+<option value="" selected="selected">No Preference</option>
+<option value="f">Foo</option>
+<option value="b">Bar</option>
+</select></p>""")
+
+ def test_save_empty_label_forms(self):
+ # Test that saving a form with a blank choice results in the expected
+ # value being stored in the database.
+ tests = [
+ (EmptyCharLabelNoneChoiceForm, 'choice_string_w_none', None),
+ (EmptyIntegerLabelChoiceForm, 'choice_integer', None),
+ (EmptyCharLabelChoiceForm, 'choice', ''),
+ ]
+
+ for form, key, expected in tests:
+ f = form({'name': 'some-key', key: ''})
+ self.assertTrue(f.is_valid())
+ m = f.save()
+ self.assertEqual(expected, getattr(m, key))
+ self.assertEqual('No Preference',
+ getattr(m, 'get_{0}_display'.format(key))())
+
+ def test_empty_field_integer(self):
+ f = EmptyIntegerLabelChoiceForm()
+ self.assertHTMLEqual(f.as_p(),
+ """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
+<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
+<option value="" selected="selected">No Preference</option>
+<option value="1">Foo</option>
+<option value="2">Bar</option>
+</select></p>""")
+
+ def test_get_display_value_on_none(self):
+ m = ChoiceModel.objects.create(name='test', choice='', choice_integer=None)
+ self.assertEqual(None, m.choice_integer)
+ self.assertEqual('No Preference', m.get_choice_integer_display())
+
+ def test_html_rendering_of_prepopulated_models(self):
+ none_model = ChoiceModel(name='none-test', choice_integer=None)
+ f = EmptyIntegerLabelChoiceForm(instance=none_model)
+ self.assertHTMLEqual(f.as_p(),
+ """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="none-test"/></p>
+<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
+<option value="" selected="selected">No Preference</option>
+<option value="1">Foo</option>
+<option value="2">Bar</option>
+</select></p>""")
+
+ foo_model = ChoiceModel(name='foo-test', choice_integer=1)
+ f = EmptyIntegerLabelChoiceForm(instance=foo_model)
+ self.assertHTMLEqual(f.as_p(),
+ """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="foo-test"/></p>
+<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
+<option value="">No Preference</option>
+<option value="1" selected="selected">Foo</option>
+<option value="2">Bar</option>
+</select></p>""")
diff --git a/tests/generic_inline_admin/admin.py b/tests/generic_inline_admin/admin.py
index 73cac7f7c5..1917024fa5 100644
--- a/tests/generic_inline_admin/admin.py
+++ b/tests/generic_inline_admin/admin.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from django.contrib.contenttypes import generic
diff --git a/tests/generic_inline_admin/tests.py b/tests/generic_inline_admin/tests.py
index ac2c191183..83bee2f4e0 100644
--- a/tests/generic_inline_admin/tests.py
+++ b/tests/generic_inline_admin/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf import settings
from django.contrib import admin
@@ -325,3 +325,23 @@ class GenericInlineModelAdminTest(TestCase):
self.assertEqual(
list(list(ma.get_formsets(request))[0]().forms[0].fields),
['description', 'keywords', 'id', 'DELETE'])
+
+ def test_get_fieldsets(self):
+ # Test that get_fieldsets is called when figuring out form fields.
+ # Refs #18681.
+ class MediaForm(ModelForm):
+ class Meta:
+ model = Media
+ fields = '__all__'
+
+ class MediaInline(GenericTabularInline):
+ form = MediaForm
+ model = Media
+ can_delete = False
+
+ def get_fieldsets(self, request, obj=None):
+ return [(None, {'fields': ['url', 'description']})]
+
+ ma = MediaInline(Media, self.site)
+ form = ma.get_formset(None).form
+ self.assertEqual(form._meta.fields, ['url', 'description'])
diff --git a/tests/generic_inline_admin/urls.py b/tests/generic_inline_admin/urls.py
index 88d7b574d4..8d68d6c922 100644
--- a/tests/generic_inline_admin/urls.py
+++ b/tests/generic_inline_admin/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, include
from . import admin
diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py
index 734b2e5143..2b52ebac56 100644
--- a/tests/generic_relations/tests.py
+++ b/tests/generic_relations/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django import forms
from django.contrib.contenttypes.generic import generic_inlineformset_factory
diff --git a/tests/generic_views/test_base.py b/tests/generic_views/test_base.py
index 013a8f282c..b1dd7a3040 100644
--- a/tests/generic_views/test_base.py
+++ b/tests/generic_views/test_base.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import time
import unittest
diff --git a/tests/generic_views/test_dates.py b/tests/generic_views/test_dates.py
index bff909f7d0..03c6d02e5e 100644
--- a/tests/generic_views/test_dates.py
+++ b/tests/generic_views/test_dates.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import time
import datetime
diff --git a/tests/generic_views/test_detail.py b/tests/generic_views/test_detail.py
index 3a97d27995..8a487a7c3d 100644
--- a/tests/generic_views/test_detail.py
+++ b/tests/generic_views/test_detail.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
diff --git a/tests/generic_views/test_edit.py b/tests/generic_views/test_edit.py
index 9ed18833e4..9b1ba0f865 100644
--- a/tests/generic_views/test_edit.py
+++ b/tests/generic_views/test_edit.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import warnings
from unittest import expectedFailure
diff --git a/tests/generic_views/test_forms.py b/tests/generic_views/test_forms.py
index 8c118e32a6..1ee26afc8f 100644
--- a/tests/generic_views/test_forms.py
+++ b/tests/generic_views/test_forms.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django import forms
diff --git a/tests/generic_views/test_list.py b/tests/generic_views/test_list.py
index a77a6418a3..e572af8e32 100644
--- a/tests/generic_views/test_list.py
+++ b/tests/generic_views/test_list.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
diff --git a/tests/generic_views/urls.py b/tests/generic_views/urls.py
index 695b50279a..4ef8f7a97f 100644
--- a/tests/generic_views/urls.py
+++ b/tests/generic_views/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from django.views.decorators.cache import cache_page
from django.views.generic import TemplateView
diff --git a/tests/generic_views/views.py b/tests/generic_views/views.py
index fd331f14b7..f839b53753 100644
--- a/tests/generic_views/views.py
+++ b/tests/generic_views/views.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
diff --git a/tests/get_earliest_or_latest/tests.py b/tests/get_earliest_or_latest/tests.py
index 8d16af9587..eeb95c0818 100644
--- a/tests/get_earliest_or_latest/tests.py
+++ b/tests/get_earliest_or_latest/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
diff --git a/tests/get_object_or_404/tests.py b/tests/get_object_or_404/tests.py
index 38ebeb4f8c..1a0b41bc4d 100644
--- a/tests/get_object_or_404/tests.py
+++ b/tests/get_object_or_404/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.http import Http404
from django.shortcuts import get_object_or_404, get_list_or_404
@@ -87,7 +87,7 @@ class GetObjectOr404Tests(TestCase):
self.assertRaisesMessage(ValueError,
"Object is of type 'str', but must be a Django Model, Manager, "
"or QuerySet",
- get_object_or_404, "Article", title__icontains="Run"
+ get_object_or_404, str("Article"), title__icontains="Run"
)
class CustomClass(object):
diff --git a/tests/get_or_create/tests.py b/tests/get_or_create/tests.py
index 0f766ab128..a612ea60a0 100644
--- a/tests/get_or_create/tests.py
+++ b/tests/get_or_create/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import date
import traceback
@@ -65,7 +65,7 @@ class GetOrCreateTests(TestCase):
ManualPrimaryKeyTest.objects.get_or_create(id=1, data="Different")
except IntegrityError as e:
formatted_traceback = traceback.format_exc()
- self.assertIn('obj.save', formatted_traceback)
+ self.assertIn(str('obj.save'), formatted_traceback)
def test_savepoint_rollback(self):
# Regression test for #20463: the database connection should still be
diff --git a/tests/get_or_create_regress/tests.py b/tests/get_or_create_regress/tests.py
index 92c371b6f8..54dafc85fb 100644
--- a/tests/get_or_create_regress/tests.py
+++ b/tests/get_or_create_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py
index 3a2ec23864..1679b6e036 100644
--- a/tests/httpwrappers/tests.py
+++ b/tests/httpwrappers/tests.py
@@ -16,10 +16,13 @@ from django.http import (QueryDict, HttpResponse, HttpResponseRedirect,
SimpleCookie, BadHeaderError,
parse_cookie)
from django.test import TestCase
-from django.utils.encoding import smart_str
+from django.utils.encoding import smart_str, force_text
+from django.utils.functional import lazy
from django.utils._os import upath
from django.utils import six
+lazystr = lazy(force_text, six.text_type)
+
class QueryDictTests(unittest.TestCase):
def test_missing_key(self):
@@ -366,6 +369,10 @@ class HttpResponseTests(unittest.TestCase):
self.assertEqual(list(i), [b'abc'])
self.assertEqual(list(i), [])
+ def test_lazy_content(self):
+ r = HttpResponse(lazystr('helloworld'))
+ self.assertEqual(r.content, b'helloworld')
+
def test_file_interface(self):
r = HttpResponse()
r.write(b"hello")
@@ -402,6 +409,11 @@ class HttpResponseSubclassesTests(TestCase):
# Test that url attribute is right
self.assertEqual(response.url, response['Location'])
+ def test_redirect_lazy(self):
+ """Make sure HttpResponseRedirect works with lazy strings."""
+ r = HttpResponseRedirect(lazystr('/redirected/'))
+ self.assertEqual(r.url, '/redirected/')
+
def test_not_modified(self):
response = HttpResponseNotModified()
self.assertEqual(response.status_code, 304)
diff --git a/tests/i18n/forms.py b/tests/i18n/forms.py
index 6e4def9c5e..07b015d590 100644
--- a/tests/i18n/forms.py
+++ b/tests/i18n/forms.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django import forms
from django.forms.extras import SelectDateWidget
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 019ed88cdb..05d1065a75 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import decimal
+from importlib import import_module
import os
import pickle
from threading import local
@@ -17,7 +18,6 @@ from django.utils import translation
from django.utils.formats import (get_format, date_format, time_format,
localize, localize_input, iter_format_modules, get_format_modules,
number_format, reset_format_cache, sanitize_separators)
-from django.utils.importlib import import_module
from django.utils.numberformat import format as nformat
from django.utils._os import upath
from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
@@ -774,6 +774,39 @@ class FormattingTests(TransRealMixin, TestCase):
self.assertEqual(template2.render(context), output2)
self.assertEqual(template3.render(context), output3)
+ def test_localized_as_text_as_hidden_input(self):
+ """
+ Tests if form input with 'as_hidden' or 'as_text' is correctly localized. Ticket #18777
+ """
+ self.maxDiff = 1200
+
+ with translation.override('de-at', deactivate=True):
+ template = Template('{% load l10n %}{{ form.date_added }}; {{ form.cents_paid }}')
+ template_as_text = Template('{% load l10n %}{{ form.date_added.as_text }}; {{ form.cents_paid.as_text }}')
+ template_as_hidden = Template('{% load l10n %}{{ form.date_added.as_hidden }}; {{ form.cents_paid.as_hidden }}')
+ form = CompanyForm({
+ 'name': 'acme',
+ 'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0),
+ 'cents_paid': decimal.Decimal('59.47'),
+ 'products_delivered': 12000,
+ })
+ context = Context({'form': form })
+ self.assertTrue(form.is_valid())
+
+ self.assertHTMLEqual(
+ template.render(context),
+ '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />'
+ )
+ self.assertHTMLEqual(
+ template_as_text.render(context),
+ '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />'
+ )
+ self.assertHTMLEqual(
+ template_as_hidden.render(context),
+ '<input id="id_date_added" name="date_added" type="hidden" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47" />'
+ )
+
+
class MiscTests(TransRealMixin, TestCase):
def setUp(self):
diff --git a/tests/inline_formsets/tests.py b/tests/inline_formsets/tests.py
index ad8a666cb5..a16488dc79 100644
--- a/tests/inline_formsets/tests.py
+++ b/tests/inline_formsets/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.forms.models import inlineformset_factory
from django.test import TestCase
diff --git a/tests/introspection/tests.py b/tests/introspection/tests.py
index f1c87bbf14..6f38439945 100644
--- a/tests/introspection/tests.py
+++ b/tests/introspection/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import unittest
diff --git a/tests/known_related_objects/tests.py b/tests/known_related_objects/tests.py
index d28d266557..6fd507cbdc 100644
--- a/tests/known_related_objects/tests.py
+++ b/tests/known_related_objects/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py
index ee9c5afe1d..2beb43929b 100644
--- a/tests/lookup/tests.py
+++ b/tests/lookup/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import datetime
from operator import attrgetter
@@ -470,7 +470,8 @@ class LookupTests(TestCase):
self.fail('FieldError not raised')
except FieldError as ex:
self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' "
- "into field. Choices are: author, headline, id, pub_date, tag")
+ "into field. Choices are: author, author_id, headline, "
+ "id, pub_date, tag")
try:
Article.objects.filter(headline__starts='Article')
self.fail('FieldError not raised')
diff --git a/tests/m2m_and_m2o/tests.py b/tests/m2m_and_m2o/tests.py
index 77f2eb3b09..0380ad4b08 100644
--- a/tests/m2m_and_m2o/tests.py
+++ b/tests/m2m_and_m2o/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.db.models import Q
from django.test import TestCase
diff --git a/tests/m2m_intermediary/tests.py b/tests/m2m_intermediary/tests.py
index f261f23546..d9c77ecb7c 100644
--- a/tests/m2m_intermediary/tests.py
+++ b/tests/m2m_intermediary/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
diff --git a/tests/m2m_multiple/tests.py b/tests/m2m_multiple/tests.py
index 7bf88f99bb..2122517ce4 100644
--- a/tests/m2m_multiple/tests.py
+++ b/tests/m2m_multiple/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
diff --git a/tests/m2m_recursive/tests.py b/tests/m2m_recursive/tests.py
index a3f2c670d6..3beafc9692 100644
--- a/tests/m2m_recursive/tests.py
+++ b/tests/m2m_recursive/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/m2m_regress/tests.py b/tests/m2m_regress/tests.py
index 884fc097a1..610f01694a 100644
--- a/tests/m2m_regress/tests.py
+++ b/tests/m2m_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import FieldError
from django.test import TestCase
diff --git a/tests/m2m_signals/tests.py b/tests/m2m_signals/tests.py
index d3d2a74c70..569a2dc12d 100644
--- a/tests/m2m_signals/tests.py
+++ b/tests/m2m_signals/tests.py
@@ -2,8 +2,6 @@
Testing signals emitted on changing m2m relations.
"""
-from .models import Person
-
from django.db import models
from django.test import TestCase
diff --git a/tests/m2m_through/tests.py b/tests/m2m_through/tests.py
index 259dc68a0b..69a7ec99bf 100644
--- a/tests/m2m_through/tests.py
+++ b/tests/m2m_through/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
from operator import attrgetter
diff --git a/tests/m2m_through_regress/tests.py b/tests/m2m_through_regress/tests.py
index de4d52a2db..c1b229b30b 100644
--- a/tests/m2m_through_regress/tests.py
+++ b/tests/m2m_through_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core import management
from django.contrib.auth.models import User
diff --git a/tests/m2o_recursive/tests.py b/tests/m2o_recursive/tests.py
index fa04c74cca..f5e8938706 100644
--- a/tests/m2o_recursive/tests.py
+++ b/tests/m2o_recursive/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/mail/tests.py b/tests/mail/tests.py
index 822c572b0f..0f85cc0c76 100644
--- a/tests/mail/tests.py
+++ b/tests/mail/tests.py
@@ -397,6 +397,34 @@ class BaseEmailBackendTests(object):
self.assertEqual(message.get_payload(), "Content")
self.assertEqual(message["from"], "=?utf-8?q?Firstname_S=C3=BCrname?= <from@example.com>")
+ def test_plaintext_send_mail(self):
+ """
+ Test send_mail without the html_message
+ regression test for adding html_message parameter to send_mail()
+ """
+ send_mail('Subject', 'Content', 'sender@example.com', ['nobody@example.com'])
+ message = self.get_the_message()
+
+ self.assertEqual(message.get('subject'), 'Subject')
+ self.assertEqual(message.get_all('to'), ['nobody@example.com'])
+ self.assertFalse(message.is_multipart())
+ self.assertEqual(message.get_payload(), 'Content')
+ self.assertEqual(message.get_content_type(), 'text/plain')
+
+ def test_html_send_mail(self):
+ """Test html_message argument to send_mail"""
+ send_mail('Subject', 'Content', 'sender@example.com', ['nobody@example.com'], html_message='HTML Content')
+ message = self.get_the_message()
+
+ self.assertEqual(message.get('subject'), 'Subject')
+ self.assertEqual(message.get_all('to'), ['nobody@example.com'])
+ self.assertTrue(message.is_multipart())
+ self.assertEqual(len(message.get_payload()), 2)
+ self.assertEqual(message.get_payload(0).get_payload(), 'Content')
+ self.assertEqual(message.get_payload(0).get_content_type(), 'text/plain')
+ self.assertEqual(message.get_payload(1).get_payload(), 'HTML Content')
+ self.assertEqual(message.get_payload(1).get_content_type(), 'text/html')
+
@override_settings(MANAGERS=[('nobody', 'nobody@example.com')])
def test_html_mail_managers(self):
"""Test html_message argument to mail_managers"""
diff --git a/tests/managers_regress/tests.py b/tests/managers_regress/tests.py
index 45059be4e5..e5dce53122 100644
--- a/tests/managers_regress/tests.py
+++ b/tests/managers_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import copy
from django.conf import settings
diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py
index 7d30379b94..e6fed191fc 100644
--- a/tests/many_to_many/tests.py
+++ b/tests/many_to_many/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index a4f87a3283..ae629288b1 100644
--- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from copy import deepcopy
import datetime
diff --git a/tests/many_to_one_null/tests.py b/tests/many_to_one_null/tests.py
index 4de44b5e64..cd1800d77c 100644
--- a/tests/many_to_one_null/tests.py
+++ b/tests/many_to_one_null/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/many_to_one_regress/tests.py b/tests/many_to_one_regress/tests.py
index 035ba53bff..19cfaad097 100644
--- a/tests/many_to_one_regress/tests.py
+++ b/tests/many_to_one_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import models
from django.test import TestCase
diff --git a/tests/max_lengths/tests.py b/tests/max_lengths/tests.py
index 0f525864d5..43f9e217c8 100644
--- a/tests/max_lengths/tests.py
+++ b/tests/max_lengths/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import unittest
diff --git a/tests/middleware/tests.py b/tests/middleware/tests.py
index 5ceab2e594..0897ec06be 100644
--- a/tests/middleware/tests.py
+++ b/tests/middleware/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import gzip
from io import BytesIO
diff --git a/tests/middleware_exceptions/urls.py b/tests/middleware_exceptions/urls.py
index 042607fdc8..fcef638553 100644
--- a/tests/middleware_exceptions/urls.py
+++ b/tests/middleware_exceptions/urls.py
@@ -1,6 +1,3 @@
-# coding: utf-8
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from . import views
diff --git a/tests/model_fields/test_imagefield.py b/tests/model_fields/test_imagefield.py
index f6019bd77f..ce7d33eb32 100644
--- a/tests/model_fields/test_imagefield.py
+++ b/tests/model_fields/test_imagefield.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import os
import shutil
diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py
index 1ce5eba3e9..378e6280cc 100644
--- a/tests/model_fields/tests.py
+++ b/tests/model_fields/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
from decimal import Decimal
@@ -8,11 +8,21 @@ from django import test
from django import forms
from django.core.exceptions import ValidationError
from django.db import connection, models, IntegrityError
-from django.db.models.fields.files import FieldFile
+from django.db.models.fields import (
+ AutoField, BigIntegerField, BinaryField, BooleanField, CharField,
+ CommaSeparatedIntegerField, DateField, DateTimeField, DecimalField,
+ EmailField, FilePathField, FloatField, IntegerField, IPAddressField,
+ GenericIPAddressField, NullBooleanField, PositiveIntegerField,
+ PositiveSmallIntegerField, SlugField, SmallIntegerField, TextField,
+ TimeField, URLField)
+from django.db.models.fields.files import FileField, ImageField
from django.utils import six
+from django.utils.functional import lazy
+from django.utils.unittest import skipIf
-from .models import (Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post,
- NullBooleanModel, BooleanModel, DataModel, Document, RenamedField,
+from .models import (
+ Foo, Bar, Whiz, BigD, BigS, BigInt, Post, NullBooleanModel,
+ BooleanModel, DataModel, Document, RenamedField,
VerboseNameField, FksToBooleans)
@@ -64,7 +74,7 @@ class BasicFieldTests(test.TestCase):
m = VerboseNameField
for i in range(1, 23):
self.assertEqual(m._meta.get_field('field%d' % i).verbose_name,
- 'verbose field%d' % i)
+ 'verbose field%d' % i)
self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk')
@@ -290,9 +300,9 @@ class SlugFieldTests(test.TestCase):
"""
Make sure SlugField honors max_length (#9706)
"""
- bs = BigS.objects.create(s = 'slug'*50)
+ bs = BigS.objects.create(s='slug' * 50)
bs = BigS.objects.get(pk=bs.pk)
- self.assertEqual(bs.s, 'slug'*50)
+ self.assertEqual(bs.s, 'slug' * 50)
class ValidationTest(test.TestCase):
@@ -313,15 +323,21 @@ class ValidationTest(test.TestCase):
self.assertRaises(ValidationError, f.clean, "a", None)
def test_charfield_with_choices_cleans_valid_choice(self):
- f = models.CharField(max_length=1, choices=[('a','A'), ('b','B')])
+ f = models.CharField(max_length=1,
+ choices=[('a', 'A'), ('b', 'B')])
self.assertEqual('a', f.clean('a', None))
def test_charfield_with_choices_raises_error_on_invalid_choice(self):
- f = models.CharField(choices=[('a','A'), ('b','B')])
+ f = models.CharField(choices=[('a', 'A'), ('b', 'B')])
self.assertRaises(ValidationError, f.clean, "not a", None)
+ def test_charfield_get_choices_with_blank_defined(self):
+ f = models.CharField(choices=[('', '<><>'), ('a', 'A')])
+ self.assertEqual(f.get_choices(True), [('', '<><>'), ('a', 'A')])
+
def test_choices_validation_supports_named_groups(self):
- f = models.IntegerField(choices=(('group',((10,'A'),(20,'B'))),(30,'C')))
+ f = models.IntegerField(
+ choices=(('group', ((10, 'A'), (20, 'B'))), (30, 'C')))
self.assertEqual(10, f.clean(10, None))
def test_nullable_integerfield_raises_error_with_blank_false(self):
@@ -370,7 +386,7 @@ class BigIntegerFieldTests(test.TestCase):
self.assertEqual(qs[0].value, minval)
def test_types(self):
- b = BigInt(value = 0)
+ b = BigInt(value=0)
self.assertIsInstance(b.value, six.integer_types)
b.save()
self.assertIsInstance(b.value, six.integer_types)
@@ -378,8 +394,8 @@ class BigIntegerFieldTests(test.TestCase):
self.assertIsInstance(b.value, six.integer_types)
def test_coercing(self):
- BigInt.objects.create(value ='10')
- b = BigInt.objects.get(value = '10')
+ BigInt.objects.create(value='10')
+ b = BigInt.objects.get(value='10')
self.assertEqual(b.value, 10)
class TypeCoercionTests(test.TestCase):
@@ -466,7 +482,7 @@ class BinaryFieldTests(test.TestCase):
test_set_and_retrieve = unittest.expectedFailure(test_set_and_retrieve)
def test_max_length(self):
- dm = DataModel(short_data=self.binary_data*4)
+ dm = DataModel(short_data=self.binary_data * 4)
self.assertRaises(ValidationError, dm.full_clean)
class GenericIPAddressFieldTests(test.TestCase):
@@ -481,3 +497,156 @@ class GenericIPAddressFieldTests(test.TestCase):
model_field = models.GenericIPAddressField(protocol='IPv6')
form_field = model_field.formfield()
self.assertRaises(ValidationError, form_field.clean, '127.0.0.1')
+
+
+class PromiseTest(test.TestCase):
+ def test_AutoField(self):
+ lazy_func = lazy(lambda: 1, int)
+ self.assertIsInstance(
+ AutoField(primary_key=True).get_prep_value(lazy_func()),
+ int)
+
+ @skipIf(six.PY3, "Python 3 has no `long` type.")
+ def test_BigIntegerField(self):
+ lazy_func = lazy(lambda: long(9999999999999999999), long)
+ self.assertIsInstance(
+ BigIntegerField().get_prep_value(lazy_func()),
+ long)
+
+ def test_BinaryField(self):
+ lazy_func = lazy(lambda: b'', bytes)
+ self.assertIsInstance(
+ BinaryField().get_prep_value(lazy_func()),
+ bytes)
+
+ def test_BooleanField(self):
+ lazy_func = lazy(lambda: True, bool)
+ self.assertIsInstance(
+ BooleanField().get_prep_value(lazy_func()),
+ bool)
+
+ def test_CharField(self):
+ lazy_func = lazy(lambda: '', six.text_type)
+ self.assertIsInstance(
+ CharField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_CommaSeparatedIntegerField(self):
+ lazy_func = lazy(lambda: '1,2', six.text_type)
+ self.assertIsInstance(
+ CommaSeparatedIntegerField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_DateField(self):
+ lazy_func = lazy(lambda: datetime.date.today(), datetime.date)
+ self.assertIsInstance(
+ DateField().get_prep_value(lazy_func()),
+ datetime.date)
+
+ def test_DateTimeField(self):
+ lazy_func = lazy(lambda: datetime.datetime.now(), datetime.datetime)
+ self.assertIsInstance(
+ DateTimeField().get_prep_value(lazy_func()),
+ datetime.datetime)
+
+ def test_DecimalField(self):
+ lazy_func = lazy(lambda: Decimal('1.2'), Decimal)
+ self.assertIsInstance(
+ DecimalField().get_prep_value(lazy_func()),
+ Decimal)
+
+ def test_EmailField(self):
+ lazy_func = lazy(lambda: 'mailbox@domain.com', six.text_type)
+ self.assertIsInstance(
+ EmailField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_FileField(self):
+ lazy_func = lazy(lambda: 'filename.ext', six.text_type)
+ self.assertIsInstance(
+ FileField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_FilePathField(self):
+ lazy_func = lazy(lambda: 'tests.py', six.text_type)
+ self.assertIsInstance(
+ FilePathField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_FloatField(self):
+ lazy_func = lazy(lambda: 1.2, float)
+ self.assertIsInstance(
+ FloatField().get_prep_value(lazy_func()),
+ float)
+
+ def test_ImageField(self):
+ lazy_func = lazy(lambda: 'filename.ext', six.text_type)
+ self.assertIsInstance(
+ ImageField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_IntegerField(self):
+ lazy_func = lazy(lambda: 1, int)
+ self.assertIsInstance(
+ IntegerField().get_prep_value(lazy_func()),
+ int)
+
+ def test_IPAddressField(self):
+ lazy_func = lazy(lambda: '127.0.0.1', six.text_type)
+ self.assertIsInstance(
+ IPAddressField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_GenericIPAddressField(self):
+ lazy_func = lazy(lambda: '127.0.0.1', six.text_type)
+ self.assertIsInstance(
+ GenericIPAddressField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_NullBooleanField(self):
+ lazy_func = lazy(lambda: True, bool)
+ self.assertIsInstance(
+ NullBooleanField().get_prep_value(lazy_func()),
+ bool)
+
+ def test_PositiveIntegerField(self):
+ lazy_func = lazy(lambda: 1, int)
+ self.assertIsInstance(
+ PositiveIntegerField().get_prep_value(lazy_func()),
+ int)
+
+ def test_PositiveSmallIntegerField(self):
+ lazy_func = lazy(lambda: 1, int)
+ self.assertIsInstance(
+ PositiveSmallIntegerField().get_prep_value(lazy_func()),
+ int)
+
+ def test_SlugField(self):
+ lazy_func = lazy(lambda: 'slug', six.text_type)
+ self.assertIsInstance(
+ SlugField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_SmallIntegerField(self):
+ lazy_func = lazy(lambda: 1, int)
+ self.assertIsInstance(
+ SmallIntegerField().get_prep_value(lazy_func()),
+ int)
+
+ def test_TextField(self):
+ lazy_func = lazy(lambda: 'Abc', six.text_type)
+ self.assertIsInstance(
+ TextField().get_prep_value(lazy_func()),
+ six.text_type)
+
+ def test_TimeField(self):
+ lazy_func = lazy(lambda: datetime.datetime.now().time(), datetime.time)
+ self.assertIsInstance(
+ TimeField().get_prep_value(lazy_func()),
+ datetime.time)
+
+ def test_URLField(self):
+ lazy_func = lazy(lambda: 'http://domain.com', six.text_type)
+ self.assertIsInstance(
+ URLField().get_prep_value(lazy_func()),
+ six.text_type)
diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py
index a4cf9471de..17aec29055 100644
--- a/tests/model_forms/models.py
+++ b/tests/model_forms/models.py
@@ -12,7 +12,7 @@ import os
import tempfile
from django.core import validators
-from django.core.exceptions import ImproperlyConfigured
+from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.files.storage import FileSystemStorage
from django.db import models
from django.utils import six
@@ -296,3 +296,7 @@ class CustomErrorMessage(models.Model):
name2 = models.CharField(max_length=50,
validators=[validators.validate_slug],
error_messages={'invalid': 'Model custom error message.'})
+
+ def clean(self):
+ if self.name1 == 'FORBIDDEN_VALUE':
+ raise ValidationError({'name1': [ValidationError('Model.clean() error messages.')]})
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index 09c62c5205..1404725484 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import os
@@ -1782,6 +1782,14 @@ class OldFormForXTests(TestCase):
'<ul class="errorlist"><li>Model custom error message.</li></ul>'
)
+ def test_model_clean_error_messages(self) :
+ data = {'name1': 'FORBIDDEN_VALUE', 'name2': 'ABC'}
+ errors = CustomErrorMessageForm(data).errors
+ self.assertHTMLEqual(
+ str(errors['name1']),
+ '<ul class="errorlist"><li>Model.clean() error messages.</li></ul>'
+ )
+
class M2mHelpTextTest(TestCase):
"""Tests for ticket #9321."""
diff --git a/tests/model_forms_regress/tests.py b/tests/model_forms_regress/tests.py
index 35e706ac4c..ffe1123b99 100644
--- a/tests/model_forms_regress/tests.py
+++ b/tests/model_forms_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import date
import unittest
diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py
index 4411bbf59a..053448181a 100644
--- a/tests/model_formsets/tests.py
+++ b/tests/model_formsets/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import re
@@ -32,6 +32,9 @@ class DeletionTests(TestCase):
'form-0-DELETE': 'on',
}
formset = PoetFormSet(data, queryset=Poet.objects.all())
+ formset.save(commit=False)
+ self.assertEqual(Poet.objects.count(), 1)
+
formset.save()
self.assertTrue(formset.is_valid())
self.assertEqual(Poet.objects.count(), 0)
@@ -388,7 +391,7 @@ class ModelFormsetTest(TestCase):
def test_custom_queryset_init(self):
"""
- Test that a queryset can be overriden in the __init__ method.
+ Test that a queryset can be overridden in the __init__ method.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#changing-the-queryset
"""
author1 = Author.objects.create(name='Charles Baudelaire')
diff --git a/tests/model_formsets_regress/tests.py b/tests/model_formsets_regress/tests.py
index 179f79fbcb..782c7d6fbc 100644
--- a/tests/model_formsets_regress/tests.py
+++ b/tests/model_formsets_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django import forms
from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index dc40d2d2e0..eb50d30cf8 100644
--- a/tests/model_inheritance/tests.py
+++ b/tests/model_inheritance/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/model_inheritance_regress/tests.py b/tests/model_inheritance_regress/tests.py
index 7ca16647fa..10a1230685 100644
--- a/tests/model_inheritance_regress/tests.py
+++ b/tests/model_inheritance_regress/tests.py
@@ -1,7 +1,7 @@
"""
Regression tests for Model inheritance behavior.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
from operator import attrgetter
diff --git a/tests/model_inheritance_same_model_name/models.py b/tests/model_inheritance_same_model_name/models.py
index b4a6b930df..8b02b08668 100644
--- a/tests/model_inheritance_same_model_name/models.py
+++ b/tests/model_inheritance_same_model_name/models.py
@@ -6,8 +6,6 @@ in the need for an %(app_label)s format string. This app specifically tests
this feature by redefining the Copy model from model_inheritance/models.py
"""
-from __future__ import absolute_import
-
from django.db import models
from model_inheritance.models import NamedURL
diff --git a/tests/model_inheritance_same_model_name/tests.py b/tests/model_inheritance_same_model_name/tests.py
index 8f22578013..fe1fb0cdd2 100644
--- a/tests/model_inheritance_same_model_name/tests.py
+++ b/tests/model_inheritance_same_model_name/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/model_inheritance_select_related/tests.py b/tests/model_inheritance_select_related/tests.py
index 078b466d0e..68f9897e25 100644
--- a/tests/model_inheritance_select_related/tests.py
+++ b/tests/model_inheritance_select_related/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/model_package/models/__init__.py b/tests/model_package/models/__init__.py
index 3c261aa444..ec29d667f9 100644
--- a/tests/model_package/models/__init__.py
+++ b/tests/model_package/models/__init__.py
@@ -1,5 +1,3 @@
# Import all the models from subpackages
-from __future__ import absolute_import
-
from .article import Article
from .publication import Publication
diff --git a/tests/model_package/tests.py b/tests/model_package/tests.py
index 5d856a9608..a352b57478 100644
--- a/tests/model_package/tests.py
+++ b/tests/model_package/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.contrib.sites.models import Site
from django.db import models
diff --git a/tests/model_permalink/tests.py b/tests/model_permalink/tests.py
index 257648ca5f..ef682ed0e8 100644
--- a/tests/model_permalink/tests.py
+++ b/tests/model_permalink/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.test import TestCase
from .models import Guitarist
diff --git a/tests/model_regress/tests.py b/tests/model_regress/tests.py
index 2924b220e6..f84a40b05b 100644
--- a/tests/model_regress/tests.py
+++ b/tests/model_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
from operator import attrgetter
diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py
index 0d0fed394a..424588cf49 100644
--- a/tests/modeladmin/tests.py
+++ b/tests/modeladmin/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import date
import unittest
@@ -51,6 +51,12 @@ class ModelAdminTests(TestCase):
self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'bio', 'sign_date'])
+ self.assertEqual(list(ma.get_fields(request)),
+ ['name', 'bio', 'sign_date'])
+
+ self.assertEqual(list(ma.get_fields(request, self.band)),
+ ['name', 'bio', 'sign_date'])
+
def test_default_fieldsets(self):
# fieldsets_add and fieldsets_change should return a special data structure that
# is used in the templates. They should generate the "right thing" whether we
@@ -97,6 +103,10 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
+ self.assertEqual(list(ma.get_fields(request)), ['name'])
+
+ self.assertEqual(list(ma.get_fields(request, self.band)), ['name'])
+
self.assertEqual(ma.get_fieldsets(request),
[(None, {'fields': ['name']})])
diff --git a/tests/multiple_database/models.py b/tests/multiple_database/models.py
index e46438649b..00534c870c 100644
--- a/tests/multiple_database/models.py
+++ b/tests/multiple_database/models.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
diff --git a/tests/multiple_database/tests.py b/tests/multiple_database/tests.py
index e65fa4e19d..629cb1237c 100644
--- a/tests/multiple_database/tests.py
+++ b/tests/multiple_database/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import pickle
diff --git a/tests/mutually_referential/tests.py b/tests/mutually_referential/tests.py
index b3deb0e75c..6006465843 100644
--- a/tests/mutually_referential/tests.py
+++ b/tests/mutually_referential/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.test import TestCase
from .models import Parent
diff --git a/tests/nested_foreign_keys/tests.py b/tests/nested_foreign_keys/tests.py
index 5cb23cfb9c..e8e20762fe 100644
--- a/tests/nested_foreign_keys/tests.py
+++ b/tests/nested_foreign_keys/tests.py
@@ -1,4 +1,5 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
+
from django.test import TestCase
from .models import Person, Movie, Event, Screening, ScreeningNullFK, Package, PackageNullFK
diff --git a/tests/null_fk/tests.py b/tests/null_fk/tests.py
index 96a06b6769..29e1fcb4bb 100644
--- a/tests/null_fk/tests.py
+++ b/tests/null_fk/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.db.models import Q
from django.test import TestCase
diff --git a/tests/null_fk_ordering/tests.py b/tests/null_fk_ordering/tests.py
index aea969de4f..70873244ac 100644
--- a/tests/null_fk_ordering/tests.py
+++ b/tests/null_fk_ordering/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/null_queries/tests.py b/tests/null_queries/tests.py
index 93e72d55d8..d08c9979d7 100644
--- a/tests/null_queries/tests.py
+++ b/tests/null_queries/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
from django.core.exceptions import FieldError
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py
index a36764b788..6e16d81cea 100644
--- a/tests/one_to_one/tests.py
+++ b/tests/one_to_one/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import transaction, IntegrityError
from django.test import TestCase
diff --git a/tests/one_to_one_regress/tests.py b/tests/one_to_one_regress/tests.py
index 615536ba38..7d82194abb 100644
--- a/tests/one_to_one_regress/tests.py
+++ b/tests/one_to_one_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/or_lookups/tests.py b/tests/or_lookups/tests.py
index e1c6fcb32a..264d999575 100644
--- a/tests/or_lookups/tests.py
+++ b/tests/or_lookups/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
from operator import attrgetter
diff --git a/tests/order_with_respect_to/tests.py b/tests/order_with_respect_to/tests.py
index 559cb1d996..155c238617 100644
--- a/tests/order_with_respect_to/tests.py
+++ b/tests/order_with_respect_to/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from operator import attrgetter
diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py
index b1b5253682..63161a3273 100644
--- a/tests/ordering/tests.py
+++ b/tests/ordering/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import datetime
from operator import attrgetter
diff --git a/tests/pagination/tests.py b/tests/pagination/tests.py
index 76799bec46..46ea428d17 100644
--- a/tests/pagination/tests.py
+++ b/tests/pagination/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from datetime import datetime
import unittest
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index 2e3fee6be6..9d5a5290da 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
from django.db import connection
diff --git a/tests/properties/tests.py b/tests/properties/tests.py
index 8a40d06e98..c471c414a1 100644
--- a/tests/properties/tests.py
+++ b/tests/properties/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/proxy_model_inheritance/app1/models.py b/tests/proxy_model_inheritance/app1/models.py
index affcf140ac..a7a99fe46b 100644
--- a/tests/proxy_model_inheritance/app1/models.py
+++ b/tests/proxy_model_inheritance/app1/models.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
# TODO: why can't I make this ..app2
from app2.models import NiceModel
diff --git a/tests/proxy_model_inheritance/tests.py b/tests/proxy_model_inheritance/tests.py
index 85bf74a4e9..dda09a080f 100644
--- a/tests/proxy_model_inheritance/tests.py
+++ b/tests/proxy_model_inheritance/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import os
import sys
diff --git a/tests/proxy_models/tests.py b/tests/proxy_models/tests.py
index 5cc5ef5478..240198cc39 100644
--- a/tests/proxy_models/tests.py
+++ b/tests/proxy_models/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import copy
from django.conf import settings
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 87d54b637e..6e03b0d7f6 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -1,5 +1,6 @@
-from __future__ import absolute_import,unicode_literals
+from __future__ import unicode_literals
+from collections import OrderedDict
import datetime
from operator import attrgetter
import pickle
@@ -14,7 +15,6 @@ from django.db.models.sql.where import WhereNode, EverythingNode, NothingNode
from django.db.models.sql.datastructures import EmptyResultSet
from django.test import TestCase, skipUnlessDBFeature
from django.test.utils import str_prefix
-from django.utils.datastructures import SortedDict
from .models import (
Annotation, Article, Author, Celebrity, Child, Cover, Detail, DumbCategory,
@@ -499,7 +499,7 @@ class Queries1Tests(BaseQuerysetTest):
)
def test_ticket2902(self):
- # Parameters can be given to extra_select, *if* you use a SortedDict.
+ # Parameters can be given to extra_select, *if* you use an OrderedDict.
# (First we need to know which order the keys fall in "naturally" on
# your system, so we can put things in the wrong way around from
@@ -513,7 +513,7 @@ class Queries1Tests(BaseQuerysetTest):
# This slightly odd comparison works around the fact that PostgreSQL will
# return 'one' and 'two' as strings, not Unicode objects. It's a side-effect of
# using constants here and not a real concern.
- d = Item.objects.extra(select=SortedDict(s), select_params=params).values('a', 'b')[0]
+ d = Item.objects.extra(select=OrderedDict(s), select_params=params).values('a', 'b')[0]
self.assertEqual(d, {'a': 'one', 'b': 'two'})
# Order by the number of tags attached to an item.
@@ -789,7 +789,7 @@ class Queries1Tests(BaseQuerysetTest):
)
def test_ticket7181(self):
- # Ordering by related tables should accomodate nullable fields (this
+ # Ordering by related tables should accommodate nullable fields (this
# test is a little tricky, since NULL ordering is database dependent.
# Instead, we just count the number of results).
self.assertEqual(len(Tag.objects.order_by('parent__name')), 5)
@@ -1987,7 +1987,7 @@ class ValuesQuerysetTests(BaseQuerysetTest):
def test_extra_values(self):
# testing for ticket 14930 issues
- qs = Number.objects.extra(select=SortedDict([('value_plus_x', 'num+%s'),
+ qs = Number.objects.extra(select=OrderedDict([('value_plus_x', 'num+%s'),
('value_minus_x', 'num-%s')]),
select_params=(1, 2))
qs = qs.order_by('value_minus_x')
@@ -2910,7 +2910,7 @@ class DoubleInSubqueryTests(TestCase):
self.assertQuerysetEqual(
qs, [lfb1], lambda x: x)
-class Ticket18785Tests(unittest.TestCase):
+class Ticket18785Tests(TestCase):
def test_ticket_18785(self):
# Test join trimming from ticket18785
qs = Item.objects.exclude(
@@ -2920,3 +2920,38 @@ class Ticket18785Tests(unittest.TestCase):
).order_by()
self.assertEqual(1, str(qs.query).count('INNER JOIN'))
self.assertEqual(0, str(qs.query).count('OUTER JOIN'))
+
+
+class Ticket20788Tests(TestCase):
+ def test_ticket_20788(self):
+ Paragraph.objects.create()
+ paragraph = Paragraph.objects.create()
+ page = paragraph.page.create()
+ chapter = Chapter.objects.create(paragraph=paragraph)
+ Book.objects.create(chapter=chapter)
+
+ paragraph2 = Paragraph.objects.create()
+ Page.objects.create()
+ chapter2 = Chapter.objects.create(paragraph=paragraph2)
+ book2 = Book.objects.create(chapter=chapter2)
+
+ sentences_not_in_pub = Book.objects.exclude(
+ chapter__paragraph__page=page)
+ self.assertQuerysetEqual(
+ sentences_not_in_pub, [book2], lambda x: x)
+
+class RelatedLookupTypeTests(TestCase):
+ def test_wrong_type_lookup(self):
+ oa = ObjectA.objects.create(name="oa")
+ wrong_type = Order.objects.create(id=oa.pk)
+ ob = ObjectB.objects.create(name="ob", objecta=oa, num=1)
+ # Currently Django doesn't care if the object is of correct
+ # type, it will just use the objecta's related fields attribute
+ # (id) for model lookup. Making things more restrictive could
+ # be a good idea...
+ self.assertQuerysetEqual(
+ ObjectB.objects.filter(objecta=wrong_type),
+ [ob], lambda x: x)
+ self.assertQuerysetEqual(
+ ObjectB.objects.filter(objecta__in=[wrong_type]),
+ [ob], lambda x: x)
diff --git a/tests/queryset_pickle/models.py b/tests/queryset_pickle/models.py
index 3a8973505c..dacd5018da 100644
--- a/tests/queryset_pickle/models.py
+++ b/tests/queryset_pickle/models.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
import datetime
from django.db import models
diff --git a/tests/queryset_pickle/tests.py b/tests/queryset_pickle/tests.py
index b4b540c80d..384073ad56 100644
--- a/tests/queryset_pickle/tests.py
+++ b/tests/queryset_pickle/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import pickle
import datetime
@@ -83,10 +83,14 @@ class PickleabilityTestCase(TestCase):
def test_model_pickle_dynamic(self):
class Meta:
proxy = True
- dynclass = type("DynamicEventSubclass", (Event, ),
+ dynclass = type(str("DynamicEventSubclass"), (Event, ),
{'Meta': Meta, '__module__': Event.__module__})
original = dynclass(pk=1)
dumped = pickle.dumps(original)
reloaded = pickle.loads(dumped)
self.assertEqual(original, reloaded)
self.assertIs(reloaded.__class__, dynclass)
+
+ def test_specialized_queryset(self):
+ self.assert_pickles(Happening.objects.values('name'))
+ self.assert_pickles(Happening.objects.values('name').dates('when', 'year'))
diff --git a/tests/raw_query/tests.py b/tests/raw_query/tests.py
index 7242b8309b..06c9b11230 100644
--- a/tests/raw_query/tests.py
+++ b/tests/raw_query/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from datetime import date
diff --git a/tests/requests/tests.py b/tests/requests/tests.py
index 8c56e48f58..5bd3e5141f 100644
--- a/tests/requests/tests.py
+++ b/tests/requests/tests.py
@@ -620,12 +620,20 @@ class HostValidationTests(SimpleTestCase):
}
self.assertEqual(request.get_host(), 'example.com')
+ # Invalid hostnames would normally raise a SuspiciousOperation,
+ # but we have DEBUG=True, so this check is disabled.
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': "invalid_hostname.com",
+ }
+ self.assertEqual(request.get_host(), "invalid_hostname.com")
@override_settings(ALLOWED_HOSTS=[])
def test_get_host_suggestion_of_allowed_host(self):
"""get_host() makes helpful suggestions if a valid-looking host is not in ALLOWED_HOSTS."""
msg_invalid_host = "Invalid HTTP_HOST header: %r."
msg_suggestion = msg_invalid_host + "You may need to add %r to ALLOWED_HOSTS."
+ msg_suggestion2 = msg_invalid_host + "The domain name provided is not valid according to RFC 1034/1035"
for host in [ # Valid-looking hosts
'example.com',
@@ -664,6 +672,14 @@ class HostValidationTests(SimpleTestCase):
request.get_host
)
+ request = HttpRequest()
+ request.META = {'HTTP_HOST': "invalid_hostname.com"}
+ self.assertRaisesMessage(
+ SuspiciousOperation,
+ msg_suggestion2 % "invalid_hostname.com",
+ request.get_host
+ )
+
@skipIf(connection.vendor == 'sqlite'
and connection.settings_dict['TEST_NAME'] in (None, '', ':memory:'),
diff --git a/tests/reserved_names/tests.py b/tests/reserved_names/tests.py
index ddffe08d34..cdf81b8477 100644
--- a/tests/reserved_names/tests.py
+++ b/tests/reserved_names/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import datetime
diff --git a/tests/reverse_lookup/tests.py b/tests/reverse_lookup/tests.py
index 549ee66392..ca16db0d31 100644
--- a/tests/reverse_lookup/tests.py
+++ b/tests/reverse_lookup/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.core.exceptions import FieldError
from django.test import TestCase
diff --git a/tests/reverse_single_related/tests.py b/tests/reverse_single_related/tests.py
index 0c755c4db6..472a3026b6 100644
--- a/tests/reverse_single_related/tests.py
+++ b/tests/reverse_single_related/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.test import TestCase
from .models import Source, Item
diff --git a/tests/runtests.py b/tests/runtests.py
index 8d5b375fb3..53318a7461 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -7,6 +7,20 @@ import sys
import tempfile
import warnings
+def upath(path):
+ """
+ Separate version of django.utils._os.upath. The django.utils version isn't
+ usable here, as upath is needed for RUNTESTS_DIR which is needed before
+ django can be imported.
+ """
+ if sys.version_info[0] != 3 and not isinstance(path, bytes):
+ fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
+ return path.decode(fs_encoding)
+ return path
+
+RUNTESTS_DIR = os.path.abspath(os.path.dirname(upath(__file__)))
+sys.path.insert(0, os.path.dirname(RUNTESTS_DIR)) # 'tests/../'
+
from django import contrib
from django.utils._os import upath
from django.utils import six
@@ -15,7 +29,6 @@ CONTRIB_MODULE_PATH = 'django.contrib'
TEST_TEMPLATE_DIR = 'templates'
-RUNTESTS_DIR = os.path.abspath(os.path.dirname(upath(__file__)))
CONTRIB_DIR = os.path.dirname(upath(contrib.__file__))
TEMP_DIR = tempfile.mkdtemp(prefix='django_')
@@ -331,10 +344,9 @@ if __name__ == "__main__":
options, args = parser.parse_args()
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
- elif "DJANGO_SETTINGS_MODULE" not in os.environ:
- parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. "
- "Set it or use --settings.")
else:
+ if "DJANGO_SETTINGS_MODULE" not in os.environ:
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'test_sqlite'
options.settings = os.environ['DJANGO_SETTINGS_MODULE']
if options.liveserver is not None:
diff --git a/tests/save_delete_hooks/tests.py b/tests/save_delete_hooks/tests.py
index 42e0d4a80e..0fd1ed4e03 100644
--- a/tests/save_delete_hooks/tests.py
+++ b/tests/save_delete_hooks/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index 3204d74224..f9e7e96ac1 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -1,15 +1,17 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import sys
import time
import unittest
from django.conf import settings
-from django.db import transaction, connection
+from django.db import transaction, connection, router
from django.db.utils import ConnectionHandler, DEFAULT_DB_ALIAS, DatabaseError
from django.test import (TransactionTestCase, skipIfDBFeature,
skipUnlessDBFeature)
+from multiple_database.tests import TestRouter
+
from .models import Person
# Some tests require threading, which might not be available. So create a
@@ -254,3 +256,13 @@ class SelectForUpdateTests(TransactionTestCase):
"""
people = list(Person.objects.select_for_update())
self.assertTrue(transaction.is_dirty())
+
+ @skipUnlessDBFeature('has_select_for_update')
+ def test_select_for_update_on_multidb(self):
+ old_routers = router.routers
+ try:
+ router.routers = [TestRouter()]
+ query = Person.objects.select_for_update()
+ self.assertEqual(router.db_for_write(Person), query.db)
+ finally:
+ router.routers = old_routers
diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py
index e6723eac9b..f07e28df99 100644
--- a/tests/select_related/tests.py
+++ b/tests/select_related/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.test import TestCase
diff --git a/tests/select_related_onetoone/tests.py b/tests/select_related_onetoone/tests.py
index d8ba4d0484..3942b2d221 100644
--- a/tests/select_related_onetoone/tests.py
+++ b/tests/select_related_onetoone/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import unittest
diff --git a/tests/select_related_regress/tests.py b/tests/select_related_regress/tests.py
index f6d21b2dd9..da47cb771f 100644
--- a/tests/select_related_regress/tests.py
+++ b/tests/select_related_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py
index bff7c53249..07c220c52e 100644
--- a/tests/serializers/tests.py
+++ b/tests/serializers/tests.py
@@ -1,6 +1,6 @@
-from __future__ import absolute_import, unicode_literals
-
# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
import json
from datetime import datetime
import unittest
diff --git a/tests/serializers_regress/tests.py b/tests/serializers_regress/tests.py
index 1751816cee..3173f73985 100644
--- a/tests/serializers_regress/tests.py
+++ b/tests/serializers_regress/tests.py
@@ -6,7 +6,7 @@ test case that is capable of testing the capabilities of
the serializers. This includes all valid data values, plus
forward, backwards and self references.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import decimal
diff --git a/tests/servers/tests.py b/tests/servers/tests.py
index be74afe820..1f02a88d5a 100644
--- a/tests/servers/tests.py
+++ b/tests/servers/tests.py
@@ -113,7 +113,7 @@ class LiveServerAddress(LiveServerBase):
def test_test_test(self):
# Intentionally empty method so that the test is picked up by the
- # test runner and the overriden setUpClass() method is executed.
+ # test runner and the overridden setUpClass() method is executed.
pass
class LiveServerViews(LiveServerBase):
diff --git a/tests/servers/urls.py b/tests/servers/urls.py
index a857c45f95..03393c30ec 100644
--- a/tests/servers/urls.py
+++ b/tests/servers/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from . import views
diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py
index 87ed4d4f5e..4031d09a58 100644
--- a/tests/settings_tests/tests.py
+++ b/tests/settings_tests/tests.py
@@ -163,7 +163,7 @@ class SettingsTests(TestCase):
def test_override_settings_delete(self):
"""
- Allow deletion of a setting in an overriden settings set (#18824)
+ Allow deletion of a setting in an overridden settings set (#18824)
"""
previous_i18n = settings.USE_I18N
with self.settings(USE_I18N=False):
@@ -226,6 +226,27 @@ class TestComplexSettingOverride(TestCase):
self.assertEqual('Overriding setting TEST_WARN can lead to unexpected behaviour.', str(w[-1].message))
+class UniqueSettngsTests(TestCase):
+ """
+ Tests for the INSTALLED_APPS setting.
+ """
+ settings_module = settings
+
+ def setUp(self):
+ self._installed_apps = self.settings_module.INSTALLED_APPS
+
+ def tearDown(self):
+ self.settings_module.INSTALLED_APPS = self._installed_apps
+
+ def test_unique(self):
+ """
+ An ImproperlyConfigured exception is raised if the INSTALLED_APPS contains
+ any duplicate strings.
+ """
+ with self.assertRaises(ImproperlyConfigured):
+ self.settings_module.INSTALLED_APPS = ("myApp1", "myApp1", "myApp2", "myApp3")
+
+
class TrailingSlashURLTests(TestCase):
"""
Tests for the MEDIA_URL and STATIC_URL settings.
diff --git a/tests/signals/tests.py b/tests/signals/tests.py
index 58f25c2868..1dfe72bf5f 100644
--- a/tests/signals/tests.py
+++ b/tests/signals/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db.models import signals
from django.dispatch import receiver
diff --git a/tests/signals_regress/tests.py b/tests/signals_regress/tests.py
index 8fb3ad5a48..2c9858efda 100644
--- a/tests/signals_regress/tests.py
+++ b/tests/signals_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import models
from django.test import TestCase
diff --git a/tests/sites_framework/tests.py b/tests/sites_framework/tests.py
index 8e664fd501..7860394aa2 100644
--- a/tests/sites_framework/tests.py
+++ b/tests/sites_framework/tests.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf import settings
from django.contrib.sites.models import Site
from django.test import TestCase
diff --git a/tests/staticfiles_tests/tests.py b/tests/staticfiles_tests/tests.py
index 912dcffe83..7200037050 100644
--- a/tests/staticfiles_tests/tests.py
+++ b/tests/staticfiles_tests/tests.py
@@ -650,8 +650,7 @@ class TestServeDisabled(TestServeStatic):
settings.DEBUG = False
def test_disabled_serving(self):
- six.assertRaisesRegex(self, ImproperlyConfigured, 'The staticfiles view '
- 'can only be used in debug mode ', self._response, 'test.txt')
+ self.assertFileNotFound('test.txt')
class TestServeStaticWithDefaultURL(TestServeStatic, TestDefaults):
@@ -774,3 +773,33 @@ class TestTemplateTag(StaticFilesTestCase):
self.assertStaticRenders("does/not/exist.png",
"/static/does/not/exist.png")
self.assertStaticRenders("testfile.txt", "/static/testfile.txt")
+
+
+class TestAppStaticStorage(TestCase):
+ def setUp(self):
+ # Creates a python module foo_module in a directory with non ascii
+ # characters
+ self.search_path = 'search_path_\xc3\xbc'
+ os.mkdir(self.search_path)
+ module_path = os.path.join(self.search_path, 'foo_module')
+ os.mkdir(module_path)
+ open(os.path.join(module_path, '__init__.py'), 'w')
+ sys.path.append(os.path.abspath(self.search_path))
+
+ def tearDown(self):
+ sys.path.remove(os.path.abspath(self.search_path))
+ shutil.rmtree(self.search_path)
+
+ def test_app_with_non_ascii_characters_in_path(self):
+ """
+ Regression test for #18404 - Tests AppStaticStorage with a module that
+ has non ascii characters in path and a non utf8 file system encoding
+ """
+ # set file system encoding to a non unicode encoding
+ old_enc_func = sys.getfilesystemencoding
+ sys.getfilesystemencoding = lambda: 'ISO-8859-1'
+ try:
+ st = storage.AppStaticStorage('foo_module')
+ st.path('bar')
+ finally:
+ sys.getfilesystemencoding = old_enc_func
diff --git a/tests/str/tests.py b/tests/str/tests.py
index d82908a0ee..3c0bc079c8 100644
--- a/tests/str/tests.py
+++ b/tests/str/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
from unittest import skipIf
diff --git a/tests/string_lookup/tests.py b/tests/string_lookup/tests.py
index b011720ddf..5a17e55560 100644
--- a/tests/string_lookup/tests.py
+++ b/tests/string_lookup/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.test import TestCase
from .models import Foo, Whiz, Bar, Article, Base, Child
@@ -80,4 +80,4 @@ class StringLookupTests(TestCase):
self.assertEqual(repr(Article.objects.filter(submitted_from__contains='192.0.2')),
repr([a]))
# Test that the searches do not match the subnet mask (/32 in this case)
- self.assertEqual(Article.objects.filter(submitted_from__contains='32').count(), 0) \ No newline at end of file
+ self.assertEqual(Article.objects.filter(submitted_from__contains='32').count(), 0)
diff --git a/tests/swappable_models/tests.py b/tests/swappable_models/tests.py
index 858061db23..2e2d544cea 100644
--- a/tests/swappable_models/tests.py
+++ b/tests/swappable_models/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.utils.six import StringIO
diff --git a/tests/syndication/feeds.py b/tests/syndication/feeds.py
index 1cd5c3d988..f8ffb4b2e6 100644
--- a/tests/syndication/feeds.py
+++ b/tests/syndication/feeds.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.syndication import views
from django.core.exceptions import ObjectDoesNotExist
diff --git a/tests/syndication/tests.py b/tests/syndication/tests.py
index d3b0058d53..8bc6b04939 100644
--- a/tests/syndication/tests.py
+++ b/tests/syndication/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from xml.dom import minidom
diff --git a/tests/syndication/urls.py b/tests/syndication/urls.py
index 06a75a4e68..1b5d77f2e1 100644
--- a/tests/syndication/urls.py
+++ b/tests/syndication/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from . import feeds
diff --git a/tests/tablespaces/tests.py b/tests/tablespaces/tests.py
index 1eaddef079..088938ca1d 100644
--- a/tests/tablespaces/tests.py
+++ b/tests/tablespaces/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import copy
diff --git a/tests/template_tests/alternate_urls.py b/tests/template_tests/alternate_urls.py
index fa4985a9dc..3c6a4e62f9 100644
--- a/tests/template_tests/alternate_urls.py
+++ b/tests/template_tests/alternate_urls.py
@@ -1,7 +1,3 @@
-# coding: utf-8
-
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from . import views
diff --git a/tests/template_tests/test_custom.py b/tests/template_tests/test_custom.py
index e941bc223e..c2dff03b10 100644
--- a/tests/template_tests/test_custom.py
+++ b/tests/template_tests/test_custom.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from unittest import TestCase
diff --git a/tests/template_tests/loaders.py b/tests/template_tests/test_loaders.py
index 497b422e7f..6fd17fd04b 100644
--- a/tests/template_tests/loaders.py
+++ b/tests/template_tests/test_loaders.py
@@ -11,10 +11,15 @@ if __name__ == '__main__':
import imp
import os.path
-import pkg_resources
import sys
import unittest
+try:
+ import pkg_resources
+except ImportError:
+ pkg_resources = None
+
+
from django.template import TemplateDoesNotExist, Context
from django.template.loaders.eggs import Loader as EggLoader
from django.template import loader
@@ -24,23 +29,6 @@ from django.utils.six import StringIO
# Mock classes and objects for pkg_resources functions.
-class MockProvider(pkg_resources.NullProvider):
- def __init__(self, module):
- pkg_resources.NullProvider.__init__(self, module)
- self.module = module
-
- def _has(self, path):
- return path in self.module._resources
-
- def _isdir(self, path):
- return False
-
- def get_resource_stream(self, manager, resource_name):
- return self.module._resources[resource_name]
-
- def _get(self, path):
- return self.module._resources[path].read()
-
class MockLoader(object):
pass
@@ -57,8 +45,27 @@ def create_egg(name, resources):
sys.modules[name] = egg
+@unittest.skipUnless(pkg_resources, 'setuptools is not installed')
class EggLoaderTest(unittest.TestCase):
def setUp(self):
+ # Defined here b/c at module scope we may not have pkg_resources
+ class MockProvider(pkg_resources.NullProvider):
+ def __init__(self, module):
+ pkg_resources.NullProvider.__init__(self, module)
+ self.module = module
+
+ def _has(self, path):
+ return path in self.module._resources
+
+ def _isdir(self, path):
+ return False
+
+ def get_resource_stream(self, manager, resource_name):
+ return self.module._resources[resource_name]
+
+ def _get(self, path):
+ return self.module._resources[path].read()
+
pkg_resources._provider_factories[MockLoader] = MockProvider
self.empty_egg = create_egg("egg_empty", {})
diff --git a/tests/template_tests/test_response.py b/tests/template_tests/test_response.py
index 6acc45626f..65f7531361 100644
--- a/tests/template_tests/test_response.py
+++ b/tests/template_tests/test_response.py
@@ -95,7 +95,7 @@ class SimpleTemplateResponseTest(TestCase):
self.assertEqual(response.content, b'foo')
def test_set_content(self):
- # content can be overriden
+ # content can be overridden
response = self._response()
self.assertFalse(response.is_rendered)
response.content = 'spam'
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index 6b8a106623..aa0283be79 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf import settings
@@ -8,8 +8,7 @@ if __name__ == '__main__':
# before importing 'template'.
settings.configure()
-from datetime import date, datetime, timedelta
-import time
+from datetime import date, datetime
import os
import sys
import traceback
@@ -31,21 +30,12 @@ from django.test.utils import (setup_test_template_loader,
from django.utils.encoding import python_2_unicode_compatible
from django.utils.formats import date_format
from django.utils._os import upath
-from django.utils.translation import activate, deactivate, ugettext as _
+from django.utils.translation import activate, deactivate
from django.utils.safestring import mark_safe
from django.utils import six
-from django.utils.tzinfo import LocalTimezone
from i18n import TransRealMixin
-try:
- from .loaders import RenderToStringTest, EggLoaderTest
-except ImportError as e:
- if "pkg_resources" in e.args[0]:
- pass # If setuptools isn't installed, that's fine. Just move on.
- else:
- raise
-
# NumPy installed?
try:
import numpy
diff --git a/tests/template_tests/urls.py b/tests/template_tests/urls.py
index b5498fade1..f3720bbda7 100644
--- a/tests/template_tests/urls.py
+++ b/tests/template_tests/urls.py
@@ -1,5 +1,5 @@
# coding: utf-8
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf.urls import patterns, url
from . import views
diff --git a/tests/templates/custom_admin/app_index.html b/tests/templates/custom_admin/app_index.html
new file mode 100644
index 0000000000..3dfae814a7
--- /dev/null
+++ b/tests/templates/custom_admin/app_index.html
@@ -0,0 +1,6 @@
+{% extends "admin/app_index.html" %}
+
+{% block content %}
+Hello from a custom app_index template
+{{ block.super }}
+{% endblock %}
diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
index 0f3cba7e88..85637b982e 100644
--- a/tests/test_client/tests.py
+++ b/tests/test_client/tests.py
@@ -20,7 +20,7 @@ testing against the contexts and templates produced by a view,
rather than the HTML rendered to the end-user.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf import settings
from django.core import mail
diff --git a/tests/test_client/urls.py b/tests/test_client/urls.py
index bd395ca552..4d2f4fb86e 100644
--- a/tests/test_client/urls.py
+++ b/tests/test_client/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from django.views.generic import RedirectView
diff --git a/tests/test_client_regress/urls.py b/tests/test_client_regress/urls.py
index 1332537d57..6a0b330e02 100644
--- a/tests/test_client_regress/urls.py
+++ b/tests/test_client_regress/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py
index 72200e40d3..7aefa4e077 100644
--- a/tests/test_runner/tests.py
+++ b/tests/test_runner/tests.py
@@ -1,8 +1,9 @@
"""
Tests for django test runner
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
+from importlib import import_module
from optparse import make_option
import sys
import unittest
@@ -13,7 +14,6 @@ from django import db
from django.test import runner, TestCase, TransactionTestCase, skipUnlessDBFeature
from django.test.testcases import connections_support_transactions
from django.test.utils import IgnoreAllDeprecationWarningsMixin
-from django.utils.importlib import import_module
from admin_scripts.tests import AdminScriptTestCase
from .models import Person
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 24aa433dd3..eb850cc3be 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import unittest
diff --git a/tests/test_utils/urls.py b/tests/test_utils/urls.py
index 31fc5cc7fc..65e8631735 100644
--- a/tests/test_utils/urls.py
+++ b/tests/test_utils/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from . import views
diff --git a/tests/test_utils/views.py b/tests/test_utils/views.py
index 5495488e2c..77e598b72c 100644
--- a/tests/test_utils/views.py
+++ b/tests/test_utils/views.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
@@ -8,4 +6,4 @@ from .models import Person
def get_person(request, pk):
person = get_object_or_404(Person, pk=pk)
- return HttpResponse(person.name) \ No newline at end of file
+ return HttpResponse(person.name)
diff --git a/tests/timezones/admin.py b/tests/timezones/admin.py
index 4c199813e2..81b49a4ab6 100644
--- a/tests/timezones/admin.py
+++ b/tests/timezones/admin.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.contrib import admin
from .models import Event, Timestamp
diff --git a/tests/timezones/urls.py b/tests/timezones/urls.py
index e4f42972db..e9a7a90df9 100644
--- a/tests/timezones/urls.py
+++ b/tests/timezones/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, include
from django.contrib import admin
diff --git a/tests/transactions/tests.py b/tests/transactions/tests.py
index afb573f366..9cf8b4d742 100644
--- a/tests/transactions/tests.py
+++ b/tests/transactions/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import sys
from unittest import skipIf, skipUnless
diff --git a/tests/transactions_regress/tests.py b/tests/transactions_regress/tests.py
index 01f8fc4186..2376bcd277 100644
--- a/tests/transactions_regress/tests.py
+++ b/tests/transactions_regress/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from unittest import skipIf, skipUnless
diff --git a/tests/unmanaged_models/tests.py b/tests/unmanaged_models/tests.py
index d7cf961a37..7b23a46096 100644
--- a/tests/unmanaged_models/tests.py
+++ b/tests/unmanaged_models/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db import connection
from django.test import TestCase
diff --git a/tests/update/tests.py b/tests/update/tests.py
index 7a1177c1fd..95e9069972 100644
--- a/tests/update/tests.py
+++ b/tests/update/tests.py
@@ -1,8 +1,8 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.test import TestCase
-from .models import A, B, C, D, DataPoint, RelatedPoint
+from .models import A, B, D, DataPoint, RelatedPoint
class SimpleTest(TestCase):
@@ -51,6 +51,15 @@ class SimpleTest(TestCase):
cnt = D.objects.filter(y=100).count()
self.assertEqual(cnt, 0)
+ def test_foreign_key_update_with_id(self):
+ """
+ Test that update works using <field>_id for foreign keys
+ """
+ num_updated = self.a1.d_set.update(a_id=self.a2)
+ self.assertEqual(num_updated, 20)
+ self.assertEqual(self.a2.d_set.count(), 20)
+
+
class AdvancedTests(TestCase):
def setUp(self):
@@ -115,4 +124,4 @@ class AdvancedTests(TestCase):
"""
method = DataPoint.objects.all()[:2].update
self.assertRaises(AssertionError, method,
- another_value='another thing')
+ another_value='another thing')
diff --git a/tests/update_only_fields/tests.py b/tests/update_only_fields/tests.py
index 97c05ddc79..1f85c3bbb2 100644
--- a/tests/update_only_fields/tests.py
+++ b/tests/update_only_fields/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
from django.db.models.signals import pre_save, post_save
from django.test import TestCase
diff --git a/tests/urlpatterns_reverse/extra_urls.py b/tests/urlpatterns_reverse/extra_urls.py
index d3a04e6b31..94e225fb46 100644
--- a/tests/urlpatterns_reverse/extra_urls.py
+++ b/tests/urlpatterns_reverse/extra_urls.py
@@ -2,8 +2,6 @@
Some extra URL patterns that are included at the top level.
"""
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/included_named_urls.py b/tests/urlpatterns_reverse/included_named_urls.py
index 353aed255e..366fe9b57a 100644
--- a/tests/urlpatterns_reverse/included_named_urls.py
+++ b/tests/urlpatterns_reverse/included_named_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/included_named_urls2.py b/tests/urlpatterns_reverse/included_named_urls2.py
index b31bdb1f7e..b8e4c531fa 100644
--- a/tests/urlpatterns_reverse/included_named_urls2.py
+++ b/tests/urlpatterns_reverse/included_named_urls2.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/included_namespace_urls.py b/tests/urlpatterns_reverse/included_namespace_urls.py
index 7a2096ecd9..ae098a64dc 100644
--- a/tests/urlpatterns_reverse/included_namespace_urls.py
+++ b/tests/urlpatterns_reverse/included_namespace_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .namespace_urls import URLObject
diff --git a/tests/urlpatterns_reverse/included_urls.py b/tests/urlpatterns_reverse/included_urls.py
index c8c9001843..af6b6882e0 100644
--- a/tests/urlpatterns_reverse/included_urls.py
+++ b/tests/urlpatterns_reverse/included_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/included_urls2.py b/tests/urlpatterns_reverse/included_urls2.py
index 98605047f4..9dcafc8535 100644
--- a/tests/urlpatterns_reverse/included_urls2.py
+++ b/tests/urlpatterns_reverse/included_urls2.py
@@ -5,8 +5,6 @@ each name to resolve and Django must distinguish the possibilities based on the
argument list.
"""
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/middleware.py b/tests/urlpatterns_reverse/middleware.py
index fbf577786e..0de692835f 100644
--- a/tests/urlpatterns_reverse/middleware.py
+++ b/tests/urlpatterns_reverse/middleware.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.core.urlresolvers import reverse
from django.http import HttpResponse, StreamingHttpResponse
diff --git a/tests/urlpatterns_reverse/named_urls.py b/tests/urlpatterns_reverse/named_urls.py
index 3290cab29c..d4d35bac33 100644
--- a/tests/urlpatterns_reverse/named_urls.py
+++ b/tests/urlpatterns_reverse/named_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/namespace_urls.py b/tests/urlpatterns_reverse/namespace_urls.py
index cf960070ec..014bc65990 100644
--- a/tests/urlpatterns_reverse/namespace_urls.py
+++ b/tests/urlpatterns_reverse/namespace_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .views import view_class_instance
diff --git a/tests/urlpatterns_reverse/reverse_lazy_urls.py b/tests/urlpatterns_reverse/reverse_lazy_urls.py
index 693c6e1b38..0ef0a1f313 100644
--- a/tests/urlpatterns_reverse/reverse_lazy_urls.py
+++ b/tests/urlpatterns_reverse/reverse_lazy_urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from .views import empty_view, LazyRedirectView, login_required_view
diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py
index 222ebe053b..aef0fa0514 100644
--- a/tests/urlpatterns_reverse/tests.py
+++ b/tests/urlpatterns_reverse/tests.py
@@ -1,7 +1,7 @@
"""
Unit tests for reverse URL lookups.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import unittest
diff --git a/tests/urlpatterns_reverse/urlconf_outer.py b/tests/urlpatterns_reverse/urlconf_outer.py
index 0cdebf83ff..20b9b09f98 100644
--- a/tests/urlpatterns_reverse/urlconf_outer.py
+++ b/tests/urlpatterns_reverse/urlconf_outer.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from . import urlconf_inner
@@ -8,4 +6,4 @@ from . import urlconf_inner
urlpatterns = patterns('',
url(r'^test/me/$', urlconf_inner.inner_view, name='outer'),
url(r'^inner_urlconf/', include(urlconf_inner.__name__))
-) \ No newline at end of file
+)
diff --git a/tests/urlpatterns_reverse/urls.py b/tests/urlpatterns_reverse/urls.py
index 1dbc8d889f..cb08e2e664 100644
--- a/tests/urlpatterns_reverse/urls.py
+++ b/tests/urlpatterns_reverse/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url, include
from .views import empty_view, absolute_kwargs_view
diff --git a/tests/urlpatterns_reverse/urls_error_handlers_callables.py b/tests/urlpatterns_reverse/urls_error_handlers_callables.py
index befeccaf45..0900ec94ba 100644
--- a/tests/urlpatterns_reverse/urls_error_handlers_callables.py
+++ b/tests/urlpatterns_reverse/urls_error_handlers_callables.py
@@ -1,7 +1,5 @@
# Used by the ErrorHandlerResolutionTests test case.
-from __future__ import absolute_import
-
from django.conf.urls import patterns
from .views import empty_view
diff --git a/tests/urlpatterns_reverse/urls_without_full_import.py b/tests/urlpatterns_reverse/urls_without_full_import.py
index ca3e424f23..c1dce5549c 100644
--- a/tests/urlpatterns_reverse/urls_without_full_import.py
+++ b/tests/urlpatterns_reverse/urls_without_full_import.py
@@ -1,8 +1,6 @@
# A URLs file that doesn't use the default
# from django.conf.urls import *
# import pattern.
-from __future__ import absolute_import
-
from django.conf.urls import patterns, url
from .views import empty_view, bad_view
diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py
index 1f2e19d8d5..74d94ea19d 100644
--- a/tests/utils_tests/test_html.py
+++ b/tests/utils_tests/test_html.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from datetime import datetime
@@ -181,3 +182,13 @@ class TestUtilsHtml(TestCase):
)
for value, tags, output in items:
self.assertEqual(f(value, tags), output)
+
+ def test_smart_urlquote(self):
+ quote = html.smart_urlquote
+ # Ensure that IDNs are properly quoted
+ self.assertEqual(quote('http://öäü.com/'), 'http://xn--4ca9at.com/')
+ self.assertEqual(quote('http://öäü.com/öäü/'), 'http://xn--4ca9at.com/%C3%B6%C3%A4%C3%BC/')
+ # Ensure that everything unsafe is quoted, !*'();:@&=+$,/?#[]~ is considered safe as per RFC
+ self.assertEqual(quote('http://example.com/path/öäü/'), 'http://example.com/path/%C3%B6%C3%A4%C3%BC/')
+ self.assertEqual(quote('http://example.com/%C3%B6/ä/'), 'http://example.com/%C3%B6/%C3%A4/')
+ self.assertEqual(quote('http://example.com/?x=1&y=2'), 'http://example.com/?x=1&y=2')
diff --git a/tests/utils_tests/test_module_loading.py b/tests/utils_tests/test_module_loading.py
index 5a43a927bf..2423215778 100644
--- a/tests/utils_tests/test_module_loading.py
+++ b/tests/utils_tests/test_module_loading.py
@@ -1,11 +1,11 @@
import imp
+from importlib import import_module
import os
import sys
import unittest
from zipimport import zipimporter
from django.core.exceptions import ImproperlyConfigured
-from django.utils.importlib import import_module
from django.utils.module_loading import import_by_path, module_has_submodule
from django.utils._os import upath
diff --git a/tests/utils_tests/test_safestring.py b/tests/utils_tests/test_safestring.py
index a6f0c0a01c..5d4528a9a8 100644
--- a/tests/utils_tests/test_safestring.py
+++ b/tests/utils_tests/test_safestring.py
@@ -1,5 +1,4 @@
-from __future__ import absolute_import, unicode_literals
-
+from __future__ import unicode_literals
from django.template import Template, Context
from django.test import TestCase
diff --git a/tests/validation/test_custom_messages.py b/tests/validation/test_custom_messages.py
index c5a1ee744f..2e259b7aef 100644
--- a/tests/validation/test_custom_messages.py
+++ b/tests/validation/test_custom_messages.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from . import ValidationTestCase
from .models import CustomMessagesModel
diff --git a/tests/validation/test_unique.py b/tests/validation/test_unique.py
index a481fcb1c4..bca1b36c93 100644
--- a/tests/validation/test_unique.py
+++ b/tests/validation/test_unique.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import datetime
import unittest
diff --git a/tests/validation/test_validators.py b/tests/validation/test_validators.py
index e58d9fd4a6..c3875d4601 100644
--- a/tests/validation/test_validators.py
+++ b/tests/validation/test_validators.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from . import ValidationTestCase
from .models import ModelToValidate
diff --git a/tests/validation/tests.py b/tests/validation/tests.py
index c8b679541a..34cde3fc8a 100644
--- a/tests/validation/tests.py
+++ b/tests/validation/tests.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django import forms
from django.core.exceptions import NON_FIELD_ERRORS
diff --git a/tests/view_tests/generic_urls.py b/tests/view_tests/generic_urls.py
index c3ac1fcafa..10e7601eb6 100644
--- a/tests/view_tests/generic_urls.py
+++ b/tests/view_tests/generic_urls.py
@@ -1,5 +1,5 @@
# -*- coding:utf-8 -*-
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
diff --git a/tests/view_tests/templatetags/debugtags.py b/tests/view_tests/templatetags/debugtags.py
index cd2d2d9ad2..9e1945cb23 100644
--- a/tests/view_tests/templatetags/debugtags.py
+++ b/tests/view_tests/templatetags/debugtags.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from django import template
from ..views import BrokenException
diff --git a/tests/view_tests/tests/__init__.py b/tests/view_tests/tests/__init__.py
index bfb2ed7376..dae149a8ef 100644
--- a/tests/view_tests/tests/__init__.py
+++ b/tests/view_tests/tests/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
from .test_debug import (DebugViewTests, ExceptionReporterTests,
ExceptionReporterTests, PlainTextReportTests, ExceptionReporterFilterTests,
AjaxResponseExceptionReporterFilter)
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index bc77fc351a..0159886918 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# This coding header is significant for tests, as the debug view is parsing
# files to search for such a header to decode the source file content
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
import inspect
import os
diff --git a/tests/view_tests/tests/test_defaults.py b/tests/view_tests/tests/test_defaults.py
index 5efd338d34..d55ed53454 100644
--- a/tests/view_tests/tests/test_defaults.py
+++ b/tests/view_tests/tests/test_defaults.py
@@ -1,8 +1,9 @@
-from __future__ import absolute_import, unicode_literals
+from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
-from django.test.utils import setup_test_template_loader, restore_template_loaders
+from django.test.utils import (setup_test_template_loader,
+ restore_template_loaders, override_settings)
from ..models import Author, Article, UrlArticle
@@ -59,3 +60,20 @@ class DefaultsTests(TestCase):
article = UrlArticle.objects.get(pk=1)
self.assertTrue(getattr(article.get_absolute_url, 'purge', False),
'The attributes of the original get_absolute_url must be added.')
+
+ @override_settings(DEFAULT_CONTENT_TYPE="text/xml")
+ def test_default_content_type_is_text_html(self):
+ """
+ Content-Type of the default error responses is text/html. Refs #20822.
+ """
+ response = self.client.get('/views/raises400/')
+ self.assertEqual(response['Content-Type'], 'text/html')
+
+ response = self.client.get('/views/raises403/')
+ self.assertEqual(response['Content-Type'], 'text/html')
+
+ response = self.client.get('/views/non_existing_url/')
+ self.assertEqual(response['Content-Type'], 'text/html')
+
+ response = self.client.get('/views/server_error/')
+ self.assertEqual(response['Content-Type'], 'text/html')
diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py
index c1852ee71f..cfee4f5093 100644
--- a/tests/view_tests/tests/test_i18n.py
+++ b/tests/view_tests/tests/test_i18n.py
@@ -1,6 +1,4 @@
# -*- coding:utf-8 -*-
-from __future__ import absolute_import
-
import gettext
import os
from os import path
@@ -200,26 +198,22 @@ class JavascriptI18nTests(LiveServerTestCase):
@override_settings(LANGUAGE_CODE='de')
def test_javascript_gettext(self):
- extended_apps = list(settings.INSTALLED_APPS) + ['view_tests']
- with self.settings(INSTALLED_APPS=extended_apps):
- self.selenium.get('%s%s' % (self.live_server_url, '/jsi18n_template/'))
+ self.selenium.get('%s%s' % (self.live_server_url, '/jsi18n_template/'))
- elem = self.selenium.find_element_by_id("gettext")
- self.assertEqual(elem.text, "Entfernen")
- elem = self.selenium.find_element_by_id("ngettext_sing")
- self.assertEqual(elem.text, "1 Element")
- elem = self.selenium.find_element_by_id("ngettext_plur")
- self.assertEqual(elem.text, "455 Elemente")
- elem = self.selenium.find_element_by_id("pgettext")
- self.assertEqual(elem.text, "Kann")
- elem = self.selenium.find_element_by_id("npgettext_sing")
- self.assertEqual(elem.text, "1 Resultat")
- elem = self.selenium.find_element_by_id("npgettext_plur")
- self.assertEqual(elem.text, "455 Resultate")
+ elem = self.selenium.find_element_by_id("gettext")
+ self.assertEqual(elem.text, "Entfernen")
+ elem = self.selenium.find_element_by_id("ngettext_sing")
+ self.assertEqual(elem.text, "1 Element")
+ elem = self.selenium.find_element_by_id("ngettext_plur")
+ self.assertEqual(elem.text, "455 Elemente")
+ elem = self.selenium.find_element_by_id("pgettext")
+ self.assertEqual(elem.text, "Kann")
+ elem = self.selenium.find_element_by_id("npgettext_sing")
+ self.assertEqual(elem.text, "1 Resultat")
+ elem = self.selenium.find_element_by_id("npgettext_plur")
+ self.assertEqual(elem.text, "455 Resultate")
def test_escaping(self):
- extended_apps = list(settings.INSTALLED_APPS) + ['view_tests']
- with self.settings(INSTALLED_APPS=extended_apps):
- # Force a language via GET otherwise the gettext functions are a noop!
- response = self.client.get('/jsi18n_admin/?language=de')
- self.assertContains(response, '\\x04')
+ # Force a language via GET otherwise the gettext functions are a noop!
+ response = self.client.get('/jsi18n_admin/?language=de')
+ self.assertContains(response, '\\x04')
diff --git a/tests/view_tests/tests/test_static.py b/tests/view_tests/tests/test_static.py
index 6104ad063e..d2f3f47fa7 100644
--- a/tests/view_tests/tests/test_static.py
+++ b/tests/view_tests/tests/test_static.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import mimetypes
from os import path
diff --git a/tests/view_tests/urls.py b/tests/view_tests/urls.py
index d792e47ddf..f2c910368d 100644
--- a/tests/view_tests/urls.py
+++ b/tests/view_tests/urls.py
@@ -1,6 +1,4 @@
# coding: utf-8
-from __future__ import absolute_import
-
from os import path
from django.conf.urls import patterns, url, include
@@ -47,8 +45,10 @@ urlpatterns = patterns('',
# a view that raises an exception for the debug view
(r'raises/$', views.raises),
- (r'raises404/$', views.raises404),
+
+ (r'raises400/$', views.raises400),
(r'raises403/$', views.raises403),
+ (r'raises404/$', views.raises404),
# i18n views
(r'^i18n/', include('django.conf.urls.i18n')),
diff --git a/tests/view_tests/views.py b/tests/view_tests/views.py
index 1cfafa4333..0bac7d9321 100644
--- a/tests/view_tests/views.py
+++ b/tests/view_tests/views.py
@@ -1,8 +1,8 @@
-from __future__ import absolute_import
+from __future__ import unicode_literals
import sys
-from django.core.exceptions import PermissionDenied
+from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.core.urlresolvers import get_resolver
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, render
@@ -31,13 +31,16 @@ def raises(request):
except Exception:
return technical_500_response(request, *sys.exc_info())
-def raises404(request):
- resolver = get_resolver(None)
- resolver.resolve('')
+def raises400(request):
+ raise SuspiciousOperation
def raises403(request):
raise PermissionDenied
+def raises404(request):
+ resolver = get_resolver(None)
+ resolver.resolve('')
+
def redirect(request):
"""
Forces an HTTP redirect.