summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2013-08-19 18:30:48 +0100
committerAndrew Godwin <andrew@aeracode.org>2013-08-19 18:30:48 +0100
commitb6a957f0ba8a2ed1b24d7ee042a9c4beaf51ab03 (patch)
tree87d42b9e8d3d4c1516b53eee1d9332735762826a /tests
parent52edc16086e3c28a78c31975bb4da2f9450590b4 (diff)
parent3c0300405009b82b52fd15483371097221662fcd (diff)
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts: docs/ref/django-admin.txt
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_views/admin.py10
-rw-r--r--tests/admin_views/models.py14
-rw-r--r--tests/admin_views/tests.py44
-rw-r--r--tests/admin_widgets/tests.py72
-rw-r--r--tests/aggregation/tests.py25
-rw-r--r--tests/aggregation_regress/models.py2
-rw-r--r--tests/basic/tests.py4
-rw-r--r--tests/check/models.py10
-rw-r--r--tests/check/tests.py20
-rw-r--r--tests/comment_tests/models.py2
-rw-r--r--tests/custom_managers/models.py4
-rw-r--r--tests/defaultfilters/tests.py37
-rw-r--r--tests/defer/tests.py6
-rw-r--r--tests/file_storage/tests.py12
-rw-r--r--tests/foreign_object/tests.py19
-rw-r--r--tests/forms_tests/tests/test_fields.py18
-rw-r--r--tests/forms_tests/tests/test_widgets.py16
-rw-r--r--tests/generic_relations/models.py2
-rw-r--r--tests/i18n/tests.py35
-rw-r--r--tests/inspectdb/models.py2
-rw-r--r--tests/logging_tests/tests.py19
-rw-r--r--tests/model_fields/models.py4
-rw-r--r--tests/model_fields/tests.py23
-rw-r--r--tests/model_formsets/models.py6
-rw-r--r--tests/model_inheritance/models.py8
-rw-r--r--tests/model_inheritance/tests.py91
-rw-r--r--tests/model_inheritance_regress/models.py21
-rw-r--r--tests/model_inheritance_regress/tests.py16
-rw-r--r--tests/model_inheritance_select_related/models.py4
-rw-r--r--tests/modeladmin/models.py2
-rw-r--r--tests/one_to_one/models.py4
-rw-r--r--tests/one_to_one_regress/models.py4
-rw-r--r--tests/one_to_one_regress/tests.py35
-rw-r--r--tests/proxy_models/admin.py6
-rw-r--r--tests/proxy_models/fixtures/myhorses.json20
-rw-r--r--tests/proxy_models/models.py6
-rw-r--r--tests/proxy_models/tests.py30
-rw-r--r--tests/proxy_models/urls.py7
-rw-r--r--tests/queries/tests.py26
-rw-r--r--tests/raw_query/models.py2
-rw-r--r--tests/reverse_single_related/models.py2
-rwxr-xr-xtests/runtests.py1
-rw-r--r--tests/serializers_regress/models.py4
-rw-r--r--tests/servers/another_app/__init__.py0
-rw-r--r--tests/servers/another_app/models.py0
-rw-r--r--tests/servers/another_app/static/another_app/another_app_static_file.txt1
-rw-r--r--tests/servers/tests.py8
-rw-r--r--tests/template_tests/test_context.py11
-rw-r--r--tests/template_tests/tests.py7
-rw-r--r--tests/test_client_regress/tests.py8
-rw-r--r--tests/test_client_regress/urls.py1
-rw-r--r--tests/test_client_regress/views.py13
-rw-r--r--tests/test_utils/tests.py71
-rw-r--r--tests/transactions/tests.py179
-rw-r--r--tests/utils_tests/test_simplelazyobject.py13
-rw-r--r--tests/view_tests/tests/test_debug.py16
-rw-r--r--tests/view_tests/tests/test_i18n.py64
-rw-r--r--tests/view_tests/tests/test_static.py8
-rw-r--r--tests/view_tests/urls.py1
-rw-r--r--tests/view_tests/views.py8
60 files changed, 729 insertions, 375 deletions
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index df8ced949e..193b64505c 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -29,7 +29,7 @@ from .models import (Article, Chapter, Account, Media, Child, Parent, Picture,
Album, Question, Answer, ComplexSortedPerson, PluggableSearchPerson, PrePopulatedPostLargeSlug,
AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod,
AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated,
- RelatedPrepopulated, UndeletableObject, UserMessenger, Simple, Choice,
+ RelatedPrepopulated, UndeletableObject, UnchangeableObject, UserMessenger, Simple, Choice,
ShortMessage, Telegram)
@@ -656,6 +656,13 @@ class UndeletableObjectAdmin(admin.ModelAdmin):
return super(UndeletableObjectAdmin, self).change_view(*args, **kwargs)
+class UnchangeableObjectAdmin(admin.ModelAdmin):
+ def get_urls(self):
+ # Disable change_view, but leave other urls untouched
+ urlpatterns = super(UnchangeableObjectAdmin, self).get_urls()
+ return [p for p in urlpatterns if not p.name.endswith("_change")]
+
+
def callable_on_unknown(obj):
return obj.unknown
@@ -741,6 +748,7 @@ site.register(Report, ReportAdmin)
site.register(MainPrepopulated, MainPrepopulatedAdmin)
site.register(UnorderedObject, UnorderedObjectAdmin)
site.register(UndeletableObject, UndeletableObjectAdmin)
+site.register(UnchangeableObject, UnchangeableObjectAdmin)
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
# That way we cover all four cases:
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index a1131210d7..1accf46819 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -115,7 +115,7 @@ class ModelWithStringPrimaryKey(models.Model):
@python_2_unicode_compatible
class Color(models.Model):
value = models.CharField(max_length=10)
- warm = models.BooleanField()
+ warm = models.BooleanField(default=False)
def __str__(self):
return self.value
@@ -144,7 +144,7 @@ class Actor(models.Model):
@python_2_unicode_compatible
class Inquisition(models.Model):
- expected = models.BooleanField()
+ expected = models.BooleanField(default=False)
leader = models.ForeignKey(Actor)
country = models.CharField(max_length=20)
@@ -376,7 +376,7 @@ class Link(models.Model):
class PrePopulatedPost(models.Model):
title = models.CharField(max_length=100)
- published = models.BooleanField()
+ published = models.BooleanField(default=False)
slug = models.SlugField()
@@ -607,7 +607,7 @@ class PrePopulatedPostLargeSlug(models.Model):
the javascript (ie, using THOUSAND_SEPARATOR ends up with maxLength=1,000)
"""
title = models.CharField(max_length=100)
- published = models.BooleanField()
+ published = models.BooleanField(default=False)
slug = models.SlugField(max_length=1000)
class AdminOrderedField(models.Model):
@@ -674,6 +674,12 @@ class UndeletableObject(models.Model):
"""
name = models.CharField(max_length=255)
+class UnchangeableObject(models.Model):
+ """
+ Model whose change_view is disabled in admin
+ Refs #20640.
+ """
+
class UserMessenger(models.Model):
"""
Dummy class for testing message_user functions on ModelAdmin
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 3ee06751fb..8f83324a37 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -15,7 +15,6 @@ from django.core import mail
from django.core.files import temp as tempfile
from django.core.urlresolvers import reverse
# Register auth models with the admin.
-from django.contrib import admin
from django.contrib.auth import get_permission_codename
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.contrib.admin.models import LogEntry, DELETION
@@ -51,7 +50,7 @@ from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount,
OtherStory, ComplexSortedPerson, PluggableSearchPerson, Parent, Child, AdminOrderedField,
AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable,
Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject,
- Simple, UndeletableObject, Choice, ShortMessage, Telegram)
+ Simple, UndeletableObject, UnchangeableObject, Choice, ShortMessage, Telegram)
from .admin import site, site2
@@ -524,31 +523,28 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
if the default language is non-English but the selected language
is English. See #13388 and #3594 for more details.
"""
- with self.settings(LANGUAGE_CODE='fr'):
- with translation.override('en-us'):
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertNotContains(response, 'Choisir une heure')
+ with self.settings(LANGUAGE_CODE='fr'), translation.override('en-us'):
+ response = self.client.get('/test_admin/admin/jsi18n/')
+ self.assertNotContains(response, 'Choisir une heure')
def testI18NLanguageNonEnglishFallback(self):
"""
Makes sure that the fallback language is still working properly
in cases where the selected language cannot be found.
"""
- with self.settings(LANGUAGE_CODE='fr'):
- with translation.override('none'):
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertContains(response, 'Choisir une heure')
+ with self.settings(LANGUAGE_CODE='fr'), translation.override('none'):
+ response = self.client.get('/test_admin/admin/jsi18n/')
+ self.assertContains(response, 'Choisir une heure')
def testL10NDeactivated(self):
"""
Check if L10N is deactivated, the JavaScript i18n view doesn't
return localized date/time formats. Refs #14824.
"""
- with self.settings(LANGUAGE_CODE='ru', USE_L10N=False):
- with translation.override('none'):
- response = self.client.get('/test_admin/admin/jsi18n/')
- self.assertNotContains(response, '%d.%m.%Y %H:%M:%S')
- self.assertContains(response, '%Y-%m-%d %H:%M:%S')
+ with self.settings(LANGUAGE_CODE='ru', USE_L10N=False), translation.override('none'):
+ response = self.client.get('/test_admin/admin/jsi18n/')
+ self.assertNotContains(response, '%d.%m.%Y %H:%M:%S')
+ self.assertContains(response, '%Y-%m-%d %H:%M:%S')
def test_disallowed_filtering(self):
with patch_logger('django.security.DisallowedModelAdminLookup', 'error') as calls:
@@ -2425,6 +2421,24 @@ class AdminActionsTest(TestCase):
self.assertContains(response, '<li>Answer: <a href="/test_admin/admin/admin_views/answer/%s/">Because.</a></li>' % a1.pk, html=True)
self.assertContains(response, '<li>Answer: <a href="/test_admin/admin/admin_views/answer/%s/">Yes.</a></li>' % a2.pk, html=True)
+ def test_model_admin_default_delete_action_no_change_url(self):
+ """
+ Default delete action shouldn't break if a user's ModelAdmin removes the url for change_view.
+
+ Regression test for #20640
+ """
+ obj = UnchangeableObject.objects.create()
+ action_data = {
+ ACTION_CHECKBOX_NAME: obj.pk,
+ "action": "delete_selected",
+ "index": "0",
+ }
+ response = self.client.post('/test_admin/admin/admin_views/unchangeableobject/', action_data)
+ # No 500 caused by NoReverseMatch
+ self.assertEqual(response.status_code, 200)
+ # The page shouldn't display a link to the nonexistent change page
+ self.assertContains(response, "<li>Unchangeable object: UnchangeableObject object</li>", 1, html=True)
+
def test_custom_function_mail_action(self):
"Tests a custom action defined in a function"
action_data = {
diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py
index 5a88df1e57..d2ecf46358 100644
--- a/tests/admin_widgets/tests.py
+++ b/tests/admin_widgets/tests.py
@@ -16,7 +16,6 @@ from django.test import TestCase as DjangoTestCase
from django.test.utils import override_settings
from django.utils import six
from django.utils import translation
-from django.utils.html import conditional_escape
from . import models
from .widgetadmin import site as widget_admin_site
@@ -238,14 +237,14 @@ class FilteredSelectMultipleWidgetTest(DjangoTestCase):
def test_render(self):
w = widgets.FilteredSelectMultiple('test', False)
self.assertHTMLEqual(
- conditional_escape(w.render('test', 'test')),
+ w.render('test', 'test'),
'<select multiple="multiple" name="test" class="selectfilter">\n</select><script type="text/javascript">addEvent(window, "load", function(e) {SelectFilter.init("id_test", "test", 0, "%(ADMIN_STATIC_PREFIX)s"); });</script>\n' % admin_static_prefix()
)
def test_stacked_render(self):
w = widgets.FilteredSelectMultiple('test', True)
self.assertHTMLEqual(
- conditional_escape(w.render('test', 'test')),
+ w.render('test', 'test'),
'<select multiple="multiple" name="test" class="selectfilterstacked">\n</select><script type="text/javascript">addEvent(window, "load", function(e) {SelectFilter.init("id_test", "test", 1, "%(ADMIN_STATIC_PREFIX)s"); });</script>\n' % admin_static_prefix()
)
@@ -257,13 +256,13 @@ class AdminDateWidgetTest(DjangoTestCase):
"""
w = widgets.AdminDateWidget()
self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
'<input value="2007-12-01" type="text" class="vDateField" name="test" size="10" />',
)
# pass attrs to widget
w = widgets.AdminDateWidget(attrs={'size': 20, 'class': 'myDateField'})
self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
'<input value="2007-12-01" type="text" class="myDateField" name="test" size="20" />',
)
@@ -275,13 +274,13 @@ class AdminTimeWidgetTest(DjangoTestCase):
"""
w = widgets.AdminTimeWidget()
self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
'<input value="09:30:00" type="text" class="vTimeField" name="test" size="8" />',
)
# pass attrs to widget
w = widgets.AdminTimeWidget(attrs={'size': 20, 'class': 'myTimeField'})
self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
'<input value="09:30:00" type="text" class="myTimeField" name="test" size="20" />',
)
@@ -289,50 +288,55 @@ class AdminSplitDateTimeWidgetTest(DjangoTestCase):
def test_render(self):
w = widgets.AdminSplitDateTime()
self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
'<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
)
def test_localization(self):
w = widgets.AdminSplitDateTime()
- with self.settings(USE_L10N=True):
- with translation.override('de-at'):
- w.is_localized = True
- self.assertHTMLEqual(
- conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))),
- '<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
- )
+ with self.settings(USE_L10N=True), translation.override('de-at'):
+ w.is_localized = True
+ self.assertHTMLEqual(
+ w.render('test', datetime(2007, 12, 1, 9, 30)),
+ '<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
+ )
class AdminURLWidgetTest(DjangoTestCase):
def test_render(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
- conditional_escape(w.render('test', '')),
+ w.render('test', ''),
'<input class="vURLField" name="test" type="url" />'
)
self.assertHTMLEqual(
- conditional_escape(w.render('test', 'http://example.com')),
+ 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="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="url" value="http://example-äüö.com" /></p>'
+ 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="url" value="http://example-äüö.com" /></p>'
)
def test_render_quoting(self):
+ # WARNING: Don't use assertHTMLEqual in that testcase!
+ # assertHTMLEqual will get rid of some escapes which are tested here!
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="url" value="http://example.com/<sometag>some text</sometag>" /></p>'
+ self.assertEqual(
+ 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="url" value="http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></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="url" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
+ self.assertEqual(
+ 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="url" value="http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></p>'
+ )
+ self.assertEqual(
+ w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"'),
+ '<p class="url">Currently: <a href="http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22">http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;</a><br />Change: <input class="vURLField" name="test" type="url" value="http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;" /></p>'
)
@@ -345,12 +349,12 @@ class AdminFileWidgetTest(DjangoTestCase):
w = widgets.AdminFileWidget()
self.assertHTMLEqual(
- conditional_escape(w.render('test', album.cover_art)),
+ w.render('test', album.cover_art),
'<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/hybrid_theory.jpg">albums\hybrid_theory.jpg</a> <span class="clearable-file-input"><input type="checkbox" name="test-clear" id="test-clear_id" /> <label for="test-clear_id">Clear</label></span><br />Change: <input type="file" name="test" /></p>' % { 'STORAGE_URL': default_storage.url('') },
)
self.assertHTMLEqual(
- conditional_escape(w.render('test', SimpleUploadedFile('test', b'content'))),
+ w.render('test', SimpleUploadedFile('test', b'content')),
'<input type="file" name="test" />',
)
@@ -365,7 +369,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual(
- conditional_escape(w.render('test', band.pk, attrs={})),
+ w.render('test', band.pk, attrs={}),
'<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_STATIC_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Linkin Park</strong>' % dict(admin_static_prefix(), bandpk=band.pk)
)
@@ -393,7 +397,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual(
- conditional_escape(w.render('honeycomb_widget', big_honeycomb.pk, attrs={})),
+ w.render('honeycomb_widget', big_honeycomb.pk, attrs={}),
'<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />&nbsp;<strong>Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk}
)
@@ -406,7 +410,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual(
- conditional_escape(w.render('individual_widget', subject1.pk, attrs={})),
+ w.render('individual_widget', subject1.pk, attrs={}),
'<input type="text" name="individual_widget" value="%(subj1pk)s" />&nbsp;<strong>Individual object</strong>' % {'subj1pk': subject1.pk}
)
@@ -438,12 +442,12 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase):
w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual(
- conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})),
+ w.render('test', [m1.pk, m2.pk], attrs={}),
'<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_static_prefix(), m1pk=m1.pk, m2pk=m2.pk)
)
self.assertHTMLEqual(
- conditional_escape(w.render('test', [m1.pk])),
+ w.render('test', [m1.pk]),
'<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_STATIC_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_static_prefix(), m1pk=m1.pk)
)
@@ -459,12 +463,12 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase):
w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual(
- conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})),
+ w.render('company_widget1', [c1.pk, c2.pk], attrs={}),
'<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" />' % {'c1pk': c1.pk, 'c2pk': c2.pk}
)
self.assertHTMLEqual(
- conditional_escape(w.render('company_widget2', [c1.pk])),
+ w.render('company_widget2', [c1.pk]),
'<input type="text" name="company_widget2" value="%(c1pk)s" />' % {'c1pk': c1.pk}
)
diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py
index 4d46cae766..7d2490a77c 100644
--- a/tests/aggregation/tests.py
+++ b/tests/aggregation/tests.py
@@ -3,8 +3,10 @@ from __future__ import unicode_literals
import datetime
from decimal import Decimal
+from django.db import connection
from django.db.models import Avg, Sum, Count, Max, Min
from django.test import TestCase, Approximate
+from django.test.utils import CaptureQueriesContext
from .models import Author, Publisher, Book, Store
@@ -617,3 +619,26 @@ class BaseAggregateTestCase(TestCase):
# 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)
+
+ def test_ticket12886(self):
+ """
+ Check that aggregation over sliced queryset works correctly.
+ """
+ qs = Book.objects.all().order_by('-rating')[0:3]
+ vals = qs.aggregate(average_top3_rating=Avg('rating'))['average_top3_rating']
+ self.assertAlmostEqual(vals, 4.5, places=2)
+
+ def test_ticket11881(self):
+ """
+ Check that subqueries do not needlessly contain ORDER BY, SELECT FOR UPDATE
+ or select_related() stuff.
+ """
+ qs = Book.objects.all().select_for_update().order_by(
+ 'pk').select_related('publisher').annotate(max_pk=Max('pk'))
+ with CaptureQueriesContext(connection) as captured_queries:
+ qs.aggregate(avg_pk=Avg('max_pk'))
+ self.assertEqual(len(captured_queries), 1)
+ qstr = captured_queries[0]['sql'].lower()
+ self.assertNotIn('for update', qstr)
+ self.assertNotIn('order by', qstr)
+ self.assertEqual(qstr.count(' join '), 0)
diff --git a/tests/aggregation_regress/models.py b/tests/aggregation_regress/models.py
index 047c871c39..dfef691882 100644
--- a/tests/aggregation_regress/models.py
+++ b/tests/aggregation_regress/models.py
@@ -64,7 +64,7 @@ class Store(models.Model):
class Entries(models.Model):
EntryID = models.AutoField(primary_key=True, db_column='Entry ID')
Entry = models.CharField(unique=True, max_length=50)
- Exclude = models.BooleanField()
+ Exclude = models.BooleanField(default=False)
class Clues(models.Model):
diff --git a/tests/basic/tests.py b/tests/basic/tests.py
index 55ed6a436f..2b051621ef 100644
--- a/tests/basic/tests.py
+++ b/tests/basic/tests.py
@@ -707,6 +707,10 @@ class ModelTest(TestCase):
with self.assertRaises(ObjectDoesNotExist):
SelfRef.objects.get(selfref=sr)
+ def test_eq(self):
+ self.assertNotEqual(Article(id=1), object())
+ self.assertNotEqual(object(), Article(id=1))
+
class ConcurrentSaveTests(TransactionTestCase):
diff --git a/tests/check/models.py b/tests/check/models.py
index 78a10abba6..212b01bdd2 100644
--- a/tests/check/models.py
+++ b/tests/check/models.py
@@ -1 +1,9 @@
-# Stubby.
+from django.db import models
+
+class Book(models.Model):
+ title = models.CharField(max_length=250)
+ is_published = models.BooleanField(default=False)
+
+class BlogPost(models.Model):
+ title = models.CharField(max_length=250)
+ is_published = models.BooleanField(default=False)
diff --git a/tests/check/tests.py b/tests/check/tests.py
index 98495e38ae..3faf086557 100644
--- a/tests/check/tests.py
+++ b/tests/check/tests.py
@@ -2,8 +2,10 @@ from django.core.checks.compatibility import base
from django.core.checks.compatibility import django_1_6_0
from django.core.management.commands import check
from django.core.management import call_command
+from django.db.models.fields import NOT_PROVIDED
from django.test import TestCase
+from .models import Book
class StubCheckModule(object):
# Has no ``run_checks`` attribute & will trigger a warning.
@@ -53,6 +55,24 @@ class CompatChecksTestCase(TestCase):
with self.settings(TEST_RUNNER='myapp.test.CustomRunnner'):
self.assertEqual(len(django_1_6_0.run_checks()), 0)
+ def test_boolean_field_default_value(self):
+ with self.settings(TEST_RUNNER='myapp.test.CustomRunnner'):
+ # We patch the field's default value to trigger the warning
+ boolean_field = Book._meta.get_field('is_published')
+ old_default = boolean_field.default
+ try:
+ boolean_field.default = NOT_PROVIDED
+ result = django_1_6_0.run_checks()
+ self.assertEqual(len(result), 1)
+ self.assertTrue("You have not set a default value for one or more BooleanFields" in result[0])
+ self.assertTrue('check.Book: "is_published"' in result[0])
+ # We did not patch the BlogPost.is_published field so
+ # there should not be a warning about it
+ self.assertFalse('check.BlogPost' in result[0])
+ finally:
+ # Restore the ``default``
+ boolean_field.default = old_default
+
def test_check_compatibility(self):
with self.settings(TEST_RUNNER='django.test.runner.DiscoverRunner'):
result = base.check_compatibility()
diff --git a/tests/comment_tests/models.py b/tests/comment_tests/models.py
index 472b66decd..a2b27e7e87 100644
--- a/tests/comment_tests/models.py
+++ b/tests/comment_tests/models.py
@@ -30,7 +30,7 @@ class Entry(models.Model):
title = models.CharField(max_length=250)
body = models.TextField()
pub_date = models.DateField()
- enable_comments = models.BooleanField()
+ enable_comments = models.BooleanField(default=False)
def __str__(self):
return self.title
diff --git a/tests/custom_managers/models.py b/tests/custom_managers/models.py
index 44d5eb70da..cba375f4d7 100644
--- a/tests/custom_managers/models.py
+++ b/tests/custom_managers/models.py
@@ -67,7 +67,7 @@ CustomManager = BaseCustomManager.from_queryset(CustomQuerySet)
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
- fun = models.BooleanField()
+ fun = models.BooleanField(default=False)
objects = PersonManager()
custom_queryset_default_manager = CustomQuerySet.as_manager()
@@ -80,7 +80,7 @@ class Person(models.Model):
class Book(models.Model):
title = models.CharField(max_length=50)
author = models.CharField(max_length=30)
- is_published = models.BooleanField()
+ is_published = models.BooleanField(default=False)
published_objects = PublishedBookManager()
authors = models.ManyToManyField(Person, related_name='books')
diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py
index 725b673903..7db872001d 100644
--- a/tests/defaultfilters/tests.py
+++ b/tests/defaultfilters/tests.py
@@ -647,22 +647,21 @@ class DefaultFiltersI18NTests(TransRealMixin, TestCase):
def test_localized_filesizeformat(self):
# NOTE: \xa0 avoids wrapping between value and unit
- with self.settings(USE_L10N=True):
- with translation.override('de', deactivate=True):
- self.assertEqual(filesizeformat(1023), '1023\xa0Bytes')
- self.assertEqual(filesizeformat(1024), '1,0\xa0KB')
- self.assertEqual(filesizeformat(10*1024), '10,0\xa0KB')
- self.assertEqual(filesizeformat(1024*1024-1), '1024,0\xa0KB')
- self.assertEqual(filesizeformat(1024*1024), '1,0\xa0MB')
- self.assertEqual(filesizeformat(1024*1024*50), '50,0\xa0MB')
- self.assertEqual(filesizeformat(1024*1024*1024-1), '1024,0\xa0MB')
- self.assertEqual(filesizeformat(1024*1024*1024), '1,0\xa0GB')
- self.assertEqual(filesizeformat(1024*1024*1024*1024), '1,0\xa0TB')
- self.assertEqual(filesizeformat(1024*1024*1024*1024*1024),
- '1,0\xa0PB')
- self.assertEqual(filesizeformat(1024*1024*1024*1024*1024*2000),
- '2000,0\xa0PB')
- self.assertEqual(filesizeformat(complex(1,-1)), '0\xa0Bytes')
- self.assertEqual(filesizeformat(""), '0\xa0Bytes')
- self.assertEqual(filesizeformat("\N{GREEK SMALL LETTER ALPHA}"),
- '0\xa0Bytes')
+ with self.settings(USE_L10N=True), translation.override('de', deactivate=True):
+ self.assertEqual(filesizeformat(1023), '1023\xa0Bytes')
+ self.assertEqual(filesizeformat(1024), '1,0\xa0KB')
+ self.assertEqual(filesizeformat(10*1024), '10,0\xa0KB')
+ self.assertEqual(filesizeformat(1024*1024-1), '1024,0\xa0KB')
+ self.assertEqual(filesizeformat(1024*1024), '1,0\xa0MB')
+ self.assertEqual(filesizeformat(1024*1024*50), '50,0\xa0MB')
+ self.assertEqual(filesizeformat(1024*1024*1024-1), '1024,0\xa0MB')
+ self.assertEqual(filesizeformat(1024*1024*1024), '1,0\xa0GB')
+ self.assertEqual(filesizeformat(1024*1024*1024*1024), '1,0\xa0TB')
+ self.assertEqual(filesizeformat(1024*1024*1024*1024*1024),
+ '1,0\xa0PB')
+ self.assertEqual(filesizeformat(1024*1024*1024*1024*1024*2000),
+ '2000,0\xa0PB')
+ self.assertEqual(filesizeformat(complex(1,-1)), '0\xa0Bytes')
+ self.assertEqual(filesizeformat(""), '0\xa0Bytes')
+ self.assertEqual(filesizeformat("\N{GREEK SMALL LETTER ALPHA}"),
+ '0\xa0Bytes')
diff --git a/tests/defer/tests.py b/tests/defer/tests.py
index 1df312e1bf..b66b173f7a 100644
--- a/tests/defer/tests.py
+++ b/tests/defer/tests.py
@@ -183,3 +183,9 @@ class DeferTests(TestCase):
with self.assertNumQueries(0):
bc_deferred.id
self.assertEqual(bc_deferred.pk, bc_deferred.id)
+
+ def test_eq(self):
+ s1 = Secondary.objects.create(first="x1", second="y1")
+ s1_defer = Secondary.objects.only('pk').get(pk=s1.pk)
+ self.assertEqual(s1, s1_defer)
+ self.assertEqual(s1_defer, s1)
diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
index cdd9720374..2a6f602e3e 100644
--- a/tests/file_storage/tests.py
+++ b/tests/file_storage/tests.py
@@ -462,6 +462,18 @@ class FileStoragePermissions(unittest.TestCase):
mode = os.stat(self.storage.path(fname))[0] & 0o777
self.assertEqual(mode, 0o666 & ~self.umask)
+ @override_settings(FILE_UPLOAD_DIRECTORY_PERMISSIONS=0o765)
+ def test_file_upload_directory_permissions(self):
+ name = self.storage.save("the_directory/the_file", ContentFile("data"))
+ dir_mode = os.stat(os.path.dirname(self.storage.path(name)))[0] & 0o777
+ self.assertEqual(dir_mode, 0o765)
+
+ @override_settings(FILE_UPLOAD_DIRECTORY_PERMISSIONS=None)
+ def test_file_upload_directory_default_permissions(self):
+ name = self.storage.save("the_directory/the_file", ContentFile("data"))
+ dir_mode = os.stat(os.path.dirname(self.storage.path(name)))[0] & 0o777
+ self.assertEqual(dir_mode, 0o777 & ~self.umask)
+
class FileStoragePathParsing(unittest.TestCase):
def setUp(self):
self.storage_dir = tempfile.mkdtemp()
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py
index cd81cc68a2..77582162a8 100644
--- a/tests/foreign_object/tests.py
+++ b/tests/foreign_object/tests.py
@@ -132,7 +132,6 @@ class MultiColumnFKTests(TestCase):
],
attrgetter('person_id')
)
-
self.assertQuerysetEqual(
Membership.objects.filter(person__in=Person.objects.filter(name='Jim')), [
self.jim.id,
@@ -140,6 +139,24 @@ class MultiColumnFKTests(TestCase):
attrgetter('person_id')
)
+ def test_double_nested_query(self):
+ m1 = Membership.objects.create(membership_country_id=self.usa.id, person_id=self.bob.id,
+ group_id=self.cia.id)
+ m2 = Membership.objects.create(membership_country_id=self.usa.id, person_id=self.jim.id,
+ group_id=self.cia.id)
+ Friendship.objects.create(from_friend_country_id=self.usa.id, from_friend_id=self.bob.id,
+ to_friend_country_id=self.usa.id, to_friend_id=self.jim.id)
+ self.assertQuerysetEqual(Membership.objects.filter(
+ person__in=Person.objects.filter(
+ from_friend__in=Friendship.objects.filter(
+ to_friend__in=Person.objects.all()))),
+ [m1], lambda x: x)
+ self.assertQuerysetEqual(Membership.objects.exclude(
+ person__in=Person.objects.filter(
+ from_friend__in=Friendship.objects.filter(
+ to_friend__in=Person.objects.all()))),
+ [m2], lambda x: x)
+
def test_select_related_foreignkey_forward_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)
diff --git a/tests/forms_tests/tests/test_fields.py b/tests/forms_tests/tests/test_fields.py
index f02593e488..a4e81d31ae 100644
--- a/tests/forms_tests/tests/test_fields.py
+++ b/tests/forms_tests/tests/test_fields.py
@@ -286,11 +286,10 @@ class FieldsTests(SimpleTestCase):
n = 4.35
self.assertFalse(f._has_changed(n, '4.3500'))
- with translation.override('fr'):
- with self.settings(USE_L10N=True):
- f = FloatField(localize=True)
- localized_n = formats.localize_input(n) # -> '4,35' in French
- self.assertFalse(f._has_changed(n, localized_n))
+ with translation.override('fr'), self.settings(USE_L10N=True):
+ f = FloatField(localize=True)
+ localized_n = formats.localize_input(n) # -> '4,35' in French
+ self.assertFalse(f._has_changed(n, localized_n))
# DecimalField ################################################################
@@ -399,11 +398,10 @@ class FieldsTests(SimpleTestCase):
self.assertFalse(f._has_changed(d, '0.10'))
self.assertTrue(f._has_changed(d, '0.101'))
- with translation.override('fr'):
- with self.settings(USE_L10N=True):
- f = DecimalField(max_digits=2, decimal_places=2, localize=True)
- localized_d = formats.localize_input(d) # -> '0,1' in French
- self.assertFalse(f._has_changed(d, localized_d))
+ with translation.override('fr'), self.settings(USE_L10N=True):
+ f = DecimalField(max_digits=2, decimal_places=2, localize=True)
+ localized_d = formats.localize_input(d) # -> '0,1' in French
+ self.assertFalse(f._has_changed(d, localized_d))
# DateField ###################################################################
diff --git a/tests/forms_tests/tests/test_widgets.py b/tests/forms_tests/tests/test_widgets.py
index 06ee2d6c53..3f11771d7a 100644
--- a/tests/forms_tests/tests/test_widgets.py
+++ b/tests/forms_tests/tests/test_widgets.py
@@ -833,6 +833,22 @@ beatle J R Ringo False""")
with self.assertRaises(IndexError):
r[42]
+ def test_subwidget(self):
+ # Each subwidget tag gets a separate ID when the widget has an ID specified
+ self.assertHTMLEqual("\n".join([c.tag() for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))]), """<input checked="checked" type="checkbox" name="letters" value="a" id="abc_0" />
+<input type="checkbox" name="letters" value="b" id="abc_1" />
+<input checked="checked" type="checkbox" name="letters" value="c" id="abc_2" />""")
+
+ # Each subwidget tag does not get an ID if the widget does not have an ID specified
+ self.assertHTMLEqual("\n".join([c.tag() for c in CheckboxSelectMultiple().subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))]), """<input checked="checked" type="checkbox" name="letters" value="a" />
+<input type="checkbox" name="letters" value="b" />
+<input checked="checked" type="checkbox" name="letters" value="c" />""")
+
+ # The id_for_label property of the subwidget should return the ID that is used on the subwidget's tag
+ self.assertHTMLEqual("\n".join(['<input type="checkbox" name="letters" value="%s" id="%s" />' % (c.choice_value, c.id_for_label) for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', [], choices=zip(list('abc'), list('ABC')))]), """<input type="checkbox" name="letters" value="a" id="abc_0" />
+<input type="checkbox" name="letters" value="b" id="abc_1" />
+<input type="checkbox" name="letters" value="c" id="abc_2" />""")
+
def test_multi(self):
class MyMultiWidget(MultiWidget):
def decompress(self, value):
diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py
index 211df8aa3d..d819a53c0e 100644
--- a/tests/generic_relations/models.py
+++ b/tests/generic_relations/models.py
@@ -92,7 +92,7 @@ class GeckoManager(models.Manager):
return super(GeckoManager, self).get_queryset().filter(has_tail=True)
class Gecko(models.Model):
- has_tail = models.BooleanField()
+ has_tail = models.BooleanField(default=False)
objects = GeckoManager()
# To test fix for #11263
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 05d1065a75..12e325b773 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -746,11 +746,11 @@ class FormattingTests(TransRealMixin, TestCase):
self.assertEqual('.', get_format('DECIMAL_SEPARATOR', lang='en'))
def test_get_format_modules_stability(self):
- with self.settings(FORMAT_MODULE_PATH='i18n.other.locale'):
- with translation.override('de', deactivate=True):
- old = str("%r") % get_format_modules(reverse=True)
- new = str("%r") % get_format_modules(reverse=True) # second try
- self.assertEqual(new, old, 'Value returned by get_formats_modules() must be preserved between calls.')
+ with self.settings(FORMAT_MODULE_PATH='i18n.other.locale'), \
+ translation.override('de', deactivate=True):
+ old = str("%r") % get_format_modules(reverse=True)
+ new = str("%r") % get_format_modules(reverse=True) # second try
+ self.assertEqual(new, old, 'Value returned by get_formats_modules() must be preserved between calls.')
def test_localize_templatetag_and_filter(self):
"""
@@ -1062,9 +1062,8 @@ class MultipleLocaleActivationTests(TransRealMixin, TestCase):
def test_multiple_locale_filter(self):
with translation.override('de'):
t = Template("{% load i18n %}{{ 0|yesno:_('yes,no,maybe') }}")
- with translation.override(self._old_language):
- with translation.override('nl'):
- self.assertEqual(t.render(Context({})), 'nee')
+ with translation.override(self._old_language), translation.override('nl'):
+ self.assertEqual(t.render(Context({})), 'nee')
def test_multiple_locale_filter_deactivate(self):
with translation.override('de', deactivate=True):
@@ -1083,9 +1082,8 @@ class MultipleLocaleActivationTests(TransRealMixin, TestCase):
def test_multiple_locale(self):
with translation.override('de'):
t = Template("{{ _('No') }}")
- with translation.override(self._old_language):
- with translation.override('nl'):
- self.assertEqual(t.render(Context({})), 'Nee')
+ with translation.override(self._old_language), translation.override('nl'):
+ self.assertEqual(t.render(Context({})), 'Nee')
def test_multiple_locale_deactivate(self):
with translation.override('de', deactivate=True):
@@ -1104,9 +1102,8 @@ class MultipleLocaleActivationTests(TransRealMixin, TestCase):
def test_multiple_locale_loadi18n(self):
with translation.override('de'):
t = Template("{% load i18n %}{{ _('No') }}")
- with translation.override(self._old_language):
- with translation.override('nl'):
- self.assertEqual(t.render(Context({})), 'Nee')
+ with translation.override(self._old_language), translation.override('nl'):
+ self.assertEqual(t.render(Context({})), 'Nee')
def test_multiple_locale_loadi18n_deactivate(self):
with translation.override('de', deactivate=True):
@@ -1125,9 +1122,8 @@ class MultipleLocaleActivationTests(TransRealMixin, TestCase):
def test_multiple_locale_trans(self):
with translation.override('de'):
t = Template("{% load i18n %}{% trans 'No' %}")
- with translation.override(self._old_language):
- with translation.override('nl'):
- self.assertEqual(t.render(Context({})), 'Nee')
+ with translation.override(self._old_language), translation.override('nl'):
+ self.assertEqual(t.render(Context({})), 'Nee')
def test_multiple_locale_deactivate_trans(self):
with translation.override('de', deactivate=True):
@@ -1146,9 +1142,8 @@ class MultipleLocaleActivationTests(TransRealMixin, TestCase):
def test_multiple_locale_btrans(self):
with translation.override('de'):
t = Template("{% load i18n %}{% blocktrans %}No{% endblocktrans %}")
- with translation.override(self._old_language):
- with translation.override('nl'):
- self.assertEqual(t.render(Context({})), 'Nee')
+ with translation.override(self._old_language), translation.override('nl'):
+ self.assertEqual(t.render(Context({})), 'Nee')
def test_multiple_locale_deactivate_btrans(self):
with translation.override('de', deactivate=True):
diff --git a/tests/inspectdb/models.py b/tests/inspectdb/models.py
index 2862f7f3dc..c25202f248 100644
--- a/tests/inspectdb/models.py
+++ b/tests/inspectdb/models.py
@@ -37,7 +37,7 @@ class SpecialColumnName(models.Model):
class ColumnTypes(models.Model):
id = models.AutoField(primary_key=True)
big_int_field = models.BigIntegerField()
- bool_field = models.BooleanField()
+ bool_field = models.BooleanField(default=False)
null_bool_field = models.NullBooleanField()
char_field = models.CharField(max_length=10)
comma_separated_int_field = models.CommaSeparatedIntegerField(max_length=99)
diff --git a/tests/logging_tests/tests.py b/tests/logging_tests/tests.py
index 8ba4702aba..ef9f979e7e 100644
--- a/tests/logging_tests/tests.py
+++ b/tests/logging_tests/tests.py
@@ -355,20 +355,19 @@ class SettingsConfigureLogging(TestCase):
self.assertTrue(dictConfig.called)
+@override_settings(DEBUG=True)
class SecurityLoggerTest(TestCase):
urls = 'logging_tests.urls'
def test_suspicious_operation_creates_log_message(self):
- with self.settings(DEBUG=True):
- with patch_logger('django.security.SuspiciousOperation', 'error') as calls:
- response = self.client.get('/suspicious/')
- self.assertEqual(len(calls), 1)
- self.assertEqual(calls[0], 'dubious')
+ with patch_logger('django.security.SuspiciousOperation', 'error') as calls:
+ response = self.client.get('/suspicious/')
+ self.assertEqual(len(calls), 1)
+ self.assertEqual(calls[0], 'dubious')
def test_suspicious_operation_uses_sublogger(self):
- with self.settings(DEBUG=True):
- with patch_logger('django.security.DisallowedHost', 'error') as calls:
- response = self.client.get('/suspicious_spec/')
- self.assertEqual(len(calls), 1)
- self.assertEqual(calls[0], 'dubious')
+ with patch_logger('django.security.DisallowedHost', 'error') as calls:
+ response = self.client.get('/suspicious_spec/')
+ self.assertEqual(len(calls), 1)
+ self.assertEqual(calls[0], 'dubious')
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
index 2d602d6412..8c304cc726 100644
--- a/tests/model_fields/models.py
+++ b/tests/model_fields/models.py
@@ -58,7 +58,7 @@ class NullBooleanModel(models.Model):
nbfield = models.NullBooleanField()
class BooleanModel(models.Model):
- bfield = models.BooleanField()
+ bfield = models.BooleanField(default=None)
string = models.CharField(max_length=10, default='abc')
class FksToBooleans(models.Model):
@@ -72,7 +72,7 @@ class RenamedField(models.Model):
class VerboseNameField(models.Model):
id = models.AutoField("verbose pk", primary_key=True)
field1 = models.BigIntegerField("verbose field1")
- field2 = models.BooleanField("verbose field2")
+ field2 = models.BooleanField("verbose field2", default=False)
field3 = models.CharField("verbose field3", max_length=10)
field4 = models.CommaSeparatedIntegerField("verbose field4", max_length=99)
field5 = models.DateField("verbose field5")
diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py
index 378e6280cc..429337f31c 100644
--- a/tests/model_fields/tests.py
+++ b/tests/model_fields/tests.py
@@ -12,7 +12,7 @@ from django.db.models.fields import (
AutoField, BigIntegerField, BinaryField, BooleanField, CharField,
CommaSeparatedIntegerField, DateField, DateTimeField, DecimalField,
EmailField, FilePathField, FloatField, IntegerField, IPAddressField,
- GenericIPAddressField, NullBooleanField, PositiveIntegerField,
+ GenericIPAddressField, NOT_PROVIDED, NullBooleanField, PositiveIntegerField,
PositiveSmallIntegerField, SlugField, SmallIntegerField, TextField,
TimeField, URLField)
from django.db.models.fields.files import FileField, ImageField
@@ -275,10 +275,23 @@ class BooleanFieldTests(unittest.TestCase):
Check that a BooleanField defaults to None -- which isn't
a valid value (#15124).
"""
- b = BooleanModel()
- self.assertIsNone(b.bfield)
- with self.assertRaises(IntegrityError):
- b.save()
+ # Patch the boolean field's default value. We give it a default
+ # value when defining the model to satisfy the check tests
+ # #20895.
+ boolean_field = BooleanModel._meta.get_field('bfield')
+ self.assertTrue(boolean_field.has_default())
+ old_default = boolean_field.default
+ try:
+ boolean_field.default = NOT_PROVIDED
+ # check patch was succcessful
+ self.assertFalse(boolean_field.has_default())
+ b = BooleanModel()
+ self.assertIsNone(b.bfield)
+ with self.assertRaises(IntegrityError):
+ b.save()
+ finally:
+ boolean_field.default = old_default
+
nb = NullBooleanModel()
self.assertIsNone(nb.nbfield)
nb.save() # no error
diff --git a/tests/model_formsets/models.py b/tests/model_formsets/models.py
index ae152448ab..adeb3455a4 100644
--- a/tests/model_formsets/models.py
+++ b/tests/model_formsets/models.py
@@ -117,7 +117,7 @@ class OwnerProfile(models.Model):
@python_2_unicode_compatible
class Restaurant(Place):
- serves_pizza = models.BooleanField()
+ serves_pizza = models.BooleanField(default=False)
def __str__(self):
return self.name
@@ -141,11 +141,11 @@ class Price(models.Model):
unique_together = (('price', 'quantity'),)
class MexicanRestaurant(Restaurant):
- serves_tacos = models.BooleanField()
+ serves_tacos = models.BooleanField(default=False)
class ClassyMexicanRestaurant(MexicanRestaurant):
restaurant = models.OneToOneField(MexicanRestaurant, parent_link=True, primary_key=True)
- tacos_are_yummy = models.BooleanField()
+ tacos_are_yummy = models.BooleanField(default=False)
# models for testing unique_together validation when a fk is involved and
# using inlineformset_factory.
diff --git a/tests/model_inheritance/models.py b/tests/model_inheritance/models.py
index 2101f394f7..106645d23c 100644
--- a/tests/model_inheritance/models.py
+++ b/tests/model_inheritance/models.py
@@ -63,7 +63,7 @@ class Attachment(models.Model):
return self.content
class Comment(Attachment):
- is_spam = models.BooleanField()
+ is_spam = models.BooleanField(default=False)
class Link(Attachment):
url = models.URLField()
@@ -96,8 +96,8 @@ class Rating(models.Model):
@python_2_unicode_compatible
class Restaurant(Place, Rating):
- serves_hot_dogs = models.BooleanField()
- serves_pizza = models.BooleanField()
+ serves_hot_dogs = models.BooleanField(default=False)
+ serves_pizza = models.BooleanField(default=False)
chef = models.ForeignKey(Chef, null=True, blank=True)
class Meta(Rating.Meta):
@@ -108,7 +108,7 @@ class Restaurant(Place, Rating):
@python_2_unicode_compatible
class ItalianRestaurant(Restaurant):
- serves_gnocchi = models.BooleanField()
+ serves_gnocchi = models.BooleanField(default=False)
def __str__(self):
return "%s the italian restaurant" % self.name
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index eb50d30cf8..b8ab0c8581 100644
--- a/tests/model_inheritance/tests.py
+++ b/tests/model_inheritance/tests.py
@@ -8,8 +8,9 @@ from django.test import TestCase
from django.test.utils import CaptureQueriesContext
from django.utils import six
-from .models import (Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place,
- Post, Restaurant, Student, StudentWorker, Supplier, Worker, MixinModel)
+from .models import (
+ Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place, Post,
+ Restaurant, Student, StudentWorker, Supplier, Worker, MixinModel)
class ModelInheritanceTests(TestCase):
@@ -20,7 +21,7 @@ class ModelInheritanceTests(TestCase):
# information for programming purposes, but still completely
# independent separate models at the database level.
w1 = Worker.objects.create(name="Fred", age=35, job="Quarry worker")
- w2 = Worker.objects.create(name="Barney", age=34, job="Quarry worker")
+ Worker.objects.create(name="Barney", age=34, job="Quarry worker")
s = Student.objects.create(name="Pebbles", age=5, school_class="1B")
@@ -48,10 +49,12 @@ class ModelInheritanceTests(TestCase):
# A StudentWorker which does not exist is both a Student and Worker
# which does not exist.
- self.assertRaises(Student.DoesNotExist,
+ self.assertRaises(
+ Student.DoesNotExist,
StudentWorker.objects.get, pk=12321321
)
- self.assertRaises(Worker.DoesNotExist,
+ self.assertRaises(
+ Worker.DoesNotExist,
StudentWorker.objects.get, pk=12321321
)
@@ -67,10 +70,12 @@ class ModelInheritanceTests(TestCase):
sw2.age = 24
sw2.save()
- self.assertRaises(Student.MultipleObjectsReturned,
+ self.assertRaises(
+ Student.MultipleObjectsReturned,
StudentWorker.objects.get, pk__lt=sw2.pk + 100
)
- self.assertRaises(Worker.MultipleObjectsReturned,
+ self.assertRaises(
+ Worker.MultipleObjectsReturned,
StudentWorker.objects.get, pk__lt=sw2.pk + 100
)
@@ -85,16 +90,16 @@ class ModelInheritanceTests(TestCase):
# The Post model doesn't have an attribute called
# 'attached_%(class)s_set'.
- self.assertRaises(AttributeError,
- getattr, post, "attached_%(class)s_set"
+ self.assertRaises(
+ AttributeError, getattr, post, "attached_%(class)s_set"
)
# The Place/Restaurant/ItalianRestaurant models all exist as
# independent models. However, the subclasses also have transparent
# access to the fields of their ancestors.
# Create a couple of Places.
- p1 = Place.objects.create(name="Master Shakes", address="666 W. Jersey")
- p2 = Place.objects.create(name="Ace Harware", address="1013 N. Ashland")
+ Place.objects.create(name="Master Shakes", address="666 W. Jersey")
+ Place.objects.create(name="Ace Harware", address="1013 N. Ashland")
# Test constructor for Restaurant.
r = Restaurant.objects.create(
@@ -134,11 +139,13 @@ class ModelInheritanceTests(TestCase):
# the right order.
self.assertEqual(
[f.name for f in Restaurant._meta.fields],
- ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs", "serves_pizza", "chef"]
+ ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
+ "serves_pizza", "chef"]
)
self.assertEqual(
[f.name for f in ItalianRestaurant._meta.fields],
- ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs", "serves_pizza", "chef", "restaurant_ptr", "serves_gnocchi"],
+ ["id", "name", "address", "place_ptr", "rating", "serves_hot_dogs",
+ "serves_pizza", "chef", "restaurant_ptr", "serves_gnocchi"],
)
self.assertEqual(Restaurant._meta.ordering, ["-rating"])
@@ -146,8 +153,8 @@ class ModelInheritanceTests(TestCase):
# Restaurant object cannot access that reverse relation, since it's not
# part of the Place-Supplier Hierarchy.
self.assertQuerysetEqual(Place.objects.filter(supplier__name="foo"), [])
- self.assertRaises(FieldError,
- Restaurant.objects.filter, supplier__name="foo"
+ self.assertRaises(
+ FieldError, Restaurant.objects.filter, supplier__name="foo"
)
# Parent fields can be used directly in filters on the child model.
@@ -185,16 +192,19 @@ class ModelInheritanceTests(TestCase):
# This won't work because the Demon Dogs restaurant is not an Italian
# restaurant.
- self.assertRaises(ItalianRestaurant.DoesNotExist,
+ self.assertRaises(
+ ItalianRestaurant.DoesNotExist,
lambda: p.restaurant.italianrestaurant
)
# An ItalianRestaurant which does not exist is also a Place which does
# not exist.
- self.assertRaises(Place.DoesNotExist,
+ self.assertRaises(
+ Place.DoesNotExist,
ItalianRestaurant.objects.get, name="The Noodle Void"
)
# MultipleObjectsReturned is also inherited.
- self.assertRaises(Place.MultipleObjectsReturned,
+ self.assertRaises(
+ Place.MultipleObjectsReturned,
Restaurant.objects.get, id__lt=12321
)
@@ -207,8 +217,8 @@ class ModelInheritanceTests(TestCase):
# This won't work because the Place we select is not a Restaurant (it's
# a Supplier).
p = Place.objects.get(name="Joe's Chickens")
- self.assertRaises(Restaurant.DoesNotExist,
- lambda: p.restaurant
+ self.assertRaises(
+ Restaurant.DoesNotExist, lambda: p.restaurant
)
self.assertEqual(p.supplier, s1)
@@ -233,10 +243,10 @@ class ModelInheritanceTests(TestCase):
attrgetter("name"),
)
- park1 = ParkingLot.objects.create(
+ ParkingLot.objects.create(
name="Main St", address="111 Main St", main_site=s1
)
- park2 = ParkingLot.objects.create(
+ ParkingLot.objects.create(
name="Well Lit", address="124 Sesame St", main_site=ir
)
@@ -268,11 +278,11 @@ class ModelInheritanceTests(TestCase):
# select_related works with fields from the parent object as if they
# were a normal part of the model.
- self.assertNumQueries(2,
- lambda: ItalianRestaurant.objects.all()[0].chef
+ self.assertNumQueries(
+ 2, lambda: ItalianRestaurant.objects.all()[0].chef
)
- self.assertNumQueries(1,
- lambda: ItalianRestaurant.objects.select_related("chef")[0].chef
+ self.assertNumQueries(
+ 1, lambda: ItalianRestaurant.objects.select_related("chef")[0].chef
)
def test_mixin_init(self):
@@ -318,3 +328,32 @@ class ModelInheritanceTests(TestCase):
sql = query['sql']
if 'UPDATE' in sql:
self.assertEqual(expected_sql, sql)
+
+ def test_eq(self):
+ # Equality doesn't transfer in multitable inheritance.
+ self.assertNotEqual(Place(id=1), Restaurant(id=1))
+ self.assertNotEqual(Restaurant(id=1), Place(id=1))
+
+ def test_ticket_12567(self):
+ r = Restaurant.objects.create(name='n1', address='a1')
+ s = Supplier.objects.create(name='s1', address='a2')
+ self.assertQuerysetEqual(
+ Place.objects.filter(supplier__isnull=False),
+ [Place.objects.get(pk=s.pk)],
+ lambda x: x
+ )
+ self.assertQuerysetEqual(
+ Place.objects.filter(supplier__isnull=True),
+ [Place.objects.get(pk=r.pk)],
+ lambda x: x
+ )
+ self.assertQuerysetEqual(
+ Place.objects.exclude(supplier__isnull=False),
+ [Place.objects.get(pk=r.pk)],
+ lambda x: x
+ )
+ self.assertQuerysetEqual(
+ Place.objects.exclude(supplier__isnull=True),
+ [Place.objects.get(pk=s.pk)],
+ lambda x: x
+ )
diff --git a/tests/model_inheritance_regress/models.py b/tests/model_inheritance_regress/models.py
index 811c8175bb..bf076a47c6 100644
--- a/tests/model_inheritance_regress/models.py
+++ b/tests/model_inheritance_regress/models.py
@@ -18,15 +18,15 @@ class Place(models.Model):
@python_2_unicode_compatible
class Restaurant(Place):
- serves_hot_dogs = models.BooleanField()
- serves_pizza = models.BooleanField()
+ serves_hot_dogs = models.BooleanField(default=False)
+ serves_pizza = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.name
@python_2_unicode_compatible
class ItalianRestaurant(Restaurant):
- serves_gnocchi = models.BooleanField()
+ serves_gnocchi = models.BooleanField(default=False)
def __str__(self):
return "%s the italian restaurant" % self.name
@@ -50,6 +50,19 @@ class ParkingLot3(Place):
primary_key = models.AutoField(primary_key=True)
parent = models.OneToOneField(Place, parent_link=True)
+class ParkingLot4(models.Model):
+ # Test parent_link connector can be discovered in abstract classes.
+ parent = models.OneToOneField(Place, parent_link=True)
+
+ class Meta:
+ abstract = True
+
+class ParkingLot4A(ParkingLot4, Place):
+ pass
+
+class ParkingLot4B(Place, ParkingLot4):
+ pass
+
class Supplier(models.Model):
restaurant = models.ForeignKey(Restaurant)
@@ -171,7 +184,7 @@ class Station(SearchableLocation):
class BusStation(Station):
bus_routes = models.CommaSeparatedIntegerField(max_length=128)
- inbound = models.BooleanField()
+ inbound = models.BooleanField(default=False)
class TrainStation(Station):
zone = models.IntegerField()
diff --git a/tests/model_inheritance_regress/tests.py b/tests/model_inheritance_regress/tests.py
index 10a1230685..7f78fc7a98 100644
--- a/tests/model_inheritance_regress/tests.py
+++ b/tests/model_inheritance_regress/tests.py
@@ -14,7 +14,8 @@ from .models import (Place, Restaurant, ItalianRestaurant, ParkingLot,
ParkingLot2, ParkingLot3, Supplier, Wholesaler, Child, SelfRefParent,
SelfRefChild, ArticleWithAuthor, M2MChild, QualityControl, DerivedM,
Person, BirthdayParty, BachelorParty, MessyBachelorParty,
- InternalCertificationAudit, BusStation, TrainStation, User, Profile)
+ InternalCertificationAudit, BusStation, TrainStation, User, Profile,
+ ParkingLot4A, ParkingLot4B)
class ModelInheritanceTest(TestCase):
@@ -311,6 +312,19 @@ class ModelInheritanceTest(TestCase):
ParkingLot3._meta.get_ancestor_link(Place).name,
"parent")
+ def test_use_explicit_o2o_to_parent_from_abstract_model(self):
+ self.assertEqual(ParkingLot4A._meta.pk.name, "parent")
+ ParkingLot4A.objects.create(
+ name="Parking4A",
+ address='21 Jump Street',
+ )
+
+ self.assertEqual(ParkingLot4B._meta.pk.name, "parent")
+ ParkingLot4A.objects.create(
+ name="Parking4B",
+ address='21 Jump Street',
+ )
+
def test_all_fields_from_abstract_base_class(self):
"""
Regression tests for #7588
diff --git a/tests/model_inheritance_select_related/models.py b/tests/model_inheritance_select_related/models.py
index 6b28772620..46c67cf07d 100644
--- a/tests/model_inheritance_select_related/models.py
+++ b/tests/model_inheritance_select_related/models.py
@@ -20,8 +20,8 @@ class Place(models.Model):
@python_2_unicode_compatible
class Restaurant(Place):
- serves_sushi = models.BooleanField()
- serves_steak = models.BooleanField()
+ serves_sushi = models.BooleanField(default=False)
+ serves_steak = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.name
diff --git a/tests/modeladmin/models.py b/tests/modeladmin/models.py
index fdbcabd187..4789e35a43 100644
--- a/tests/modeladmin/models.py
+++ b/tests/modeladmin/models.py
@@ -32,7 +32,7 @@ class ValidationTestModel(models.Model):
slug = models.SlugField()
users = models.ManyToManyField(User)
state = models.CharField(max_length=2, choices=(("CO", "Colorado"), ("WA", "Washington")))
- is_active = models.BooleanField()
+ is_active = models.BooleanField(default=False)
pub_date = models.DateTimeField()
band = models.ForeignKey(Band)
no = models.IntegerField(verbose_name="Number", blank=True, null=True) # This field is intentionally 2 characters long. See #16080.
diff --git a/tests/one_to_one/models.py b/tests/one_to_one/models.py
index 9599496cb7..ff809be22d 100644
--- a/tests/one_to_one/models.py
+++ b/tests/one_to_one/models.py
@@ -22,8 +22,8 @@ class Place(models.Model):
@python_2_unicode_compatible
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
- serves_hot_dogs = models.BooleanField()
- serves_pizza = models.BooleanField()
+ serves_hot_dogs = models.BooleanField(default=False)
+ serves_pizza = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.place.name
diff --git a/tests/one_to_one_regress/models.py b/tests/one_to_one_regress/models.py
index 058baafc82..9b65edf2ab 100644
--- a/tests/one_to_one_regress/models.py
+++ b/tests/one_to_one_regress/models.py
@@ -15,8 +15,8 @@ class Place(models.Model):
@python_2_unicode_compatible
class Restaurant(models.Model):
place = models.OneToOneField(Place)
- serves_hot_dogs = models.BooleanField()
- serves_pizza = models.BooleanField()
+ serves_hot_dogs = models.BooleanField(default=False)
+ serves_pizza = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.place.name
diff --git a/tests/one_to_one_regress/tests.py b/tests/one_to_one_regress/tests.py
index 7d82194abb..0e20f19acb 100644
--- a/tests/one_to_one_regress/tests.py
+++ b/tests/one_to_one_regress/tests.py
@@ -141,12 +141,10 @@ class OneToOneRegressionTests(TestCase):
"""
p = Place(name='Zombie Cats', address='Not sure')
p.save()
- with self.assertNumQueries(1):
- with self.assertRaises(Restaurant.DoesNotExist):
- p.restaurant
- with self.assertNumQueries(0):
- with self.assertRaises(Restaurant.DoesNotExist):
- p.restaurant
+ with self.assertNumQueries(1), self.assertRaises(Restaurant.DoesNotExist):
+ p.restaurant
+ with self.assertNumQueries(0), self.assertRaises(Restaurant.DoesNotExist):
+ p.restaurant
def test_reverse_object_cached_when_related_is_accessed(self):
"""
@@ -199,9 +197,8 @@ class OneToOneRegressionTests(TestCase):
self.assertEqual(self.p1.undergroundbar, b)
b.place = None
b.save()
- with self.assertNumQueries(0):
- with self.assertRaises(UndergroundBar.DoesNotExist):
- self.p1.undergroundbar
+ with self.assertNumQueries(0), self.assertRaises(UndergroundBar.DoesNotExist):
+ self.p1.undergroundbar
def test_get_reverse_on_unsaved_object(self):
"""
@@ -213,24 +210,21 @@ class OneToOneRegressionTests(TestCase):
p = Place()
# When there's no instance of the origin of the one-to-one
- with self.assertNumQueries(0):
- with self.assertRaises(UndergroundBar.DoesNotExist):
- p.undergroundbar
+ with self.assertNumQueries(0), self.assertRaises(UndergroundBar.DoesNotExist):
+ p.undergroundbar
UndergroundBar.objects.create()
# When there's one instance of the origin
# (p.undergroundbar used to return that instance)
- with self.assertNumQueries(0):
- with self.assertRaises(UndergroundBar.DoesNotExist):
- p.undergroundbar
+ with self.assertNumQueries(0), self.assertRaises(UndergroundBar.DoesNotExist):
+ p.undergroundbar
UndergroundBar.objects.create()
# When there are several instances of the origin
- with self.assertNumQueries(0):
- with self.assertRaises(UndergroundBar.DoesNotExist):
- p.undergroundbar
+ with self.assertNumQueries(0), self.assertRaises(UndergroundBar.DoesNotExist):
+ p.undergroundbar
def test_set_reverse_on_unsaved_object(self):
"""
@@ -239,6 +233,5 @@ class OneToOneRegressionTests(TestCase):
"""
p = Place()
b = UndergroundBar.objects.create()
- with self.assertNumQueries(0):
- with self.assertRaises(ValueError):
- p.undergroundbar = b
+ with self.assertNumQueries(0), self.assertRaises(ValueError):
+ p.undergroundbar = b
diff --git a/tests/proxy_models/admin.py b/tests/proxy_models/admin.py
new file mode 100644
index 0000000000..d2b6319301
--- /dev/null
+++ b/tests/proxy_models/admin.py
@@ -0,0 +1,6 @@
+from django.contrib import admin
+
+from .models import TrackerUser, ProxyTrackerUser
+
+admin.site.register(TrackerUser)
+admin.site.register(ProxyTrackerUser)
diff --git a/tests/proxy_models/fixtures/myhorses.json b/tests/proxy_models/fixtures/myhorses.json
index 15943064c8..97e190a8a2 100644
--- a/tests/proxy_models/fixtures/myhorses.json
+++ b/tests/proxy_models/fixtures/myhorses.json
@@ -1,6 +1,24 @@
[
{
"pk": 100,
+ "model": "auth.user",
+ "fields": {
+ "username": "super",
+ "first_name": "Super",
+ "last_name": "User",
+ "is_active": true,
+ "is_superuser": true,
+ "is_staff": true,
+ "last_login": "2007-05-30 13:20:10",
+ "groups": [],
+ "user_permissions": [],
+ "password": "sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158",
+ "email": "super@example.com",
+ "date_joined": "2007-05-30 13:20:10"
+ }
+ },
+ {
+ "pk": 100,
"model": "proxy_models.BaseUser",
"fields": {
"name": "Django Pony"
@@ -21,4 +39,4 @@
"assignee": 100
}
}
-] \ No newline at end of file
+]
diff --git a/tests/proxy_models/models.py b/tests/proxy_models/models.py
index ffb36657e1..2e5741ab6b 100644
--- a/tests/proxy_models/models.py
+++ b/tests/proxy_models/models.py
@@ -117,9 +117,13 @@ class StateProxy(State):
# Proxy models still works with filters (on related fields)
# and select_related, even when mixed with model inheritance
+@python_2_unicode_compatible
class BaseUser(models.Model):
name = models.CharField(max_length=255)
+ def __str__(self):
+ return ':'.join((self.__class__.__name__, self.name,))
+
class TrackerUser(BaseUser):
status = models.CharField(max_length=50)
@@ -134,7 +138,7 @@ class Issue(models.Model):
assignee = models.ForeignKey(TrackerUser)
def __str__(self):
- return ':'.join((self.__class__.__name__,self.summary,))
+ return ':'.join((self.__class__.__name__, self.summary,))
class Bug(Issue):
version = models.CharField(max_length=50)
diff --git a/tests/proxy_models/tests.py b/tests/proxy_models/tests.py
index 240198cc39..f0c0d046e1 100644
--- a/tests/proxy_models/tests.py
+++ b/tests/proxy_models/tests.py
@@ -10,12 +10,14 @@ from django.db import models, DEFAULT_DB_ALIAS
from django.db.models import signals
from django.db.models.loading import cache
from django.test import TestCase
+from django.test.utils import override_settings
from .models import (MyPerson, Person, StatusPerson, LowerStatusPerson,
MyPersonProxy, Abstract, OtherPerson, User, UserProxy, UserProxyProxy,
Country, State, StateProxy, TrackerUser, BaseUser, Bug, ProxyTrackerUser,
Improvement, ProxyProxyBug, ProxyBug, ProxyImprovement, Issue)
+from .admin import admin as force_admin_model_registration
class ProxyModelTests(TestCase):
@@ -362,9 +364,14 @@ class ProxyModelTests(TestCase):
p = MyPerson.objects.get(pk=100)
self.assertEqual(p.name, 'Elvis Presley')
+ def test_eq(self):
+ self.assertEqual(MyPerson(id=100), Person(id=100))
+
+@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class ProxyModelAdminTests(TestCase):
fixtures = ['myhorses']
+ urls = 'proxy_models.urls'
def test_cascade_delete_proxy_model_admin_warning(self):
"""
@@ -380,3 +387,26 @@ class ProxyModelAdminTests(TestCase):
self.assertTrue(tracker_user in collector.edges.get(None, ()))
self.assertTrue(base_user in collector.edges.get(None, ()))
self.assertTrue(issue in collector.edges.get(tracker_user, ()))
+
+ def test_delete_str_in_model_admin(self):
+ """
+ Test if the admin delete page shows the correct string representation
+ for a proxy model.
+ """
+ user = TrackerUser.objects.get(name='Django Pony')
+ proxy = ProxyTrackerUser.objects.get(name='Django Pony')
+
+ user_str = (
+ 'Tracker user: <a href="/admin/proxy_models/trackeruser/%s/">%s</a>' % (user.pk, user))
+ proxy_str = (
+ 'Proxy tracker user: <a href="/admin/proxy_models/proxytrackeruser/%s/">%s</a>' %
+ (proxy.pk, proxy))
+
+ self.client.login(username='super', password='secret')
+ response = self.client.get('/admin/proxy_models/trackeruser/%s/delete/' % (user.pk,))
+ delete_str = response.context['deleted_objects'][0]
+ self.assertEqual(delete_str, user_str)
+ response = self.client.get('/admin/proxy_models/proxytrackeruser/%s/delete/' % (proxy.pk,))
+ delete_str = response.context['deleted_objects'][0]
+ self.assertEqual(delete_str, proxy_str)
+ self.client.logout()
diff --git a/tests/proxy_models/urls.py b/tests/proxy_models/urls.py
new file mode 100644
index 0000000000..644a34f556
--- /dev/null
+++ b/tests/proxy_models/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls import patterns, include
+
+from django.contrib import admin
+
+urlpatterns = patterns('',
+ (r'^admin/', include(admin.site.urls)),
+)
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 6e03b0d7f6..4d9ffb353f 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -27,7 +27,6 @@ from .models import (
BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book,
MyObject, Order, OrderItem)
-
class BaseQuerysetTest(TestCase):
def assertValueQuerysetEqual(self, qs, values):
return self.assertQuerysetEqual(qs, values, transform=lambda x: x)
@@ -84,6 +83,19 @@ class Queries1Tests(BaseQuerysetTest):
Cover.objects.create(title="first", item=i4)
Cover.objects.create(title="second", item=self.i2)
+ def test_subquery_condition(self):
+ qs1 = Tag.objects.filter(pk__lte=0)
+ qs2 = Tag.objects.filter(parent__in=qs1)
+ qs3 = Tag.objects.filter(parent__in=qs2)
+ self.assertEqual(qs3.query.subq_aliases, set(['T', 'U', 'V']))
+ self.assertIn('v0', str(qs3.query).lower())
+ qs4 = qs3.filter(parent__in=qs1)
+ self.assertEqual(qs4.query.subq_aliases, set(['T', 'U', 'V']))
+ # It is possible to reuse U for the second subquery, no need to use W.
+ self.assertNotIn('w0', str(qs4.query).lower())
+ # So, 'U0."id"' is referenced twice.
+ self.assertTrue(str(qs4.query).lower().count('u0'), 2)
+
def test_ticket1050(self):
self.assertQuerysetEqual(
Item.objects.filter(tags__isnull=True),
@@ -810,7 +822,7 @@ class Queries1Tests(BaseQuerysetTest):
# Make sure bump_prefix() (an internal Query method) doesn't (re-)break. It's
# sufficient that this query runs without error.
qs = Tag.objects.values_list('id', flat=True).order_by('id')
- qs.query.bump_prefix()
+ qs.query.bump_prefix(qs.query)
first = qs[0]
self.assertEqual(list(qs), list(range(first, first+5)))
@@ -2940,6 +2952,16 @@ class Ticket20788Tests(TestCase):
self.assertQuerysetEqual(
sentences_not_in_pub, [book2], lambda x: x)
+class Ticket12807Tests(TestCase):
+ def test_ticket_12807(self):
+ p1 = Paragraph.objects.create()
+ p2 = Paragraph.objects.create()
+ # The ORed condition below should have no effect on the query - the
+ # ~Q(pk__in=[]) will always be True.
+ qs = Paragraph.objects.filter((Q(pk=p2.pk) | ~Q(pk__in=[])) & Q(pk=p1.pk))
+ self.assertQuerysetEqual(qs, [p1], lambda x: x)
+
+
class RelatedLookupTypeTests(TestCase):
def test_wrong_type_lookup(self):
oa = ObjectA.objects.create(name="oa")
diff --git a/tests/raw_query/models.py b/tests/raw_query/models.py
index e7e221dc6e..33f754958e 100644
--- a/tests/raw_query/models.py
+++ b/tests/raw_query/models.py
@@ -18,7 +18,7 @@ class Author(models.Model):
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(Author)
- paperback = models.BooleanField()
+ paperback = models.BooleanField(default=False)
opening_line = models.TextField()
class Coffee(models.Model):
diff --git a/tests/reverse_single_related/models.py b/tests/reverse_single_related/models.py
index 30ba345120..5d53e04772 100644
--- a/tests/reverse_single_related/models.py
+++ b/tests/reverse_single_related/models.py
@@ -6,7 +6,7 @@ class SourceManager(models.Manager):
return super(SourceManager, self).get_queryset().filter(is_public=True)
class Source(models.Model):
- is_public = models.BooleanField()
+ is_public = models.BooleanField(default=False)
objects = SourceManager()
class Item(models.Model):
diff --git a/tests/runtests.py b/tests/runtests.py
index 53318a7461..adfc77b13b 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -60,6 +60,7 @@ ALWAYS_INSTALLED_APPS = [
'staticfiles_tests',
'staticfiles_tests.apps.test',
'staticfiles_tests.apps.no_label',
+ 'servers.another_app',
]
diff --git a/tests/serializers_regress/models.py b/tests/serializers_regress/models.py
index 21a3448a8e..ab3d3063a4 100644
--- a/tests/serializers_regress/models.py
+++ b/tests/serializers_regress/models.py
@@ -16,7 +16,7 @@ class BinaryData(models.Model):
data = models.BinaryField(null=True)
class BooleanData(models.Model):
- data = models.BooleanField()
+ data = models.BooleanField(default=False)
class CharData(models.Model):
data = models.CharField(max_length=30, null=True)
@@ -166,7 +166,7 @@ class Intermediate(models.Model):
# or all database backends.
class BooleanPKData(models.Model):
- data = models.BooleanField(primary_key=True)
+ data = models.BooleanField(primary_key=True, default=False)
class CharPKData(models.Model):
data = models.CharField(max_length=30, primary_key=True)
diff --git a/tests/servers/another_app/__init__.py b/tests/servers/another_app/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/servers/another_app/__init__.py
diff --git a/tests/servers/another_app/models.py b/tests/servers/another_app/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/servers/another_app/models.py
diff --git a/tests/servers/another_app/static/another_app/another_app_static_file.txt b/tests/servers/another_app/static/another_app/another_app_static_file.txt
new file mode 100644
index 0000000000..a2784fa8e2
--- /dev/null
+++ b/tests/servers/another_app/static/another_app/another_app_static_file.txt
@@ -0,0 +1 @@
+static file from another_app
diff --git a/tests/servers/tests.py b/tests/servers/tests.py
index 1f02a88d5a..0340873013 100644
--- a/tests/servers/tests.py
+++ b/tests/servers/tests.py
@@ -145,6 +145,14 @@ class LiveServerViews(LiveServerBase):
f = self.urlopen('/static/example_static_file.txt')
self.assertEqual(f.read().rstrip(b'\r\n'), b'example static file')
+ def test_collectstatic_emulation(self):
+ """
+ Test LiveServerTestCase use of staticfiles' serve() allows it to
+ discover app's static assets without having to collectstatic first.
+ """
+ f = self.urlopen('/static/another_app/another_app_static_file.txt')
+ self.assertEqual(f.read().rstrip(b'\r\n'), b'static file from another_app')
+
def test_media_files(self):
"""
Ensure that the LiveServerTestCase serves media files.
diff --git a/tests/template_tests/test_context.py b/tests/template_tests/test_context.py
index ca167a73f3..7bcfb7f9f2 100644
--- a/tests/template_tests/test_context.py
+++ b/tests/template_tests/test_context.py
@@ -2,7 +2,7 @@
from unittest import TestCase
-from django.template import Context
+from django.template import Context, Variable, VariableDoesNotExist
class ContextTests(TestCase):
@@ -25,3 +25,12 @@ class ContextTests(TestCase):
with c.push(a=3):
self.assertEqual(c['a'], 3)
self.assertEqual(c['a'], 1)
+
+ def test_resolve_on_context_method(self):
+ # Regression test for #17778
+ empty_context = Context()
+ self.assertRaises(VariableDoesNotExist,
+ Variable('no_such_variable').resolve, empty_context)
+ self.assertRaises(VariableDoesNotExist,
+ Variable('new').resolve, empty_context)
+ self.assertEqual(Variable('new').resolve(Context({'new': 'foo'})), 'foo')
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index aa0283be79..034280f08d 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -1575,6 +1575,13 @@ class TemplateTests(TransRealMixin, TestCase):
# Test whitespace in filter argument
'widthratio15': ('{% load custom %}{% widthratio a|noop:"x y" b 0 %}', {'a':50,'b':100}, '0'),
+ # Widthratio with variable assignment
+ 'widthratio16': ('{% widthratio a b 100 as variable %}-{{ variable }}-', {'a':50,'b':100}, '-50-'),
+ 'widthratio17': ('{% widthratio a b 100 as variable %}-{{ variable }}-', {'a':100,'b':100}, '-100-'),
+
+ 'widthratio18': ('{% widthratio a b 100 as %}', { }, template.TemplateSyntaxError),
+ 'widthratio19': ('{% widthratio a b 100 not_as variable %}', { }, template.TemplateSyntaxError),
+
### WITH TAG ########################################################
'with01': ('{% with key=dict.key %}{{ key }}{% endwith %}', {'dict': {'key': 50}}, '50'),
'legacywith01': ('{% with dict.key as key %}{{ key }}{% endwith %}', {'dict': {'key': 50}}, '50'),
diff --git a/tests/test_client_regress/tests.py b/tests/test_client_regress/tests.py
index 67e66fa52d..857d6d83c0 100644
--- a/tests/test_client_regress/tests.py
+++ b/tests/test_client_regress/tests.py
@@ -925,6 +925,14 @@ class ContextTests(TestCase):
finally:
django.template.context._standard_context_processors = None
+ def test_nested_requests(self):
+ """
+ response.context is not lost when view call another view.
+ """
+ response = self.client.get("/test_client_regress/nested_view/")
+ self.assertEqual(response.context.__class__, Context)
+ self.assertEqual(response.context['nested'], 'yes')
+
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class SessionTests(TestCase):
diff --git a/tests/test_client_regress/urls.py b/tests/test_client_regress/urls.py
index 6a0b330e02..1bde10315d 100644
--- a/tests/test_client_regress/urls.py
+++ b/tests/test_client_regress/urls.py
@@ -11,6 +11,7 @@ urlpatterns = patterns('',
(r'^request_data/$', views.request_data),
(r'^request_data_extended/$', views.request_data, {'template':'extended.html', 'data':'bacon'}),
url(r'^arg_view/(?P<name>.+)/$', views.view_with_argument, name='arg_view'),
+ url(r'^nested_view/$', views.nested_view, name='nested_view'),
(r'^login_protected_redirect_view/$', views.login_protected_redirect_view),
(r'^redirects/$', RedirectView.as_view(url='/test_client_regress/redirects/further/')),
(r'^redirects/further/$', RedirectView.as_view(url='/test_client_regress/redirects/further/more/')),
diff --git a/tests/test_client_regress/views.py b/tests/test_client_regress/views.py
index 71e5b526e5..d7c54cf2f7 100644
--- a/tests/test_client_regress/views.py
+++ b/tests/test_client_regress/views.py
@@ -5,8 +5,10 @@ from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.serializers.json import DjangoJSONEncoder
-from django.test.client import CONTENT_TYPE_RE
from django.template import RequestContext
+from django.test import Client
+from django.test.client import CONTENT_TYPE_RE
+from django.test.utils import setup_test_environment
class CustomTestException(Exception):
@@ -52,6 +54,15 @@ def view_with_argument(request, name):
else:
return HttpResponse('Howdy, %s' % name)
+def nested_view(request):
+ """
+ A view that uses test client to call another view.
+ """
+ setup_test_environment()
+ c = Client()
+ c.get("/test_client_regress/no_template_view")
+ return render_to_response('base.html', {'nested':'yes'})
+
def login_protected_redirect_view(request):
"A view that redirects all requests to the GET view"
return HttpResponseRedirect('/test_client_regress/get_view/')
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index eb850cc3be..1b3c78b2e2 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -152,9 +152,8 @@ class CaptureQueriesContextManagerTests(TestCase):
self.assertEqual(2, len(captured_queries))
def test_failure(self):
- with self.assertRaises(TypeError):
- with CaptureQueriesContext(connection):
- raise TypeError
+ with self.assertRaises(TypeError), CaptureQueriesContext(connection):
+ raise TypeError
def test_with_client(self):
with CaptureQueriesContext(connection) as captured_queries:
@@ -190,14 +189,12 @@ class AssertNumQueriesContextManagerTests(TestCase):
Person.objects.count()
def test_failure(self):
- with self.assertRaises(AssertionError) as exc_info:
- with self.assertNumQueries(2):
- Person.objects.count()
+ with self.assertRaises(AssertionError) as exc_info, self.assertNumQueries(2):
+ Person.objects.count()
self.assertIn("1 queries executed, 2 expected", str(exc_info.exception))
- with self.assertRaises(TypeError):
- with self.assertNumQueries(4000):
- raise TypeError
+ with self.assertRaises(TypeError), self.assertNumQueries(4000):
+ raise TypeError
def test_with_client(self):
person = Person.objects.create(name="test")
@@ -232,13 +229,13 @@ class AssertTemplateUsedContextManagerTests(TestCase):
render_to_string('template_used/base.html')
def test_nested_usage(self):
- with self.assertTemplateUsed('template_used/base.html'):
- with self.assertTemplateUsed('template_used/include.html'):
- render_to_string('template_used/include.html')
+ with self.assertTemplateUsed('template_used/base.html'), \
+ self.assertTemplateUsed('template_used/include.html'):
+ render_to_string('template_used/include.html')
- with self.assertTemplateUsed('template_used/extends.html'):
- with self.assertTemplateUsed('template_used/base.html'):
- render_to_string('template_used/extends.html')
+ with self.assertTemplateUsed('template_used/extends.html'), \
+ self.assertTemplateUsed('template_used/base.html'):
+ render_to_string('template_used/extends.html')
with self.assertTemplateUsed('template_used/base.html'):
with self.assertTemplateUsed('template_used/alternative.html'):
@@ -258,38 +255,34 @@ class AssertTemplateUsedContextManagerTests(TestCase):
pass
def test_error_message(self):
- with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html'):
- with self.assertTemplateUsed('template_used/base.html'):
- pass
+ with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html'), \
+ self.assertTemplateUsed('template_used/base.html'):
+ pass
- with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html'):
- with self.assertTemplateUsed(template_name='template_used/base.html'):
- pass
+ with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html'), \
+ self.assertTemplateUsed(template_name='template_used/base.html'):
+ pass
- with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html.*template_used/alternative\.html$'):
- with self.assertTemplateUsed('template_used/base.html'):
- render_to_string('template_used/alternative.html')
+ with six.assertRaisesRegex(self, AssertionError, r'^template_used/base\.html.*template_used/alternative\.html$'), \
+ self.assertTemplateUsed('template_used/base.html'):
+ render_to_string('template_used/alternative.html')
def test_failure(self):
- with self.assertRaises(TypeError):
- with self.assertTemplateUsed():
- pass
+ with self.assertRaises(TypeError), self.assertTemplateUsed():
+ pass
- with self.assertRaises(AssertionError):
- with self.assertTemplateUsed(''):
- pass
+ with self.assertRaises(AssertionError), self.assertTemplateUsed(''):
+ pass
- with self.assertRaises(AssertionError):
- with self.assertTemplateUsed(''):
- render_to_string('template_used/base.html')
+ with self.assertRaises(AssertionError), self.assertTemplateUsed(''):
+ render_to_string('template_used/base.html')
- with self.assertRaises(AssertionError):
- with self.assertTemplateUsed(template_name=''):
- pass
+ with self.assertRaises(AssertionError), self.assertTemplateUsed(template_name=''):
+ pass
- with self.assertRaises(AssertionError):
- with self.assertTemplateUsed('template_used/base.html'):
- render_to_string('template_used/alternative.html')
+ with self.assertRaises(AssertionError), \
+ self.assertTemplateUsed('template_used/base.html'):
+ render_to_string('template_used/alternative.html')
class HTMLEqualTests(TestCase):
diff --git a/tests/transactions/tests.py b/tests/transactions/tests.py
index 9cf8b4d742..d7cbbd0f3c 100644
--- a/tests/transactions/tests.py
+++ b/tests/transactions/tests.py
@@ -65,10 +65,9 @@ class AtomicTests(TransactionTestCase):
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
def test_rollback(self):
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_nested_commit_commit(self):
@@ -82,30 +81,27 @@ class AtomicTests(TransactionTestCase):
def test_nested_commit_rollback(self):
with transaction.atomic():
Reporter.objects.create(first_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
def test_nested_rollback_commit(self):
- with six.assertRaisesRegex(self, Exception, "Oops"):
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(last_name="Tintin")
with transaction.atomic():
- Reporter.objects.create(last_name="Tintin")
- with transaction.atomic():
- Reporter.objects.create(last_name="Haddock")
- raise Exception("Oops, that's his first name")
+ Reporter.objects.create(last_name="Haddock")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_nested_rollback_rollback(self):
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(last_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
- raise Exception("Oops, that's his first name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(last_name="Tintin")
+ with six.assertRaisesRegex(self, Exception, "Oops"):
+ with transaction.atomic():
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_merged_commit_commit(self):
@@ -119,31 +115,29 @@ class AtomicTests(TransactionTestCase):
def test_merged_commit_rollback(self):
with transaction.atomic():
Reporter.objects.create(first_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), \
+ transaction.atomic(savepoint=False):
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
# Writes in the outer block are rolled back too.
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_merged_rollback_commit(self):
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(last_name="Tintin")
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(last_name="Haddock")
- raise Exception("Oops, that's his first name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(last_name="Tintin")
+ with transaction.atomic(savepoint=False):
+ Reporter.objects.create(last_name="Haddock")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_merged_rollback_rollback(self):
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic():
- Reporter.objects.create(last_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
- raise Exception("Oops, that's his first name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), transaction.atomic():
+ Reporter.objects.create(last_name="Tintin")
+ with six.assertRaisesRegex(self, Exception, "Oops"):
+ with transaction.atomic(savepoint=False):
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_reuse_commit_commit(self):
@@ -159,32 +153,29 @@ class AtomicTests(TransactionTestCase):
atomic = transaction.atomic()
with atomic:
Reporter.objects.create(first_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with atomic:
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), atomic:
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
def test_reuse_rollback_commit(self):
atomic = transaction.atomic()
- with six.assertRaisesRegex(self, Exception, "Oops"):
+ with six.assertRaisesRegex(self, Exception, "Oops"), atomic:
+ Reporter.objects.create(last_name="Tintin")
with atomic:
- Reporter.objects.create(last_name="Tintin")
- with atomic:
- Reporter.objects.create(last_name="Haddock")
- raise Exception("Oops, that's his first name")
+ Reporter.objects.create(last_name="Haddock")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_reuse_rollback_rollback(self):
atomic = transaction.atomic()
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with atomic:
- Reporter.objects.create(last_name="Tintin")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with atomic:
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
- raise Exception("Oops, that's his first name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), atomic:
+ Reporter.objects.create(last_name="Tintin")
+ with six.assertRaisesRegex(self, Exception, "Oops"):
+ with atomic:
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
+ raise Exception("Oops, that's his first name")
self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_force_rollback(self):
@@ -200,10 +191,9 @@ class AtomicTests(TransactionTestCase):
Reporter.objects.create(first_name="Tintin")
sid = transaction.savepoint()
# trigger a database error inside an inner atomic without savepoint
- with self.assertRaises(DatabaseError):
- with transaction.atomic(savepoint=False):
- connection.cursor().execute(
- "SELECT no_such_col FROM transactions_reporter")
+ with self.assertRaises(DatabaseError), transaction.atomic(savepoint=False):
+ connection.cursor().execute(
+ "SELECT no_such_col FROM transactions_reporter")
transaction.savepoint_rollback(sid)
# atomic block should rollback, but prevent it, as we just did it.
self.assertTrue(transaction.get_rollback())
@@ -263,10 +253,10 @@ class AtomicMergeTests(TransactionTestCase):
Reporter.objects.create(first_name="Tintin")
with transaction.atomic(savepoint=False):
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(first_name="Tournesol")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), \
+ transaction.atomic(savepoint=False):
+ Reporter.objects.create(first_name="Tournesol")
+ raise Exception("Oops, that's his last name")
# It wasn't possible to roll back
self.assertEqual(Reporter.objects.count(), 3)
# It wasn't possible to roll back
@@ -279,10 +269,10 @@ class AtomicMergeTests(TransactionTestCase):
Reporter.objects.create(first_name="Tintin")
with transaction.atomic():
Reporter.objects.create(first_name="Archibald", last_name="Haddock")
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(first_name="Tournesol")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), \
+ transaction.atomic(savepoint=False):
+ Reporter.objects.create(first_name="Tournesol")
+ raise Exception("Oops, that's his last name")
# It wasn't possible to roll back
self.assertEqual(Reporter.objects.count(), 3)
# The first block with a savepoint must roll back
@@ -293,10 +283,10 @@ class AtomicMergeTests(TransactionTestCase):
with transaction.atomic():
Reporter.objects.create(first_name="Tintin")
# Inner block without a savepoint fails
- with six.assertRaisesRegex(self, Exception, "Oops"):
- with transaction.atomic(savepoint=False):
- Reporter.objects.create(first_name="Haddock")
- raise Exception("Oops, that's his last name")
+ with six.assertRaisesRegex(self, Exception, "Oops"), \
+ transaction.atomic(savepoint=False):
+ Reporter.objects.create(first_name="Haddock")
+ raise Exception("Oops, that's his last name")
# It wasn't possible to roll back
self.assertEqual(Reporter.objects.count(), 2)
# Inner block with a savepoint succeeds
@@ -316,9 +306,9 @@ class AtomicErrorsTests(TransactionTestCase):
def test_atomic_prevents_setting_autocommit(self):
autocommit = transaction.get_autocommit()
- with transaction.atomic():
- with self.assertRaises(transaction.TransactionManagementError):
- transaction.set_autocommit(not autocommit)
+ with transaction.atomic(), \
+ self.assertRaises(transaction.TransactionManagementError):
+ transaction.set_autocommit(not autocommit)
# Make sure autocommit wasn't changed.
self.assertEqual(connection.autocommit, autocommit)
@@ -552,9 +542,8 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
The autocommit context manager works exactly the same as the default
behavior.
"""
- with self.assertRaises(Exception):
- with transaction.autocommit():
- self.create_reporter_and_fail()
+ with self.assertRaises(Exception), transaction.autocommit():
+ self.create_reporter_and_fail()
self.assertEqual(Reporter.objects.count(), 1)
@@ -563,9 +552,8 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
"""
The autocommit context manager also works with a using argument.
"""
- with self.assertRaises(Exception):
- with transaction.autocommit(using="default"):
- self.create_reporter_and_fail()
+ with self.assertRaises(Exception), transaction.autocommit(using="default"):
+ self.create_reporter_and_fail()
self.assertEqual(Reporter.objects.count(), 1)
@@ -575,9 +563,8 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
With the commit_on_success context manager, the transaction is only
committed if the block doesn't throw an exception.
"""
- with self.assertRaises(Exception):
- with transaction.commit_on_success():
- self.create_reporter_and_fail()
+ with self.assertRaises(Exception), transaction.commit_on_success():
+ self.create_reporter_and_fail()
self.assertEqual(Reporter.objects.count(), 0)
@@ -586,9 +573,8 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
"""
The commit_on_success context manager also works with a using argument.
"""
- with self.assertRaises(Exception):
- with transaction.commit_on_success(using="default"):
- self.create_reporter_and_fail()
+ with self.assertRaises(Exception), transaction.commit_on_success(using="default"):
+ self.create_reporter_and_fail()
self.assertEqual(Reporter.objects.count(), 0)
@@ -633,18 +619,18 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
"""
If you forget, you'll get bad errors.
"""
- with self.assertRaises(transaction.TransactionManagementError):
- with transaction.commit_manually():
- Reporter.objects.create(first_name="Scott", last_name="Browning")
+ with self.assertRaises(transaction.TransactionManagementError), \
+ transaction.commit_manually():
+ Reporter.objects.create(first_name="Scott", last_name="Browning")
@skipUnlessDBFeature('supports_transactions')
def test_manually_managed_with_using(self):
"""
The commit_manually function also works with a using argument.
"""
- with self.assertRaises(transaction.TransactionManagementError):
- with transaction.commit_manually(using="default"):
- Reporter.objects.create(first_name="Walter", last_name="Cronkite")
+ with self.assertRaises(transaction.TransactionManagementError), \
+ transaction.commit_manually(using="default"):
+ Reporter.objects.create(first_name="Walter", last_name="Cronkite")
@skipUnlessDBFeature('requires_rollback_on_dirty_transaction')
def test_bad_sql(self):
@@ -654,8 +640,7 @@ class TransactionContextManagerTests(IgnoreDeprecationWarningsMixin, Transaction
be rolled back. The bug is only visible using the psycopg2 backend,
though the fix is generally a good idea.
"""
- with self.assertRaises(IntegrityError):
- with transaction.commit_on_success():
- cursor = connection.cursor()
- cursor.execute("INSERT INTO transactions_reporter (first_name, last_name) VALUES ('Douglas', 'Adams');")
+ with self.assertRaises(IntegrityError), transaction.commit_on_success():
+ cursor = connection.cursor()
+ cursor.execute("INSERT INTO transactions_reporter (first_name, last_name) VALUES ('Douglas', 'Adams');")
transaction.rollback()
diff --git a/tests/utils_tests/test_simplelazyobject.py b/tests/utils_tests/test_simplelazyobject.py
index 7b681d9290..f16b5e4da1 100644
--- a/tests/utils_tests/test_simplelazyobject.py
+++ b/tests/utils_tests/test_simplelazyobject.py
@@ -136,6 +136,9 @@ class TestUtilsSimpleLazyObject(TestCase):
self.assertEqual(lazydict['one'], 1)
lazydict['one'] = -1
self.assertEqual(lazydict['one'], -1)
+ self.assertTrue('one' in lazydict)
+ self.assertFalse('two' in lazydict)
+ self.assertEqual(len(lazydict), 1)
del lazydict['one']
with self.assertRaises(KeyError):
lazydict['one']
@@ -183,3 +186,13 @@ class TestUtilsSimpleLazyObject(TestCase):
# This would fail with "TypeError: expected string or Unicode object, NoneType found".
pickled = cPickle.dumps(x)
+
+ def test_list_set(self):
+ lazy_list = SimpleLazyObject(lambda: [1, 2, 3, 4, 5])
+ lazy_set = SimpleLazyObject(lambda: set([1, 2, 3, 4]))
+ self.assertTrue(1 in lazy_list)
+ self.assertTrue(1 in lazy_set)
+ self.assertFalse(6 in lazy_list)
+ self.assertFalse(6 in lazy_set)
+ self.assertEqual(len(lazy_list), 5)
+ self.assertEqual(len(lazy_set), 4)
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index 0159886918..e941f4ae0e 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import inspect
import os
+import re
import shutil
import sys
from tempfile import NamedTemporaryFile, mkdtemp, mkstemp
@@ -69,6 +70,21 @@ class DebugViewTests(TestCase):
self.assertRaises(BrokenException, self.client.get,
reverse('view_exception', args=(n,)))
+ def test_non_l10ned_numeric_ids(self):
+ """
+ Numeric IDs and fancy traceback context blocks line numbers shouldn't be localized.
+ """
+ with self.settings(DEBUG=True, USE_L10N=True):
+ response = self.client.get('/views/raises500/')
+ # We look for a HTML fragment of the form
+ # '<div class="context" id="c38123208">', not '<div class="context" id="c38,123,208"'
+ self.assertContains(response, '<div class="context" id="', status_code=500)
+ match = re.search(b'<div class="context" id="(?P<id>[^"]+)">', response.content)
+ self.assertFalse(match is None)
+ id_repr = match.group('id')
+ self.assertFalse(re.search(b'[^c\d]', id_repr),
+ "Numeric IDs in debug response HTML page shouldn't be localized (value: %s)." % id_repr)
+
def test_template_exceptions(self):
for n in range(len(except_args)):
try:
diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py
index cfee4f5093..50677947b6 100644
--- a/tests/view_tests/tests/test_i18n.py
+++ b/tests/view_tests/tests/test_i18n.py
@@ -85,20 +85,18 @@ class JsI18NTests(TestCase):
languages and you've set settings.LANGUAGE_CODE to some other language
than English.
"""
- with self.settings(LANGUAGE_CODE='es'):
- with override('en-us'):
- response = self.client.get('/views/jsi18n/')
- self.assertNotContains(response, 'esto tiene que ser traducido')
+ with self.settings(LANGUAGE_CODE='es'), override('en-us'):
+ response = self.client.get('/views/jsi18n/')
+ self.assertNotContains(response, 'esto tiene que ser traducido')
def test_jsi18n_fallback_language(self):
"""
Let's make sure that the fallback language is still working properly
in cases where the selected language cannot be found.
"""
- with self.settings(LANGUAGE_CODE='fr'):
- with override('fi'):
- response = self.client.get('/views/jsi18n/')
- self.assertContains(response, 'il faut le traduire')
+ with self.settings(LANGUAGE_CODE='fr'), override('fi'):
+ response = self.client.get('/views/jsi18n/')
+ self.assertContains(response, 'il faut le traduire')
def testI18NLanguageNonEnglishDefault(self):
"""
@@ -107,10 +105,9 @@ class JsI18NTests(TestCase):
is English and there is not 'en' translation available. See #13388,
#3594 and #13726 for more details.
"""
- with self.settings(LANGUAGE_CODE='fr'):
- with override('en-us'):
- response = self.client.get('/views/jsi18n/')
- self.assertNotContains(response, 'Choisir une heure')
+ with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
+ response = self.client.get('/views/jsi18n/')
+ self.assertNotContains(response, 'Choisir une heure')
def test_nonenglish_default_english_userpref(self):
"""
@@ -119,20 +116,19 @@ class JsI18NTests(TestCase):
with the proper English translations. See #13726 for more details.
"""
extended_apps = list(settings.INSTALLED_APPS) + ['view_tests.app0']
- with self.settings(LANGUAGE_CODE='fr', INSTALLED_APPS=extended_apps):
- with override('en-us'):
- response = self.client.get('/views/jsi18n_english_translation/')
- self.assertContains(response, javascript_quote('this app0 string is to be translated'))
+ with self.settings(LANGUAGE_CODE='fr', INSTALLED_APPS=extended_apps), \
+ override('en-us'):
+ response = self.client.get('/views/jsi18n_english_translation/')
+ self.assertContains(response, javascript_quote('this app0 string is to be translated'))
def testI18NLanguageNonEnglishFallback(self):
"""
Makes sure that the fallback language is still working properly
in cases where the selected language cannot be found.
"""
- with self.settings(LANGUAGE_CODE='fr'):
- with override('none'):
- response = self.client.get('/views/jsi18n/')
- self.assertContains(response, 'Choisir une heure')
+ with self.settings(LANGUAGE_CODE='fr'), override('none'):
+ response = self.client.get('/views/jsi18n/')
+ self.assertContains(response, 'Choisir une heure')
class JsI18NTestsMultiPackage(TestCase):
@@ -149,10 +145,11 @@ class JsI18NTestsMultiPackage(TestCase):
#3594 and #13514 for more details.
"""
extended_apps = list(settings.INSTALLED_APPS) + ['view_tests.app1', 'view_tests.app2']
- with self.settings(LANGUAGE_CODE='en-us', INSTALLED_APPS=extended_apps):
- with override('fr'):
- response = self.client.get('/views/jsi18n_multi_packages1/')
- self.assertContains(response, javascript_quote('il faut traduire cette chaîne de caractères de app1'))
+ with self.settings(LANGUAGE_CODE='en-us', INSTALLED_APPS=extended_apps), \
+ override('fr'):
+ response = self.client.get('/views/jsi18n_multi_packages1/')
+ self.assertContains(response,
+ javascript_quote('il faut traduire cette chaîne de caractères de app1'))
def testI18NDifferentNonEnLangs(self):
"""
@@ -160,20 +157,21 @@ class JsI18NTestsMultiPackage(TestCase):
English.
"""
extended_apps = list(settings.INSTALLED_APPS) + ['view_tests.app3', 'view_tests.app4']
- with self.settings(LANGUAGE_CODE='fr', INSTALLED_APPS=extended_apps):
- with override('es-ar'):
- response = self.client.get('/views/jsi18n_multi_packages2/')
- self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido'))
+ with self.settings(LANGUAGE_CODE='fr', INSTALLED_APPS=extended_apps), \
+ override('es-ar'):
+ response = self.client.get('/views/jsi18n_multi_packages2/')
+ self.assertContains(response,
+ javascript_quote('este texto de app3 debe ser traducido'))
def testI18NWithLocalePaths(self):
extended_locale_paths = settings.LOCALE_PATHS + (
path.join(path.dirname(
path.dirname(path.abspath(upath(__file__)))), 'app3', 'locale'),)
- with self.settings(LANGUAGE_CODE='es-ar', LOCALE_PATHS=extended_locale_paths):
- with override('es-ar'):
- response = self.client.get('/views/jsi18n/')
- self.assertContains(response,
- javascript_quote('este texto de app3 debe ser traducido'))
+ with self.settings(LANGUAGE_CODE='es-ar', LOCALE_PATHS=extended_locale_paths), \
+ override('es-ar'):
+ response = self.client.get('/views/jsi18n/')
+ self.assertContains(response,
+ javascript_quote('este texto de app3 debe ser traducido'))
skip_selenium = not os.environ.get('DJANGO_SELENIUM_TESTS', False)
diff --git a/tests/view_tests/tests/test_static.py b/tests/view_tests/tests/test_static.py
index d2f3f47fa7..8f67890c11 100644
--- a/tests/view_tests/tests/test_static.py
+++ b/tests/view_tests/tests/test_static.py
@@ -6,7 +6,7 @@ import unittest
from django.conf.urls.static import static
from django.http import HttpResponseNotModified
-from django.test import TestCase
+from django.test import SimpleTestCase
from django.test.utils import override_settings
from django.utils.http import http_date
from django.views.static import was_modified_since
@@ -16,7 +16,7 @@ from ..urls import media_dir
@override_settings(DEBUG=True)
-class StaticTests(TestCase):
+class StaticTests(SimpleTestCase):
"""Tests django views in django/views/static.py"""
prefix = 'site_media'
@@ -94,6 +94,10 @@ class StaticTests(TestCase):
self.assertEqual(len(response_content),
int(response['Content-Length']))
+ def test_404(self):
+ response = self.client.get('/views/%s/non_existing_resource' % self.prefix)
+ self.assertEqual(404, response.status_code)
+
class StaticHelperTest(StaticTests):
"""
diff --git a/tests/view_tests/urls.py b/tests/view_tests/urls.py
index f2c910368d..4db3e262ed 100644
--- a/tests/view_tests/urls.py
+++ b/tests/view_tests/urls.py
@@ -49,6 +49,7 @@ urlpatterns = patterns('',
(r'raises400/$', views.raises400),
(r'raises403/$', views.raises403),
(r'raises404/$', views.raises404),
+ (r'raises500/$', views.raises500),
# i18n views
(r'^i18n/', include('django.conf.urls.i18n')),
diff --git a/tests/view_tests/views.py b/tests/view_tests/views.py
index 0bac7d9321..04924bc9f7 100644
--- a/tests/view_tests/views.py
+++ b/tests/view_tests/views.py
@@ -31,6 +31,14 @@ def raises(request):
except Exception:
return technical_500_response(request, *sys.exc_info())
+def raises500(request):
+ # We need to inspect the HTML generated by the fancy 500 debug view but
+ # the test client ignores it, so we send it explicitly.
+ try:
+ raise Exception
+ except Exception:
+ return technical_500_response(request, *sys.exc_info())
+
def raises400(request):
raise SuspiciousOperation