mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts: django/core/management/commands/flush.py django/core/management/commands/syncdb.py django/db/models/loading.py docs/internals/deprecation.txt docs/ref/django-admin.txt docs/releases/1.7.txt
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
from django.core.paginator import Paginator
|
||||
|
||||
@@ -107,3 +105,10 @@ class DynamicListFilterChildAdmin(admin.ModelAdmin):
|
||||
my_list_filter.remove('parent')
|
||||
return my_list_filter
|
||||
|
||||
class DynamicSearchFieldsChildAdmin(admin.ModelAdmin):
|
||||
search_fields = ('name',)
|
||||
|
||||
def get_search_fields(self, request):
|
||||
search_fields = super(DynamicSearchFieldsChildAdmin, self).get_search_fields(request)
|
||||
search_fields += ('age',)
|
||||
return search_fields
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -18,7 +18,8 @@ from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin,
|
||||
GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin,
|
||||
DynamicListDisplayLinksChildAdmin, CustomPaginationAdmin,
|
||||
FilteredChildAdmin, CustomPaginator, site as custom_site,
|
||||
SwallowAdmin, DynamicListFilterChildAdmin, InvitationAdmin)
|
||||
SwallowAdmin, DynamicListFilterChildAdmin, InvitationAdmin,
|
||||
DynamicSearchFieldsChildAdmin)
|
||||
from .models import (Event, Child, Parent, Genre, Band, Musician, Group,
|
||||
Quartet, Membership, ChordsMusician, ChordsBand, Invitation, Swallow,
|
||||
UnorderedObject, OrderedObject, CustomIdUser)
|
||||
@@ -91,7 +92,7 @@ class ChangeListTests(TestCase):
|
||||
context = Context({'cl': cl})
|
||||
table_output = template.render(context)
|
||||
link = reverse('admin:admin_changelist_child_change', args=(new_child.id,))
|
||||
row_html = '<tbody><tr class="row1"><th><a href="%s">name</a></th><td class="nowrap">(None)</td></tr></tbody>' % link
|
||||
row_html = '<tbody><tr class="row1"><th class="field-name"><a href="%s">name</a></th><td class="field-parent nowrap">(None)</td></tr></tbody>' % link
|
||||
self.assertFalse(table_output.find(row_html) == -1,
|
||||
'Failed to find expected row element: %s' % table_output)
|
||||
|
||||
@@ -114,7 +115,7 @@ class ChangeListTests(TestCase):
|
||||
context = Context({'cl': cl})
|
||||
table_output = template.render(context)
|
||||
link = reverse('admin:admin_changelist_child_change', args=(new_child.id,))
|
||||
row_html = '<tbody><tr class="row1"><th><a href="%s">name</a></th><td class="nowrap">Parent object</td></tr></tbody>' % link
|
||||
row_html = '<tbody><tr class="row1"><th class="field-name"><a href="%s">name</a></th><td class="field-parent nowrap">Parent object</td></tr></tbody>' % link
|
||||
self.assertFalse(table_output.find(row_html) == -1,
|
||||
'Failed to find expected row element: %s' % table_output)
|
||||
|
||||
@@ -150,7 +151,7 @@ class ChangeListTests(TestCase):
|
||||
|
||||
# make sure that list editable fields are rendered in divs correctly
|
||||
editable_name_field = '<input name="form-0-name" value="name" class="vTextField" maxlength="30" type="text" id="id_form-0-name" />'
|
||||
self.assertInHTML('<td>%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field')
|
||||
self.assertInHTML('<td class="field-name">%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field')
|
||||
|
||||
def test_result_list_editable(self):
|
||||
"""
|
||||
@@ -588,6 +589,13 @@ class ChangeListTests(TestCase):
|
||||
response = m.changelist_view(request)
|
||||
self.assertEqual(response.context_data['cl'].list_filter, ('parent', 'name', 'age'))
|
||||
|
||||
def test_dynamic_search_fields(self):
|
||||
child = self._create_superuser('child')
|
||||
m = DynamicSearchFieldsChildAdmin(Child, admin.site)
|
||||
request = self._mocked_authenticated_request('/child/', child)
|
||||
response = m.changelist_view(request)
|
||||
self.assertEqual(response.context_data['cl'].search_fields, ('name', 'age'))
|
||||
|
||||
def test_pagination_page_range(self):
|
||||
"""
|
||||
Regression tests for ticket #15653: ensure the number of pages
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
import warnings
|
||||
|
||||
from django.contrib.admin.util import quote
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# coding: utf-8
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns
|
||||
|
||||
from . import views
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
from django import forms
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||
from django.contrib.admin.helpers import InlineAdminForm
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns, include
|
||||
|
||||
from . import admin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.contrib import admin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from ..models.foo import Foo
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.db import models
|
||||
|
||||
from ..admin import foo
|
||||
|
||||
9
tests/admin_scripts/management/commands/color_command.py
Normal file
9
tests/admin_scripts/management/commands/color_command.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Test color output"
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
return self.style.SQL_KEYWORD('BEGIN')
|
||||
@@ -1,3 +1 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from ..complex_app.models.bar import Bar
|
||||
|
||||
@@ -18,7 +18,7 @@ import unittest
|
||||
import django
|
||||
from django import conf, get_version
|
||||
from django.conf import settings
|
||||
from django.core.management import BaseCommand, CommandError
|
||||
from django.core.management import BaseCommand, CommandError, call_command
|
||||
from django.db import connection
|
||||
from django.test.runner import DiscoverRunner
|
||||
from django.utils.encoding import force_text
|
||||
@@ -45,6 +45,7 @@ class AdminScriptTestCase(unittest.TestCase):
|
||||
settings_file_path = os.path.join(test_dir, filename)
|
||||
|
||||
with open(settings_file_path, 'w') as settings_file:
|
||||
settings_file.write('# -*- coding: utf-8 -*\n')
|
||||
settings_file.write('# Settings file automatically generated by admin_scripts test case\n')
|
||||
exports = [
|
||||
'DATABASES',
|
||||
@@ -921,14 +922,21 @@ class ManageAlternateSettings(AdminScriptTestCase):
|
||||
"alternate: manage.py can execute user commands if settings are provided as argument"
|
||||
args = ['noargs_command', '--settings=alternate_settings']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertNoOutput(err)
|
||||
|
||||
def test_custom_command_with_environment(self):
|
||||
"alternate: manage.py can execute user commands if settings are provided in environment"
|
||||
args = ['noargs_command']
|
||||
out, err = self.run_manage(args, 'alternate_settings')
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertNoOutput(err)
|
||||
|
||||
def test_custom_command_output_color(self):
|
||||
"alternate: manage.py output syntax color can be deactivated with the `--no-color` option"
|
||||
args = ['noargs_command', '--no-color', '--settings=alternate_settings']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', True), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertNoOutput(err)
|
||||
|
||||
|
||||
@@ -1271,40 +1279,47 @@ class CommandTypes(AdminScriptTestCase):
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s).")
|
||||
|
||||
def test_no_color(self):
|
||||
"--no-color prevent colorization of the output"
|
||||
out = StringIO()
|
||||
|
||||
call_command('color_command', no_color=True, stdout=out)
|
||||
self.assertEqual(out.getvalue(), 'BEGIN\n')
|
||||
|
||||
def test_base_command(self):
|
||||
"User BaseCommands can execute when a label is provided"
|
||||
args = ['base_command', 'testlabel']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_base_command_no_label(self):
|
||||
"User BaseCommands can execute when no labels are provided"
|
||||
args = ['base_command']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_base_command_multiple_label(self):
|
||||
"User BaseCommands can execute when no labels are provided"
|
||||
args = ['base_command', 'testlabel', 'anotherlabel']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_base_command_with_option(self):
|
||||
"User BaseCommands can execute with options when a label is provided"
|
||||
args = ['base_command', 'testlabel', '--option_a=x']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_base_command_with_options(self):
|
||||
"User BaseCommands can execute with multiple options when a label is provided"
|
||||
args = ['base_command', 'testlabel', '-a', 'x', '--option_b=y']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_base_run_from_argv(self):
|
||||
"""
|
||||
@@ -1350,7 +1365,7 @@ class CommandTypes(AdminScriptTestCase):
|
||||
args = ['noargs_command']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_noargs_with_args(self):
|
||||
"NoArg Commands raise an error if an argument is provided"
|
||||
@@ -1365,7 +1380,7 @@ class CommandTypes(AdminScriptTestCase):
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
|
||||
self.assertOutput(out, os.sep.join(['django', 'contrib', 'auth', 'models.py']))
|
||||
self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_app_command_no_apps(self):
|
||||
"User AppCommands raise an error when no app name is provided"
|
||||
@@ -1380,10 +1395,10 @@ class CommandTypes(AdminScriptTestCase):
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
|
||||
self.assertOutput(out, os.sep.join(['django', 'contrib', 'auth', 'models.py']))
|
||||
self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.contenttypes.models'")
|
||||
self.assertOutput(out, os.sep.join(['django', 'contrib', 'contenttypes', 'models.py']))
|
||||
self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_app_command_invalid_appname(self):
|
||||
"User AppCommands can execute when a single app name is provided"
|
||||
@@ -1402,7 +1417,7 @@ class CommandTypes(AdminScriptTestCase):
|
||||
args = ['label_command', 'testlabel']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_label_command_no_label(self):
|
||||
"User LabelCommands raise an error if no label is provided"
|
||||
@@ -1415,8 +1430,8 @@ class CommandTypes(AdminScriptTestCase):
|
||||
args = ['label_command', 'testlabel', 'anotherlabel']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
class ArgumentOrder(AdminScriptTestCase):
|
||||
"""Tests for 2-stage argument parsing scheme.
|
||||
@@ -1440,35 +1455,35 @@ class ArgumentOrder(AdminScriptTestCase):
|
||||
args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_setting_then_short_option(self):
|
||||
"Short options passed after settings are correctly handled"
|
||||
args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_option_then_setting(self):
|
||||
"Options passed before settings are correctly handled"
|
||||
args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_short_option_then_setting(self):
|
||||
"Short options passed before settings are correctly handled"
|
||||
args = ['base_command', 'testlabel', '-a', 'x', '--settings=alternate_settings']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
def test_option_then_setting_then_option(self):
|
||||
"Options are correctly handled when they are passed before and after a setting"
|
||||
args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings', '--option_b=y']
|
||||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]")
|
||||
|
||||
|
||||
class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@@ -301,7 +301,7 @@ class UtilTests(SimpleTestCase):
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
|
||||
'<label for="id_text" class="required inline"><i>text</i>:</label>')
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i>:</label>')
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>')
|
||||
|
||||
# normal strings needs to be escaped
|
||||
class MyForm(forms.Form):
|
||||
@@ -312,7 +312,7 @@ class UtilTests(SimpleTestCase):
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),
|
||||
'<label for="id_text" class="required inline">&text:</label>')
|
||||
self.assertHTMLEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline">&cb:</label>')
|
||||
'<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>')
|
||||
|
||||
def test_flatten_fieldsets(self):
|
||||
"""
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
from django.test.utils import str_prefix
|
||||
|
||||
from .models import Song, Book, Album, TwoAlbumFKAndAnE, State, City
|
||||
|
||||
@@ -185,7 +186,8 @@ class ValidationTestCase(TestCase):
|
||||
readonly_fields = ("title", "nonexistant")
|
||||
|
||||
self.assertRaisesMessage(ImproperlyConfigured,
|
||||
"SongAdmin.readonly_fields[1], 'nonexistant' is not a callable or an attribute of 'SongAdmin' or found in the model 'Song'.",
|
||||
str_prefix("SongAdmin.readonly_fields[1], %(_)s'nonexistant' is not a callable "
|
||||
"or an attribute of 'SongAdmin' or found in the model 'Song'."),
|
||||
SongAdmin.validate,
|
||||
Song)
|
||||
|
||||
@@ -195,7 +197,8 @@ class ValidationTestCase(TestCase):
|
||||
readonly_fields=['i_dont_exist'] # Missing attribute
|
||||
|
||||
self.assertRaisesMessage(ImproperlyConfigured,
|
||||
"CityInline.readonly_fields[0], 'i_dont_exist' is not a callable or an attribute of 'CityInline' or found in the model 'City'.",
|
||||
str_prefix("CityInline.readonly_fields[0], %(_)s'i_dont_exist' is not a callable "
|
||||
"or an attribute of 'CityInline' or found in the model 'City'."),
|
||||
CityInline.validate,
|
||||
City)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
A second, custom AdminSite -- see tests.CustomAdminSiteTests.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import patterns
|
||||
from django.contrib import admin
|
||||
@@ -13,6 +13,7 @@ from . import models, forms, admin as base_admin
|
||||
|
||||
|
||||
class Admin2(admin.AdminSite):
|
||||
app_index_template = 'custom_admin/app_index.html'
|
||||
login_form = forms.CustomAdminAuthenticationForm
|
||||
login_template = 'custom_admin/login.html'
|
||||
logout_template = 'custom_admin/logout.html'
|
||||
|
||||
@@ -644,8 +644,8 @@ class MainPrepopulated(models.Model):
|
||||
max_length=20,
|
||||
choices=(('option one', 'Option One'),
|
||||
('option two', 'Option Two')))
|
||||
slug1 = models.SlugField()
|
||||
slug2 = models.SlugField()
|
||||
slug1 = models.SlugField(blank=True)
|
||||
slug2 = models.SlugField(blank=True)
|
||||
|
||||
class RelatedPrepopulated(models.Model):
|
||||
parent = models.ForeignKey(MainPrepopulated)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# coding: utf-8
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -806,6 +806,12 @@ class CustomModelAdminTest(AdminViewBasicTestCase):
|
||||
self.assertTemplateUsed(response, 'custom_admin/index.html')
|
||||
self.assertContains(response, 'Hello from a custom index template *bar*')
|
||||
|
||||
def testCustomAdminSiteAppIndexViewandTemplate(self):
|
||||
response = self.client.get('/test_admin/admin2/admin_views/')
|
||||
self.assertIsInstance(response, TemplateResponse)
|
||||
self.assertTemplateUsed(response, 'custom_admin/app_index.html')
|
||||
self.assertContains(response, 'Hello from a custom app_index template')
|
||||
|
||||
def testCustomAdminSitePasswordChangeTemplate(self):
|
||||
response = self.client.get('/test_admin/admin2/password_change/')
|
||||
self.assertIsInstance(response, TemplateResponse)
|
||||
@@ -1496,7 +1502,7 @@ class AdminViewStringPrimaryKeyTest(TestCase):
|
||||
response = self.client.get(prefix)
|
||||
# this URL now comes through reverse(), thus url quoting and iri_to_uri encoding
|
||||
pk_final_url = escape(iri_to_uri(urlquote(quote(self.pk))))
|
||||
should_contain = """<th><a href="%s%s/">%s</a></th>""" % (prefix, pk_final_url, escape(self.pk))
|
||||
should_contain = """<th class="field-__str__"><a href="%s%s/">%s</a></th>""" % (prefix, pk_final_url, escape(self.pk))
|
||||
self.assertContains(response, should_contain)
|
||||
|
||||
def test_recentactions_link(self):
|
||||
@@ -1527,6 +1533,17 @@ class AdminViewStringPrimaryKeyTest(TestCase):
|
||||
self.assertEqual(counted_presence_before - 1,
|
||||
counted_presence_after)
|
||||
|
||||
def test_logentry_get_admin_url(self):
|
||||
"LogEntry.get_admin_url returns a URL to edit the entry's object or None for non-existent (possibly deleted) models"
|
||||
log_entry_name = "Model with string primary key" # capitalized in Recent Actions
|
||||
logentry = LogEntry.objects.get(content_type__name__iexact=log_entry_name)
|
||||
model = "modelwithstringprimarykey"
|
||||
desired_admin_url = "/test_admin/admin/admin_views/%s/%s/" % (model, escape(iri_to_uri(urlquote(quote(self.pk)))))
|
||||
self.assertEqual(logentry.get_admin_url(), desired_admin_url)
|
||||
|
||||
logentry.content_type.model = "non-existent"
|
||||
self.assertEqual(logentry.get_admin_url(), None)
|
||||
|
||||
def test_deleteconfirmation_link(self):
|
||||
"The link from the delete confirmation page referring back to the changeform of the object should be quoted"
|
||||
response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk))
|
||||
@@ -2151,8 +2168,8 @@ class AdminViewListEditable(TestCase):
|
||||
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
|
||||
self.assertContains(response, 'id="id_form-1-id"', 1)
|
||||
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True)
|
||||
self.assertContains(response, '<td>%d</td>' % story1.id, 1)
|
||||
self.assertContains(response, '<td>%d</td>' % story2.id, 1)
|
||||
self.assertContains(response, '<td class="field-id">%d</td>' % story1.id, 1)
|
||||
self.assertContains(response, '<td class="field-id">%d</td>' % story2.id, 1)
|
||||
|
||||
def test_pk_hidden_fields_with_list_display_links(self):
|
||||
""" Similarly as test_pk_hidden_fields, but when the hidden pk fields are
|
||||
@@ -2167,8 +2184,8 @@ class AdminViewListEditable(TestCase):
|
||||
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
|
||||
self.assertContains(response, 'id="id_form-1-id"', 1)
|
||||
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True)
|
||||
self.assertContains(response, '<th><a href="%s">%d</a></th>' % (link1, story1.id), 1)
|
||||
self.assertContains(response, '<th><a href="%s">%d</a></th>' % (link2, story2.id), 1)
|
||||
self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link1, story1.id), 1)
|
||||
self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link2, story2.id), 1)
|
||||
|
||||
|
||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||
@@ -3438,6 +3455,50 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
|
||||
slug2='option-one-tabular-inline-ignored-characters',
|
||||
)
|
||||
|
||||
def test_populate_existing_object(self):
|
||||
"""
|
||||
Ensure that the prepopulation works for existing objects too, as long
|
||||
as the original field is empty.
|
||||
Refs #19082.
|
||||
"""
|
||||
# Slugs are empty to start with.
|
||||
item = MainPrepopulated.objects.create(
|
||||
name=' this is the mAin nÀMë',
|
||||
pubdate='2012-02-18',
|
||||
status='option two',
|
||||
slug1='',
|
||||
slug2='',
|
||||
)
|
||||
self.admin_login(username='super',
|
||||
password='secret',
|
||||
login_url='/test_admin/admin/')
|
||||
|
||||
object_url = '%s%s' % (
|
||||
self.live_server_url,
|
||||
'/test_admin/admin/admin_views/mainprepopulated/{}/'.format(item.id))
|
||||
|
||||
self.selenium.get(object_url)
|
||||
self.selenium.find_element_by_css_selector('#id_name').send_keys(' the best')
|
||||
|
||||
# The slugs got prepopulated since they were originally empty
|
||||
slug1 = self.selenium.find_element_by_css_selector('#id_slug1').get_attribute('value')
|
||||
slug2 = self.selenium.find_element_by_css_selector('#id_slug2').get_attribute('value')
|
||||
self.assertEqual(slug1, 'main-name-best-2012-02-18')
|
||||
self.assertEqual(slug2, 'option-two-main-name-best')
|
||||
|
||||
# Save the object
|
||||
self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
|
||||
self.wait_page_loaded()
|
||||
|
||||
self.selenium.get(object_url)
|
||||
self.selenium.find_element_by_css_selector('#id_name').send_keys(' hello')
|
||||
|
||||
# The slugs got prepopulated didn't change since they were originally not empty
|
||||
slug1 = self.selenium.find_element_by_css_selector('#id_slug1').get_attribute('value')
|
||||
slug2 = self.selenium.find_element_by_css_selector('#id_slug2').get_attribute('value')
|
||||
self.assertEqual(slug1, 'main-name-best-2012-02-18')
|
||||
self.assertEqual(slug2, 'option-two-main-name-best')
|
||||
|
||||
def test_collapsible_fieldset(self):
|
||||
"""
|
||||
Test that the 'collapse' class in fieldsets definition allows to
|
||||
@@ -3877,6 +3938,22 @@ class CSSTest(TestCase):
|
||||
self.assertContains(response,
|
||||
'<body class="app-admin_views model-section ')
|
||||
|
||||
def test_changelist_field_classes(self):
|
||||
"""
|
||||
Cells of the change list table should contain the field name in their class attribute
|
||||
Refs #11195.
|
||||
"""
|
||||
Podcast.objects.create(name="Django Dose",
|
||||
release_date=datetime.date.today())
|
||||
response = self.client.get('/test_admin/admin/admin_views/podcast/')
|
||||
self.assertContains(
|
||||
response, '<th class="field-name">')
|
||||
self.assertContains(
|
||||
response, '<td class="field-release_date nowrap">')
|
||||
self.assertContains(
|
||||
response, '<td class="action-checkbox">')
|
||||
|
||||
|
||||
try:
|
||||
import docutils
|
||||
except ImportError:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns, include
|
||||
|
||||
from . import views, customadmin, admin
|
||||
|
||||
@@ -13,6 +13,7 @@ class Member(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
birthdate = models.DateTimeField(blank=True, null=True)
|
||||
gender = models.CharField(max_length=1, blank=True, choices=[('M','Male'), ('F', 'Female')])
|
||||
email = models.EmailField(blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -55,7 +56,8 @@ class Inventory(models.Model):
|
||||
return self.name
|
||||
|
||||
class Event(models.Model):
|
||||
band = models.ForeignKey(Band, limit_choices_to=models.Q(pk__gt=0))
|
||||
main_band = models.ForeignKey(Band, limit_choices_to=models.Q(pk__gt=0), related_name='events_main_band_at')
|
||||
supporting_bands = models.ManyToManyField(Band, null=True, blank=True, related_name='events_supporting_band_at')
|
||||
start_date = models.DateField(blank=True, null=True)
|
||||
start_time = models.TimeField(blank=True, null=True)
|
||||
description = models.TextField(blank=True)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# encoding: utf-8
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from unittest import TestCase
|
||||
@@ -83,19 +83,22 @@ class AdminFormfieldForDBFieldTests(TestCase):
|
||||
def testCharField(self):
|
||||
self.assertFormfield(models.Member, 'name', widgets.AdminTextInputWidget)
|
||||
|
||||
def testEmailField(self):
|
||||
self.assertFormfield(models.Member, 'email', widgets.AdminEmailInputWidget)
|
||||
|
||||
def testFileField(self):
|
||||
self.assertFormfield(models.Album, 'cover_art', widgets.AdminFileWidget)
|
||||
|
||||
def testForeignKey(self):
|
||||
self.assertFormfield(models.Event, 'band', forms.Select)
|
||||
self.assertFormfield(models.Event, 'main_band', forms.Select)
|
||||
|
||||
def testRawIDForeignKey(self):
|
||||
self.assertFormfield(models.Event, 'band', widgets.ForeignKeyRawIdWidget,
|
||||
raw_id_fields=['band'])
|
||||
self.assertFormfield(models.Event, 'main_band', widgets.ForeignKeyRawIdWidget,
|
||||
raw_id_fields=['main_band'])
|
||||
|
||||
def testRadioFieldsForeignKey(self):
|
||||
ff = self.assertFormfield(models.Event, 'band', widgets.AdminRadioSelect,
|
||||
radio_fields={'band':admin.VERTICAL})
|
||||
ff = self.assertFormfield(models.Event, 'main_band', widgets.AdminRadioSelect,
|
||||
radio_fields={'main_band':admin.VERTICAL})
|
||||
self.assertEqual(ff.empty_label, None)
|
||||
|
||||
def testManyToMany(self):
|
||||
@@ -198,7 +201,7 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
|
||||
pk = band.pk
|
||||
band.delete()
|
||||
post_data = {
|
||||
"band": '%s' % pk,
|
||||
"main_band": '%s' % pk,
|
||||
}
|
||||
# Try posting with a non-existent pk in a raw id field: this
|
||||
# should result in an error message, not a server exception.
|
||||
@@ -212,7 +215,7 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
|
||||
for test_str in ('Iñtërnâtiônàlizætiøn', "1234'", -1234):
|
||||
# This should result in an error message, not a server exception.
|
||||
response = self.client.post('%s/admin_widgets/event/add/' % self.admin_root,
|
||||
{"band": test_str})
|
||||
{"main_band": test_str})
|
||||
|
||||
self.assertContains(response,
|
||||
'Select a valid choice. That choice is not one of the available choices.')
|
||||
@@ -223,6 +226,13 @@ class AdminForeignKeyRawIdWidget(DjangoTestCase):
|
||||
self.assertEqual(lookup1, {'color__in': 'red,blue'})
|
||||
self.assertEqual(lookup1, lookup2)
|
||||
|
||||
def test_url_params_from_lookup_dict_callable(self):
|
||||
def my_callable():
|
||||
return 'works'
|
||||
lookup1 = widgets.url_params_from_lookup_dict({'myfield': my_callable})
|
||||
lookup2 = widgets.url_params_from_lookup_dict({'myfield': my_callable()})
|
||||
self.assertEqual(lookup1, lookup2)
|
||||
|
||||
|
||||
class FilteredSelectMultipleWidgetTest(DjangoTestCase):
|
||||
def test_render(self):
|
||||
@@ -300,29 +310,29 @@ class AdminURLWidgetTest(DjangoTestCase):
|
||||
w = widgets.AdminURLFieldWidget()
|
||||
self.assertHTMLEqual(
|
||||
conditional_escape(w.render('test', '')),
|
||||
'<input class="vURLField" name="test" type="text" />'
|
||||
'<input class="vURLField" name="test" type="url" />'
|
||||
)
|
||||
self.assertHTMLEqual(
|
||||
conditional_escape(w.render('test', 'http://example.com')),
|
||||
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /></p>'
|
||||
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com" /></p>'
|
||||
)
|
||||
|
||||
def test_render_idn(self):
|
||||
w = widgets.AdminURLFieldWidget()
|
||||
self.assertHTMLEqual(
|
||||
conditional_escape(w.render('test', 'http://example-äüö.com')),
|
||||
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com" /></p>'
|
||||
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com" /></p>'
|
||||
)
|
||||
|
||||
def test_render_quoting(self):
|
||||
w = widgets.AdminURLFieldWidget()
|
||||
self.assertHTMLEqual(
|
||||
conditional_escape(w.render('test', 'http://example.com/<sometag>some text</sometag>')),
|
||||
'<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/<sometag>some text</sometag></a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some text</sometag>" /></p>'
|
||||
'<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/<sometag>some text</sometag></a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com/<sometag>some text</sometag>" /></p>'
|
||||
)
|
||||
self.assertHTMLEqual(
|
||||
conditional_escape(w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>')),
|
||||
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/<sometag>some text</sometag></a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
|
||||
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/<sometag>some text</sometag></a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
|
||||
)
|
||||
|
||||
|
||||
@@ -816,3 +826,100 @@ class HorizontalVerticalFilterSeleniumChromeTests(HorizontalVerticalFilterSeleni
|
||||
|
||||
class HorizontalVerticalFilterSeleniumIETests(HorizontalVerticalFilterSeleniumFirefoxTests):
|
||||
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
||||
|
||||
|
||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||
class AdminRawIdWidgetSeleniumFirefoxTests(AdminSeleniumWebDriverTestCase):
|
||||
available_apps = ['admin_widgets'] + AdminSeleniumWebDriverTestCase.available_apps
|
||||
fixtures = ['admin-widgets-users.xml']
|
||||
urls = "admin_widgets.urls"
|
||||
webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
|
||||
|
||||
def setUp(self):
|
||||
models.Band.objects.create(id=42, name='Bogey Blues')
|
||||
models.Band.objects.create(id=98, name='Green Potatoes')
|
||||
super(AdminRawIdWidgetSeleniumFirefoxTests, self).setUp()
|
||||
|
||||
def test_foreignkey(self):
|
||||
self.admin_login(username='super', password='secret', login_url='/')
|
||||
self.selenium.get(
|
||||
'%s%s' % (self.live_server_url, '/admin_widgets/event/add/'))
|
||||
main_window = self.selenium.current_window_handle
|
||||
|
||||
# No value has been selected yet
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
|
||||
'')
|
||||
|
||||
# Open the popup window and click on a band
|
||||
self.selenium.find_element_by_id('lookup_id_main_band').click()
|
||||
self.selenium.switch_to_window('id_main_band')
|
||||
self.wait_page_loaded()
|
||||
link = self.selenium.find_element_by_link_text('Bogey Blues')
|
||||
self.assertTrue('/band/42/' in link.get_attribute('href'))
|
||||
link.click()
|
||||
|
||||
# The field now contains the selected band's id
|
||||
self.selenium.switch_to_window(main_window)
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
|
||||
'42')
|
||||
|
||||
# Reopen the popup window and click on another band
|
||||
self.selenium.find_element_by_id('lookup_id_main_band').click()
|
||||
self.selenium.switch_to_window('id_main_band')
|
||||
self.wait_page_loaded()
|
||||
link = self.selenium.find_element_by_link_text('Green Potatoes')
|
||||
self.assertTrue('/band/98/' in link.get_attribute('href'))
|
||||
link.click()
|
||||
|
||||
# The field now contains the other selected band's id
|
||||
self.selenium.switch_to_window(main_window)
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_main_band').get_attribute('value'),
|
||||
'98')
|
||||
|
||||
def test_many_to_many(self):
|
||||
self.admin_login(username='super', password='secret', login_url='/')
|
||||
self.selenium.get(
|
||||
'%s%s' % (self.live_server_url, '/admin_widgets/event/add/'))
|
||||
main_window = self.selenium.current_window_handle
|
||||
|
||||
# No value has been selected yet
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
|
||||
'')
|
||||
|
||||
# Open the popup window and click on a band
|
||||
self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
|
||||
self.selenium.switch_to_window('id_supporting_bands')
|
||||
self.wait_page_loaded()
|
||||
link = self.selenium.find_element_by_link_text('Bogey Blues')
|
||||
self.assertTrue('/band/42/' in link.get_attribute('href'))
|
||||
link.click()
|
||||
|
||||
# The field now contains the selected band's id
|
||||
self.selenium.switch_to_window(main_window)
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
|
||||
'42')
|
||||
|
||||
# Reopen the popup window and click on another band
|
||||
self.selenium.find_element_by_id('lookup_id_supporting_bands').click()
|
||||
self.selenium.switch_to_window('id_supporting_bands')
|
||||
self.wait_page_loaded()
|
||||
link = self.selenium.find_element_by_link_text('Green Potatoes')
|
||||
self.assertTrue('/band/98/' in link.get_attribute('href'))
|
||||
link.click()
|
||||
|
||||
# The field now contains the two selected bands' ids
|
||||
self.selenium.switch_to_window(main_window)
|
||||
self.assertEqual(
|
||||
self.selenium.find_element_by_id('id_supporting_bands').get_attribute('value'),
|
||||
'42,98')
|
||||
|
||||
class AdminRawIdWidgetSeleniumChromeTests(AdminRawIdWidgetSeleniumFirefoxTests):
|
||||
webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'
|
||||
|
||||
class AdminRawIdWidgetSeleniumIETests(AdminRawIdWidgetSeleniumFirefoxTests):
|
||||
webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns, include
|
||||
|
||||
from . import widgetadmin
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from . import models
|
||||
@@ -23,7 +18,7 @@ class CarTireAdmin(admin.ModelAdmin):
|
||||
return super(CarTireAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
|
||||
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ['band']
|
||||
raw_id_fields = ['main_band', 'supporting_bands']
|
||||
|
||||
|
||||
class SchoolAdmin(admin.ModelAdmin):
|
||||
@@ -47,4 +42,4 @@ site.register(models.Bee)
|
||||
|
||||
site.register(models.Advisor)
|
||||
|
||||
site.register(models.School, SchoolAdmin)
|
||||
site.register(models.School, SchoolAdmin)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
@@ -585,3 +585,35 @@ class BaseAggregateTestCase(TestCase):
|
||||
"datetime.date(2008, 1, 1)"
|
||||
]
|
||||
)
|
||||
|
||||
def test_values_aggregation(self):
|
||||
# Refs #20782
|
||||
max_rating = Book.objects.values('rating').aggregate(max_rating=Max('rating'))
|
||||
self.assertEqual(max_rating['max_rating'], 5)
|
||||
max_books_per_rating = Book.objects.values('rating').annotate(
|
||||
books_per_rating=Count('id')
|
||||
).aggregate(Max('books_per_rating'))
|
||||
self.assertEqual(
|
||||
max_books_per_rating,
|
||||
{'books_per_rating__max': 3})
|
||||
|
||||
def test_ticket17424(self):
|
||||
"""
|
||||
Check that doing exclude() on a foreign model after annotate()
|
||||
doesn't crash.
|
||||
"""
|
||||
all_books = list(Book.objects.values_list('pk', flat=True).order_by('pk'))
|
||||
annotated_books = Book.objects.order_by('pk').annotate(one=Count("id"))
|
||||
|
||||
# The value doesn't matter, we just need any negative
|
||||
# constraint on a related model that's a noop.
|
||||
excluded_books = annotated_books.exclude(publisher__name="__UNLIKELY_VALUE__")
|
||||
|
||||
# Try to generate query tree
|
||||
str(excluded_books.query)
|
||||
|
||||
self.assertQuerysetEqual(excluded_books, all_books, lambda x: x.pk)
|
||||
|
||||
# Check internal state
|
||||
self.assertIsNone(annotated_books.query.alias_map["aggregation_book"].join_type)
|
||||
self.assertIsNone(excluded_books.query.alias_map["aggregation_book"].join_type)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import pickle
|
||||
@@ -250,6 +250,13 @@ class AggregationTests(TestCase):
|
||||
'price__max': Decimal("82.80")
|
||||
})
|
||||
|
||||
# Regression for #15624 - Missing SELECT columns when using values, annotate
|
||||
# and aggregate in a single query
|
||||
self.assertEqual(
|
||||
Book.objects.annotate(c=Count('authors')).values('c').aggregate(Max('c')),
|
||||
{'c__max': 3}
|
||||
)
|
||||
|
||||
def test_field_error(self):
|
||||
# Bad field requests in aggregates are caught and reported
|
||||
self.assertRaises(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import copy
|
||||
import os
|
||||
@@ -7,7 +7,8 @@ import time
|
||||
from unittest import TestCase
|
||||
|
||||
from django.conf import Settings
|
||||
from django.db.models.loading import cache, load_app, get_model, get_models
|
||||
from django.db.models.loading import cache, load_app, get_model, get_models, AppCache
|
||||
from django.test.utils import override_settings
|
||||
from django.utils._os import upath
|
||||
|
||||
|
||||
@@ -61,12 +62,33 @@ class EggLoadingTest(TestCase):
|
||||
egg_name = '%s/brokenapp.egg' % self.egg_dir
|
||||
sys.path.append(egg_name)
|
||||
self.assertRaises(ImportError, load_app, 'broken_app')
|
||||
raised = None
|
||||
try:
|
||||
load_app('broken_app')
|
||||
except ImportError as e:
|
||||
# Make sure the message is indicating the actual
|
||||
# problem in the broken app.
|
||||
self.assertTrue("modelz" in e.args[0])
|
||||
raised = e
|
||||
|
||||
# Make sure the message is indicating the actual
|
||||
# problem in the broken app.
|
||||
self.assertTrue(raised is not None)
|
||||
self.assertTrue("modelz" in raised.args[0])
|
||||
|
||||
def test_missing_app(self):
|
||||
"""
|
||||
Test that repeated app loading doesn't succeed in case there is an
|
||||
error. Refs #17667.
|
||||
"""
|
||||
# AppCache is a Borg, so we can instantiate one and change its
|
||||
# loaded to False to force the following code to actually try to
|
||||
# populate the cache.
|
||||
a = AppCache()
|
||||
a.loaded = False
|
||||
try:
|
||||
with override_settings(INSTALLED_APPS=('notexists',)):
|
||||
self.assertRaises(ImportError, get_model, 'notexists', 'nomodel', seed_cache=True)
|
||||
self.assertRaises(ImportError, get_model, 'notexists', 'nomodel', seed_cache=True)
|
||||
finally:
|
||||
a.loaded = True
|
||||
|
||||
|
||||
class GetModelsTest(TestCase):
|
||||
|
||||
@@ -68,11 +68,18 @@ class Reporter(models.Model):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
|
||||
class ReporterProxy(Reporter):
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Article(models.Model):
|
||||
headline = models.CharField(max_length=100)
|
||||
pub_date = models.DateField()
|
||||
reporter = models.ForeignKey(Reporter)
|
||||
reporter_proxy = models.ForeignKey(ReporterProxy, null=True,
|
||||
related_name='reporter_proxy')
|
||||
|
||||
def __str__(self):
|
||||
return self.headline
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Unit and doctests for specific database backends.
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
@@ -614,12 +614,19 @@ class FkConstraintsTests(TransactionTestCase):
|
||||
Try to create a model instance that violates a FK constraint. If it
|
||||
fails it should fail with IntegrityError.
|
||||
"""
|
||||
a = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
|
||||
a1 = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
|
||||
try:
|
||||
a.save()
|
||||
a1.save()
|
||||
except IntegrityError:
|
||||
return
|
||||
self.skipTest("This backend does not support integrity checks.")
|
||||
pass
|
||||
else:
|
||||
self.skipTest("This backend does not support integrity checks.")
|
||||
# Now that we know this backend supports integrity checks we make sure
|
||||
# constraints are also enforced for proxy models. Refs #17519
|
||||
a2 = models.Article(headline='This is another test', reporter=self.r,
|
||||
pub_date=datetime.datetime(2012, 8, 3),
|
||||
reporter_proxy_id=30)
|
||||
self.assertRaises(IntegrityError, a2.save)
|
||||
|
||||
def test_integrity_checks_on_update(self):
|
||||
"""
|
||||
@@ -628,14 +635,26 @@ class FkConstraintsTests(TransactionTestCase):
|
||||
"""
|
||||
# Create an Article.
|
||||
models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
|
||||
# Retrive it from the DB
|
||||
a = models.Article.objects.get(headline="Test article")
|
||||
a.reporter_id = 30
|
||||
# Retrieve it from the DB
|
||||
a1 = models.Article.objects.get(headline="Test article")
|
||||
a1.reporter_id = 30
|
||||
try:
|
||||
a.save()
|
||||
a1.save()
|
||||
except IntegrityError:
|
||||
return
|
||||
self.skipTest("This backend does not support integrity checks.")
|
||||
pass
|
||||
else:
|
||||
self.skipTest("This backend does not support integrity checks.")
|
||||
# Now that we know this backend supports integrity checks we make sure
|
||||
# constraints are also enforced for proxy models. Refs #17519
|
||||
# Create another article
|
||||
r_proxy = models.ReporterProxy.objects.get(pk=self.r.pk)
|
||||
models.Article.objects.create(headline='Another article',
|
||||
pub_date=datetime.datetime(1988, 5, 15),
|
||||
reporter=self.r, reporter_proxy=r_proxy)
|
||||
# Retreive the second article from the DB
|
||||
a2 = models.Article.objects.get(headline='Another article')
|
||||
a2.reporter_proxy_id = 30
|
||||
self.assertRaises(IntegrityError, a2.save)
|
||||
|
||||
def test_disable_constraint_checks_manually(self):
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
import threading
|
||||
@@ -6,6 +6,7 @@ import threading
|
||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
||||
from django.db import connections, DEFAULT_DB_ALIAS
|
||||
from django.db.models.fields import Field, FieldDoesNotExist
|
||||
from django.db.models.manager import BaseManager
|
||||
from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet, MAX_GET_RESULTS
|
||||
from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||
from django.utils import six
|
||||
@@ -734,3 +735,59 @@ class ConcurrentSaveTests(TransactionTestCase):
|
||||
t.join()
|
||||
a.save()
|
||||
self.assertEqual(Article.objects.get(pk=a.pk).headline, 'foo')
|
||||
|
||||
|
||||
class ManagerTest(TestCase):
|
||||
QUERYSET_PROXY_METHODS = [
|
||||
'none',
|
||||
'count',
|
||||
'dates',
|
||||
'datetimes',
|
||||
'distinct',
|
||||
'extra',
|
||||
'get',
|
||||
'get_or_create',
|
||||
'update_or_create',
|
||||
'create',
|
||||
'bulk_create',
|
||||
'filter',
|
||||
'aggregate',
|
||||
'annotate',
|
||||
'complex_filter',
|
||||
'exclude',
|
||||
'in_bulk',
|
||||
'iterator',
|
||||
'earliest',
|
||||
'latest',
|
||||
'first',
|
||||
'last',
|
||||
'order_by',
|
||||
'select_for_update',
|
||||
'select_related',
|
||||
'prefetch_related',
|
||||
'values',
|
||||
'values_list',
|
||||
'update',
|
||||
'reverse',
|
||||
'defer',
|
||||
'only',
|
||||
'using',
|
||||
'exists',
|
||||
'_insert',
|
||||
'_update',
|
||||
'raw',
|
||||
]
|
||||
|
||||
def test_manager_methods(self):
|
||||
"""
|
||||
This test ensures that the correct set of methods from `QuerySet`
|
||||
are copied onto `Manager`.
|
||||
|
||||
It's particularly useful to prevent accidentally leaking new methods
|
||||
into `Manager`. New `QuerySet` methods that should also be copied onto
|
||||
`Manager` will need to be added to `ManagerTest.QUERYSET_PROXY_METHODS`.
|
||||
"""
|
||||
self.assertEqual(
|
||||
sorted(BaseManager._get_queryset_methods(QuerySet).keys()),
|
||||
sorted(self.QUERYSET_PROXY_METHODS),
|
||||
)
|
||||
|
||||
@@ -4,8 +4,6 @@ gets called *again* for each FileField. This test will fail if calling a
|
||||
ModelForm's save() method causes Model.save() to be called more than once.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Story
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from operator import attrgetter
|
||||
|
||||
|
||||
2
tests/cache/tests.py
vendored
2
tests/cache/tests.py
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
# Unit tests for cache framework
|
||||
# Uses whatever cache backend is set in the test settings file.
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import Person
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.comments.forms import CommentForm
|
||||
from django.contrib.comments.models import Comment
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import comments
|
||||
from django.contrib.comments.models import Comment
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.comments.models import Comment
|
||||
from django.contrib.comments.moderation import (moderator, CommentModerator,
|
||||
AlreadyModerated)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.comments.models import Comment
|
||||
|
||||
from . import CommentTestCase
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from django.contrib.comments import signals
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.comments.forms import CommentForm
|
||||
from django.contrib.comments.models import Comment
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.contrib.comments.feeds import LatestCommentFeed
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.views.decorators.http import condition, etag, last_modified
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import patterns
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from . import views
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import FieldError
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import FieldError
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -20,6 +20,49 @@ class PersonManager(models.Manager):
|
||||
def get_fun_people(self):
|
||||
return self.filter(fun=True)
|
||||
|
||||
# An example of a custom manager that sets get_queryset().
|
||||
|
||||
class PublishedBookManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(PublishedBookManager, self).get_queryset().filter(is_published=True)
|
||||
|
||||
# An example of a custom queryset that copies its methods onto the manager.
|
||||
|
||||
class CustomQuerySet(models.QuerySet):
|
||||
def filter(self, *args, **kwargs):
|
||||
queryset = super(CustomQuerySet, self).filter(fun=True)
|
||||
queryset._filter_CustomQuerySet = True
|
||||
return queryset
|
||||
|
||||
def public_method(self, *args, **kwargs):
|
||||
return self.all()
|
||||
|
||||
def _private_method(self, *args, **kwargs):
|
||||
return self.all()
|
||||
|
||||
def optout_public_method(self, *args, **kwargs):
|
||||
return self.all()
|
||||
optout_public_method.queryset_only = True
|
||||
|
||||
def _optin_private_method(self, *args, **kwargs):
|
||||
return self.all()
|
||||
_optin_private_method.queryset_only = False
|
||||
|
||||
class BaseCustomManager(models.Manager):
|
||||
def __init__(self, arg):
|
||||
super(BaseCustomManager, self).__init__()
|
||||
self.init_arg = arg
|
||||
|
||||
def filter(self, *args, **kwargs):
|
||||
queryset = super(BaseCustomManager, self).filter(fun=True)
|
||||
queryset._filter_CustomManager = True
|
||||
return queryset
|
||||
|
||||
def manager_only(self):
|
||||
return self.all()
|
||||
|
||||
CustomManager = BaseCustomManager.from_queryset(CustomQuerySet)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(max_length=30)
|
||||
@@ -27,15 +70,12 @@ class Person(models.Model):
|
||||
fun = models.BooleanField()
|
||||
objects = PersonManager()
|
||||
|
||||
custom_queryset_default_manager = CustomQuerySet.as_manager()
|
||||
custom_queryset_custom_manager = CustomManager('hello')
|
||||
|
||||
def __str__(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
# An example of a custom manager that sets get_queryset().
|
||||
|
||||
class PublishedBookManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(PublishedBookManager, self).get_queryset().filter(is_published=True)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
@@ -11,12 +11,54 @@ class CustomManagerTests(TestCase):
|
||||
p1 = Person.objects.create(first_name="Bugs", last_name="Bunny", fun=True)
|
||||
p2 = Person.objects.create(first_name="Droopy", last_name="Dog", fun=False)
|
||||
|
||||
# Test a custom `Manager` method.
|
||||
self.assertQuerysetEqual(
|
||||
Person.objects.get_fun_people(), [
|
||||
"Bugs Bunny"
|
||||
],
|
||||
six.text_type
|
||||
)
|
||||
|
||||
# Test that the methods of a custom `QuerySet` are properly
|
||||
# copied onto the default `Manager`.
|
||||
for manager in ['custom_queryset_default_manager',
|
||||
'custom_queryset_custom_manager']:
|
||||
manager = getattr(Person, manager)
|
||||
|
||||
# Copy public methods.
|
||||
manager.public_method()
|
||||
# Don't copy private methods.
|
||||
with self.assertRaises(AttributeError):
|
||||
manager._private_method()
|
||||
# Copy methods with `manager=True` even if they are private.
|
||||
manager._optin_private_method()
|
||||
# Don't copy methods with `manager=False` even if they are public.
|
||||
with self.assertRaises(AttributeError):
|
||||
manager.optout_public_method()
|
||||
|
||||
# Test that the overridden method is called.
|
||||
queryset = manager.filter()
|
||||
self.assertQuerysetEqual(queryset, ["Bugs Bunny"], six.text_type)
|
||||
self.assertEqual(queryset._filter_CustomQuerySet, True)
|
||||
|
||||
# Test that specialized querysets inherit from our custom queryset.
|
||||
queryset = manager.values_list('first_name', flat=True).filter()
|
||||
self.assertEqual(list(queryset), [six.text_type("Bugs")])
|
||||
self.assertEqual(queryset._filter_CustomQuerySet, True)
|
||||
|
||||
# Test that the custom manager `__init__()` argument has been set.
|
||||
self.assertEqual(Person.custom_queryset_custom_manager.init_arg, 'hello')
|
||||
|
||||
# Test that the custom manager method is only available on the manager.
|
||||
Person.custom_queryset_custom_manager.manager_only()
|
||||
with self.assertRaises(AttributeError):
|
||||
Person.custom_queryset_custom_manager.all().manager_only()
|
||||
|
||||
# Test that the queryset method doesn't override the custom manager method.
|
||||
queryset = Person.custom_queryset_custom_manager.filter()
|
||||
self.assertQuerysetEqual(queryset, ["Bugs Bunny"], six.text_type)
|
||||
self.assertEqual(queryset._filter_CustomManager, True)
|
||||
|
||||
# The RelatedManager used on the 'books' descriptor extends the default
|
||||
# manager
|
||||
self.assertIsInstance(p2.books, PublishedBookManager)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import date
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ By default, Django adds an ``"id"`` field to each model. But you can override
|
||||
this behavior by explicitly adding ``primary_key=True`` to a field.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.test import TestCase, skipIfDBFeature
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -249,9 +249,10 @@ class DefaultFiltersTests(TestCase):
|
||||
'<a href="https://google.com" rel="nofollow">https://google.com</a>')
|
||||
|
||||
# Check urlize doesn't overquote already quoted urls - see #9655
|
||||
self.assertEqual(urlize('http://hi.baidu.com/%D6%D8%D0%C2%BF'),
|
||||
'<a href="http://hi.baidu.com/%D6%D8%D0%C2%BF" rel="nofollow">'
|
||||
'http://hi.baidu.com/%D6%D8%D0%C2%BF</a>')
|
||||
# The teststring is the urlquoted version of 'http://hi.baidu.com/重新开始'
|
||||
self.assertEqual(urlize('http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B'),
|
||||
'<a href="http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B" rel="nofollow">'
|
||||
'http://hi.baidu.com/%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B</a>')
|
||||
self.assertEqual(urlize('www.mystore.com/30%OffCoupons!'),
|
||||
'<a href="http://www.mystore.com/30%25OffCoupons!" rel="nofollow">'
|
||||
'www.mystore.com/30%OffCoupons!</a>')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models.query_utils import DeferredAttribute, InvalidQuery
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from operator import attrgetter
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, IntegrityError, connection
|
||||
from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -2,7 +2,5 @@
|
||||
Unit-tests for the dispatch project
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .test_dispatcher import DispatcherTests, ReceiverTestCase
|
||||
from .test_saferef import SaferefTests
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models import Max
|
||||
from django.test import TestCase, skipUnlessDBFeature
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models.loading import get_app
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import FieldError
|
||||
from django.db.models import F
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Spanning tests for all the operations that F() expressions can perform.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
from django.utils.datastructures import SortedDict
|
||||
|
||||
from .models import TestObject, Order, RevisionableModel
|
||||
|
||||
@@ -74,7 +74,7 @@ class ExtraRegressTests(TestCase):
|
||||
# select portions. Applies when portions are updated or otherwise
|
||||
# moved around.
|
||||
qs = User.objects.extra(
|
||||
select=SortedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))),
|
||||
select=OrderedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))),
|
||||
select_params=(1, 3)
|
||||
)
|
||||
qs = qs.extra(select={"beta": 4})
|
||||
@@ -180,100 +180,100 @@ class ExtraRegressTests(TestCase):
|
||||
obj.save()
|
||||
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values()),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values()),
|
||||
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}]
|
||||
)
|
||||
|
||||
# Extra clauses after an empty values clause are still included
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.values().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
list(TestObject.objects.values().extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}]
|
||||
)
|
||||
|
||||
# Extra columns are ignored if not mentioned in the values() clause
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second')),
|
||||
[{'second': 'second', 'first': 'first'}]
|
||||
)
|
||||
|
||||
# Extra columns after a non-empty values() clause are ignored
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.values('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
list(TestObject.objects.values('first', 'second').extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
[{'second': 'second', 'first': 'first'}]
|
||||
)
|
||||
|
||||
# Extra columns can be partially returned
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second', 'foo')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second', 'foo')),
|
||||
[{'second': 'second', 'foo': 'first', 'first': 'first'}]
|
||||
)
|
||||
|
||||
# Also works if only extra columns are included
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('foo', 'whiz')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('foo', 'whiz')),
|
||||
[{'foo': 'first', 'whiz': 'third'}]
|
||||
)
|
||||
|
||||
# Values list works the same way
|
||||
# All columns are returned for an empty values_list()
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list()),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list()),
|
||||
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
|
||||
)
|
||||
|
||||
# Extra columns after an empty values_list() are still included
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.values_list().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
list(TestObject.objects.values_list().extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
|
||||
)
|
||||
|
||||
# Extra columns ignored completely if not mentioned in values_list()
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second')),
|
||||
[('first', 'second')]
|
||||
)
|
||||
|
||||
# Extra columns after a non-empty values_list() clause are ignored completely
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.values_list('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
list(TestObject.objects.values_list('first', 'second').extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
|
||||
[('first', 'second')]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('second', flat=True)),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('second', flat=True)),
|
||||
['second']
|
||||
)
|
||||
|
||||
# Only the extra columns specified in the values_list() are returned
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second', 'whiz')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second', 'whiz')),
|
||||
[('first', 'second', 'third')]
|
||||
)
|
||||
|
||||
# ...also works if only extra columns are included
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('foo','whiz')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('foo','whiz')),
|
||||
[('first', 'third')]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', flat=True)),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', flat=True)),
|
||||
['third']
|
||||
)
|
||||
|
||||
# ... and values are returned in the order they are specified
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz','foo')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz','foo')),
|
||||
[('third', 'first')]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first','id')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first','id')),
|
||||
[('first', obj.pk)]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')),
|
||||
list(TestObject.objects.extra(select=OrderedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')),
|
||||
[('third', 'first', 'second', obj.pk)]
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
Tests for field subclassing.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.db import models
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core import serializers
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import errno
|
||||
import os
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#! -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
import errno
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import patterns
|
||||
|
||||
from . import views
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import gzip
|
||||
|
||||
2
tests/fixtures/tests.py
vendored
2
tests/fixtures/tests.py
vendored
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import warnings
|
||||
|
||||
|
||||
2
tests/fixtures_model_package/models/sql/book.sql
Normal file
2
tests/fixtures_model_package/models/sql/book.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- Deprecated search path for custom SQL -- remove in Django 1.9
|
||||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Deprecated Book');
|
||||
1
tests/fixtures_model_package/sql/book.sql
Normal file
1
tests/fixtures_model_package/sql/book.sql
Normal file
@@ -0,0 +1 @@
|
||||
INSERT INTO fixtures_model_package_book (name) VALUES ('My Book');
|
||||
@@ -5,6 +5,7 @@ import warnings
|
||||
from django.core import management
|
||||
from django.db import transaction
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.utils.six import StringIO
|
||||
|
||||
from .models import Article, Book
|
||||
|
||||
@@ -110,3 +111,19 @@ class FixtureTestCase(TestCase):
|
||||
],
|
||||
lambda a: a.headline,
|
||||
)
|
||||
|
||||
|
||||
class InitialSQLTests(TestCase):
|
||||
|
||||
def test_custom_sql(self):
|
||||
"""
|
||||
#14300 -- Verify that custom_sql_for_model searches `app/sql` and not
|
||||
`app/models/sql` (the old location will work until Django 1.9)
|
||||
"""
|
||||
out = StringIO()
|
||||
management.call_command("sqlcustom", "fixtures_model_package", stdout=out)
|
||||
output = out.getvalue()
|
||||
self.assertTrue("INSERT INTO fixtures_model_package_book (name) "
|
||||
"VALUES ('My Book')" in output)
|
||||
# value from deprecated search path models/sql (remove in Django 1.9)
|
||||
self.assertTrue("Deprecated Book" in output)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Unittests for fixtures.
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -181,55 +181,68 @@ class TestFixtures(TestCase):
|
||||
"""
|
||||
Test for ticket #4371 -- Loading a fixture file with invalid data
|
||||
using explicit filename.
|
||||
Validate that error conditions are caught correctly
|
||||
Test for ticket #18213 -- warning conditions are caught correctly
|
||||
"""
|
||||
with six.assertRaisesRegex(self, management.CommandError,
|
||||
"No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
|
||||
with warnings.catch_warnings(record=True) as warning_list:
|
||||
warnings.simplefilter("always")
|
||||
management.call_command(
|
||||
'loaddata',
|
||||
'bad_fixture2.xml',
|
||||
verbosity=0,
|
||||
)
|
||||
warning = warning_list.pop()
|
||||
self.assertEqual(warning.category, RuntimeWarning)
|
||||
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
|
||||
|
||||
def test_invalid_data_no_ext(self):
|
||||
"""
|
||||
Test for ticket #4371 -- Loading a fixture file with invalid data
|
||||
without file extension.
|
||||
Validate that error conditions are caught correctly
|
||||
Test for ticket #18213 -- warning conditions are caught correctly
|
||||
"""
|
||||
with six.assertRaisesRegex(self, management.CommandError,
|
||||
"No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
|
||||
with warnings.catch_warnings(record=True) as warning_list:
|
||||
warnings.simplefilter("always")
|
||||
management.call_command(
|
||||
'loaddata',
|
||||
'bad_fixture2',
|
||||
verbosity=0,
|
||||
)
|
||||
warning = warning_list.pop()
|
||||
self.assertEqual(warning.category, RuntimeWarning)
|
||||
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
|
||||
|
||||
def test_empty(self):
|
||||
"""
|
||||
Test for ticket #4371 -- Loading a fixture file with no data returns an error.
|
||||
Validate that error conditions are caught correctly
|
||||
Test for ticket #18213 -- Loading a fixture file with no data output a warning.
|
||||
Previously empty fixture raises an error exception, see ticket #4371.
|
||||
"""
|
||||
with six.assertRaisesRegex(self, management.CommandError,
|
||||
"No fixture data found for 'empty'. \(File format may be invalid.\)"):
|
||||
with warnings.catch_warnings(record=True) as warning_list:
|
||||
warnings.simplefilter("always")
|
||||
management.call_command(
|
||||
'loaddata',
|
||||
'empty',
|
||||
verbosity=0,
|
||||
)
|
||||
warning = warning_list.pop()
|
||||
self.assertEqual(warning.category, RuntimeWarning)
|
||||
self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)")
|
||||
|
||||
def test_error_message(self):
|
||||
"""
|
||||
(Regression for #9011 - error message is correct)
|
||||
Regression for #9011 - error message is correct.
|
||||
Change from error to warning for ticket #18213.
|
||||
"""
|
||||
with six.assertRaisesRegex(self, management.CommandError,
|
||||
"^No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)$"):
|
||||
with warnings.catch_warnings(record=True) as warning_list:
|
||||
warnings.simplefilter("always")
|
||||
management.call_command(
|
||||
'loaddata',
|
||||
'bad_fixture2',
|
||||
'animal',
|
||||
verbosity=0,
|
||||
)
|
||||
warning = warning_list.pop()
|
||||
self.assertEqual(warning.category, RuntimeWarning)
|
||||
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)")
|
||||
|
||||
def test_pg_sequence_resetting_checks(self):
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import transaction, IntegrityError, DatabaseError
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -5,14 +5,15 @@ from django.db.models.fields.related import ReverseSingleRelatedObjectDescriptor
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import get_language
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Country(models.Model):
|
||||
# Table Column Fields
|
||||
name = models.CharField(max_length=50)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Person(models.Model):
|
||||
# Table Column Fields
|
||||
name = models.CharField(max_length=128)
|
||||
@@ -26,9 +27,10 @@ class Person(models.Model):
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Group(models.Model):
|
||||
# Table Column Fields
|
||||
name = models.CharField(max_length=128)
|
||||
@@ -38,10 +40,11 @@ class Group(models.Model):
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Membership(models.Model):
|
||||
# Table Column Fields
|
||||
membership_country = models.ForeignKey(Country)
|
||||
@@ -51,17 +54,19 @@ class Membership(models.Model):
|
||||
group_id = models.IntegerField()
|
||||
|
||||
# Relation Fields
|
||||
person = models.ForeignObject(Person,
|
||||
person = models.ForeignObject(
|
||||
Person,
|
||||
from_fields=['membership_country', 'person_id'],
|
||||
to_fields=['person_country_id', 'id'])
|
||||
group = models.ForeignObject(Group,
|
||||
group = models.ForeignObject(
|
||||
Group,
|
||||
from_fields=['membership_country', 'group_id'],
|
||||
to_fields=['group_country', 'id'])
|
||||
|
||||
class Meta:
|
||||
ordering = ('date_joined', 'invite_reason')
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return "%s is a member of %s" % (self.person.name, self.group.name)
|
||||
|
||||
|
||||
@@ -73,17 +78,20 @@ class Friendship(models.Model):
|
||||
to_friend_id = models.IntegerField()
|
||||
|
||||
# Relation Fields
|
||||
from_friend = models.ForeignObject(Person,
|
||||
from_friend = models.ForeignObject(
|
||||
Person,
|
||||
from_fields=['from_friend_country', 'from_friend_id'],
|
||||
to_fields=['person_country_id', 'id'],
|
||||
related_name='from_friend')
|
||||
|
||||
to_friend_country = models.ForeignObject(Country,
|
||||
to_friend_country = models.ForeignObject(
|
||||
Country,
|
||||
from_fields=['to_friend_country_id'],
|
||||
to_fields=['id'],
|
||||
related_name='to_friend_country')
|
||||
|
||||
to_friend = models.ForeignObject(Person,
|
||||
to_friend = models.ForeignObject(
|
||||
Person,
|
||||
from_fields=['to_friend_country_id', 'to_friend_id'],
|
||||
to_fields=['person_country_id', 'id'],
|
||||
related_name='to_friend')
|
||||
@@ -140,6 +148,9 @@ class Article(models.Model):
|
||||
except ArticleTranslation.DoesNotExist:
|
||||
return '[No translation found]'
|
||||
|
||||
class NewsArticle(Article):
|
||||
pass
|
||||
|
||||
class ArticleTranslation(models.Model):
|
||||
article = models.ForeignKey(Article)
|
||||
lang = models.CharField(max_length='2')
|
||||
@@ -156,5 +167,6 @@ class ArticleTag(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
class ArticleIdea(models.Model):
|
||||
articles = models.ManyToManyField(Article, related_name="ideas", related_query_name="idea_things")
|
||||
articles = models.ManyToManyField(Article, related_name="ideas",
|
||||
related_query_name="idea_things")
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import datetime
|
||||
from operator import attrgetter
|
||||
|
||||
from .models import Country, Person, Group, Membership, Friendship, Article, ArticleTranslation, ArticleTag, ArticleIdea
|
||||
from .models import (
|
||||
Country, Person, Group, Membership, Friendship, Article,
|
||||
ArticleTranslation, ArticleTag, ArticleIdea, NewsArticle)
|
||||
from django.test import TestCase
|
||||
from django.utils.translation import activate
|
||||
from django.core.exceptions import FieldError
|
||||
from django import forms
|
||||
|
||||
# Note that these tests are testing internal implementation details.
|
||||
# ForeignObject is not part of public API.
|
||||
|
||||
class MultiColumnFKTests(TestCase):
|
||||
def setUp(self):
|
||||
# Creating countries
|
||||
@@ -140,9 +145,9 @@ class MultiColumnFKTests(TestCase):
|
||||
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
|
||||
|
||||
with self.assertNumQueries(1):
|
||||
people = [m.person for m in Membership.objects.select_related('person')]
|
||||
people = [m.person for m in Membership.objects.select_related('person').order_by('pk')]
|
||||
|
||||
normal_people = [m.person for m in Membership.objects.all()]
|
||||
normal_people = [m.person for m in Membership.objects.all().order_by('pk')]
|
||||
self.assertEqual(people, normal_people)
|
||||
|
||||
def test_prefetch_foreignkey_forward_works(self):
|
||||
@@ -150,19 +155,22 @@ class MultiColumnFKTests(TestCase):
|
||||
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
|
||||
|
||||
with self.assertNumQueries(2):
|
||||
people = [m.person for m in Membership.objects.prefetch_related('person')]
|
||||
people = [
|
||||
m.person for m in Membership.objects.prefetch_related('person').order_by('pk')]
|
||||
|
||||
normal_people = [m.person for m in Membership.objects.all()]
|
||||
normal_people = [m.person for m in Membership.objects.order_by('pk')]
|
||||
self.assertEqual(people, normal_people)
|
||||
|
||||
def test_prefetch_foreignkey_reverse_works(self):
|
||||
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
|
||||
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
|
||||
with self.assertNumQueries(2):
|
||||
membership_sets = [list(p.membership_set.all())
|
||||
for p in Person.objects.prefetch_related('membership_set')]
|
||||
membership_sets = [
|
||||
list(p.membership_set.all())
|
||||
for p in Person.objects.prefetch_related('membership_set').order_by('pk')]
|
||||
|
||||
normal_membership_sets = [list(p.membership_set.all()) for p in Person.objects.all()]
|
||||
normal_membership_sets = [list(p.membership_set.all())
|
||||
for p in Person.objects.order_by('pk')]
|
||||
self.assertEqual(membership_sets, normal_membership_sets)
|
||||
|
||||
def test_m2m_through_forward_returns_valid_members(self):
|
||||
@@ -339,6 +347,20 @@ class MultiColumnFKTests(TestCase):
|
||||
with self.assertRaises(FieldError):
|
||||
Article.objects.filter(ideas__name="idea1")
|
||||
|
||||
def test_inheritance(self):
|
||||
activate("fi")
|
||||
na = NewsArticle.objects.create(pub_date=datetime.date.today())
|
||||
ArticleTranslation.objects.create(
|
||||
article=na, lang="fi", title="foo", body="bar")
|
||||
self.assertQuerysetEqual(
|
||||
NewsArticle.objects.select_related('active_translation'),
|
||||
[na], lambda x: x
|
||||
)
|
||||
with self.assertNumQueries(1):
|
||||
self.assertEqual(
|
||||
NewsArticle.objects.select_related(
|
||||
'active_translation')[0].active_translation.title,
|
||||
"foo")
|
||||
|
||||
class FormsTests(TestCase):
|
||||
# ForeignObjects should not have any form fields, currently the user needs
|
||||
|
||||
@@ -34,7 +34,30 @@ class Defaults(models.Model):
|
||||
|
||||
class ChoiceModel(models.Model):
|
||||
"""For ModelChoiceField and ModelMultipleChoiceField tests."""
|
||||
CHOICES = [
|
||||
('', 'No Preference'),
|
||||
('f', 'Foo'),
|
||||
('b', 'Bar'),
|
||||
]
|
||||
|
||||
INTEGER_CHOICES = [
|
||||
(None, 'No Preference'),
|
||||
(1, 'Foo'),
|
||||
(2, 'Bar'),
|
||||
]
|
||||
|
||||
STRING_CHOICES_WITH_NONE = [
|
||||
(None, 'No Preference'),
|
||||
('f', 'Foo'),
|
||||
('b', 'Bar'),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=10)
|
||||
choice = models.CharField(max_length=2, blank=True, choices=CHOICES)
|
||||
choice_string_w_none = models.CharField(
|
||||
max_length=2, blank=True, null=True, choices=STRING_CHOICES_WITH_NONE)
|
||||
choice_integer = models.IntegerField(choices=INTEGER_CHOICES, blank=True,
|
||||
null=True)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .test_error_messages import (FormsErrorMessagesTestCase,
|
||||
ModelChoiceFieldErrorMessagesTestCase)
|
||||
from .test_extra import FormsExtraTestCase, FormsExtraL10NTestCase
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.forms import *
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -620,6 +620,37 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
|
||||
self.assertTrue(f.is_valid())
|
||||
self.assertEqual(f.cleaned_data['username'], 'sirrobin')
|
||||
|
||||
def test_changing_cleaned_data_nothing_returned(self):
|
||||
class UserForm(Form):
|
||||
username = CharField(max_length=10)
|
||||
password = CharField(widget=PasswordInput)
|
||||
|
||||
def clean(self):
|
||||
self.cleaned_data['username'] = self.cleaned_data['username'].lower()
|
||||
# don't return anything
|
||||
|
||||
f = UserForm({'username': 'SirRobin', 'password': 'blue'})
|
||||
self.assertTrue(f.is_valid())
|
||||
self.assertEqual(f.cleaned_data['username'], 'sirrobin')
|
||||
|
||||
def test_changing_cleaned_data_in_clean(self):
|
||||
class UserForm(Form):
|
||||
username = CharField(max_length=10)
|
||||
password = CharField(widget=PasswordInput)
|
||||
|
||||
def clean(self):
|
||||
data = self.cleaned_data
|
||||
|
||||
# Return a different dict. We have not changed self.cleaned_data.
|
||||
return {
|
||||
'username': data['username'].lower(),
|
||||
'password': 'this_is_not_a_secret',
|
||||
}
|
||||
|
||||
f = UserForm({'username': 'SirRobin', 'password': 'blue'})
|
||||
self.assertTrue(f.is_valid())
|
||||
self.assertEqual(f.cleaned_data['username'], 'sirrobin')
|
||||
|
||||
def test_overriding_errorlist(self):
|
||||
@python_2_unicode_compatible
|
||||
class DivErrorList(ErrorList):
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
|
||||
import datetime
|
||||
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.core.validators import RegexValidator
|
||||
from django.forms import *
|
||||
from django.http import QueryDict
|
||||
from django.template import Template, Context
|
||||
@@ -1792,6 +1793,75 @@ class FormsTestCase(TestCase):
|
||||
self.assertTrue(form.is_valid())
|
||||
self.assertEqual(form.cleaned_data, {'name' : 'fname lname'})
|
||||
|
||||
def test_multivalue_optional_subfields(self):
|
||||
class PhoneField(MultiValueField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
fields = (
|
||||
CharField(label='Country Code', validators=[
|
||||
RegexValidator(r'^\+\d{1,2}$', message='Enter a valid country code.')]),
|
||||
CharField(label='Phone Number'),
|
||||
CharField(label='Extension', error_messages={'incomplete': 'Enter an extension.'}),
|
||||
CharField(label='Label', required=False, help_text='E.g. home, work.'),
|
||||
)
|
||||
super(PhoneField, self).__init__(fields, *args, **kwargs)
|
||||
|
||||
def compress(self, data_list):
|
||||
if data_list:
|
||||
return '%s.%s ext. %s (label: %s)' % tuple(data_list)
|
||||
return None
|
||||
|
||||
# An empty value for any field will raise a `required` error on a
|
||||
# required `MultiValueField`.
|
||||
f = PhoneField()
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ['+61'])
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ['+61', '287654321', '123'])
|
||||
self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home']))
|
||||
self.assertRaisesMessage(ValidationError,
|
||||
"'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
|
||||
|
||||
# Empty values for fields will NOT raise a `required` error on an
|
||||
# optional `MultiValueField`
|
||||
f = PhoneField(required=False)
|
||||
self.assertEqual(None, f.clean(''))
|
||||
self.assertEqual(None, f.clean(None))
|
||||
self.assertEqual(None, f.clean([]))
|
||||
self.assertEqual('+61. ext. (label: )', f.clean(['+61']))
|
||||
self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
|
||||
self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home']))
|
||||
self.assertRaisesMessage(ValidationError,
|
||||
"'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
|
||||
|
||||
# For a required `MultiValueField` with `require_all_fields=False`, a
|
||||
# `required` error will only be raised if all fields are empty. Fields
|
||||
# can individually be required or optional. An empty value for any
|
||||
# required field will raise an `incomplete` error.
|
||||
f = PhoneField(require_all_fields=False)
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
|
||||
self.assertRaisesMessage(ValidationError, "'Enter a complete value.'", f.clean, ['+61'])
|
||||
self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
|
||||
six.assertRaisesRegex(self, ValidationError,
|
||||
"'Enter a complete value\.', u?'Enter an extension\.'", f.clean, ['', '', '', 'Home'])
|
||||
self.assertRaisesMessage(ValidationError,
|
||||
"'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
|
||||
|
||||
# For an optional `MultiValueField` with `require_all_fields=False`, we
|
||||
# don't get any `required` error but we still get `incomplete` errors.
|
||||
f = PhoneField(required=False, require_all_fields=False)
|
||||
self.assertEqual(None, f.clean(''))
|
||||
self.assertEqual(None, f.clean(None))
|
||||
self.assertEqual(None, f.clean([]))
|
||||
self.assertRaisesMessage(ValidationError, "'Enter a complete value.'", f.clean, ['+61'])
|
||||
self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123']))
|
||||
six.assertRaisesRegex(self, ValidationError,
|
||||
"'Enter a complete value\.', u?'Enter an extension\.'", f.clean, ['', '', '', 'Home'])
|
||||
self.assertRaisesMessage(ValidationError,
|
||||
"'Enter a valid country code.'", f.clean, ['61', '287654321', '123', 'Home'])
|
||||
|
||||
def test_custom_empty_values(self):
|
||||
"""
|
||||
Test that form fields can customize what is considered as an empty value
|
||||
@@ -1824,7 +1894,7 @@ class FormsTestCase(TestCase):
|
||||
# passing just one argument: overrides the field's label
|
||||
(('custom',), {}, '<label for="id_field">custom:</label>'),
|
||||
|
||||
# the overriden label is escaped
|
||||
# the overridden label is escaped
|
||||
(('custom&',), {}, '<label for="id_field">custom&:</label>'),
|
||||
((mark_safe('custom&'),), {}, '<label for="id_field">custom&:</label>'),
|
||||
|
||||
@@ -1870,3 +1940,13 @@ class FormsTestCase(TestCase):
|
||||
boundfield = SomeForm()['field']
|
||||
|
||||
self.assertHTMLEqual(boundfield.label_tag(), '<label for="id_field"></label>')
|
||||
|
||||
def test_label_tag_override(self):
|
||||
"""
|
||||
BoundField label_suffix (if provided) overrides Form label_suffix
|
||||
"""
|
||||
class SomeForm(Form):
|
||||
field = CharField()
|
||||
boundfield = SomeForm(label_suffix='!')['field']
|
||||
|
||||
self.assertHTMLEqual(boundfield.label_tag(label_suffix='$'), '<label for="id_field">Field$</label>')
|
||||
|
||||
@@ -849,6 +849,14 @@ beatle J R Ringo False""")
|
||||
w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
|
||||
self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />')
|
||||
|
||||
# Test needs_multipart_form=True if any widget needs it
|
||||
w = MyMultiWidget(widgets=(TextInput(), FileInput()))
|
||||
self.assertTrue(w.needs_multipart_form)
|
||||
|
||||
# Test needs_multipart_form=False if no widget needs it
|
||||
w = MyMultiWidget(widgets=(TextInput(), TextInput()))
|
||||
self.assertFalse(w.needs_multipart_form)
|
||||
|
||||
def test_splitdatetime(self):
|
||||
w = SplitDateTimeWidget()
|
||||
self.assertHTMLEqual(w.render('date', ''), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -10,8 +10,8 @@ from django.forms.models import ModelFormMetaclass
|
||||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
|
||||
from ..models import (ChoiceOptionModel, ChoiceFieldModel, FileModel, Group,
|
||||
BoundaryModel, Defaults, OptionalMultiChoiceModel)
|
||||
from ..models import (ChoiceModel, ChoiceOptionModel, ChoiceFieldModel,
|
||||
FileModel, Group, BoundaryModel, Defaults, OptionalMultiChoiceModel)
|
||||
|
||||
|
||||
class ChoiceFieldForm(ModelForm):
|
||||
@@ -34,6 +34,24 @@ class ChoiceFieldExclusionForm(ModelForm):
|
||||
model = ChoiceFieldModel
|
||||
|
||||
|
||||
class EmptyCharLabelChoiceForm(ModelForm):
|
||||
class Meta:
|
||||
model = ChoiceModel
|
||||
fields = ['name', 'choice']
|
||||
|
||||
|
||||
class EmptyIntegerLabelChoiceForm(ModelForm):
|
||||
class Meta:
|
||||
model = ChoiceModel
|
||||
fields = ['name', 'choice_integer']
|
||||
|
||||
|
||||
class EmptyCharLabelNoneChoiceForm(ModelForm):
|
||||
class Meta:
|
||||
model = ChoiceModel
|
||||
fields = ['name', 'choice_string_w_none']
|
||||
|
||||
|
||||
class FileForm(Form):
|
||||
file1 = FileField()
|
||||
|
||||
@@ -259,3 +277,78 @@ class ManyToManyExclusionTestCase(TestCase):
|
||||
self.assertEqual(form.instance.choice_int.pk, data['choice_int'])
|
||||
self.assertEqual(list(form.instance.multi_choice.all()), [opt2, opt3])
|
||||
self.assertEqual([obj.pk for obj in form.instance.multi_choice_int.all()], data['multi_choice_int'])
|
||||
|
||||
|
||||
class EmptyLabelTestCase(TestCase):
|
||||
def test_empty_field_char(self):
|
||||
f = EmptyCharLabelChoiceForm()
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
|
||||
<p><label for="id_choice">Choice:</label> <select id="id_choice" name="choice">
|
||||
<option value="" selected="selected">No Preference</option>
|
||||
<option value="f">Foo</option>
|
||||
<option value="b">Bar</option>
|
||||
</select></p>""")
|
||||
|
||||
def test_empty_field_char_none(self):
|
||||
f = EmptyCharLabelNoneChoiceForm()
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
|
||||
<p><label for="id_choice_string_w_none">Choice string w none:</label> <select id="id_choice_string_w_none" name="choice_string_w_none">
|
||||
<option value="" selected="selected">No Preference</option>
|
||||
<option value="f">Foo</option>
|
||||
<option value="b">Bar</option>
|
||||
</select></p>""")
|
||||
|
||||
def test_save_empty_label_forms(self):
|
||||
# Test that saving a form with a blank choice results in the expected
|
||||
# value being stored in the database.
|
||||
tests = [
|
||||
(EmptyCharLabelNoneChoiceForm, 'choice_string_w_none', None),
|
||||
(EmptyIntegerLabelChoiceForm, 'choice_integer', None),
|
||||
(EmptyCharLabelChoiceForm, 'choice', ''),
|
||||
]
|
||||
|
||||
for form, key, expected in tests:
|
||||
f = form({'name': 'some-key', key: ''})
|
||||
self.assertTrue(f.is_valid())
|
||||
m = f.save()
|
||||
self.assertEqual(expected, getattr(m, key))
|
||||
self.assertEqual('No Preference',
|
||||
getattr(m, 'get_{0}_display'.format(key))())
|
||||
|
||||
def test_empty_field_integer(self):
|
||||
f = EmptyIntegerLabelChoiceForm()
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
|
||||
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
|
||||
<option value="" selected="selected">No Preference</option>
|
||||
<option value="1">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
|
||||
def test_get_display_value_on_none(self):
|
||||
m = ChoiceModel.objects.create(name='test', choice='', choice_integer=None)
|
||||
self.assertEqual(None, m.choice_integer)
|
||||
self.assertEqual('No Preference', m.get_choice_integer_display())
|
||||
|
||||
def test_html_rendering_of_prepopulated_models(self):
|
||||
none_model = ChoiceModel(name='none-test', choice_integer=None)
|
||||
f = EmptyIntegerLabelChoiceForm(instance=none_model)
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="none-test"/></p>
|
||||
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
|
||||
<option value="" selected="selected">No Preference</option>
|
||||
<option value="1">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
|
||||
foo_model = ChoiceModel(name='foo-test', choice_integer=1)
|
||||
f = EmptyIntegerLabelChoiceForm(instance=foo_model)
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="foo-test"/></p>
|
||||
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer">
|
||||
<option value="">No Preference</option>
|
||||
<option value="1" selected="selected">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.contenttypes import generic
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
@@ -325,3 +325,23 @@ class GenericInlineModelAdminTest(TestCase):
|
||||
self.assertEqual(
|
||||
list(list(ma.get_formsets(request))[0]().forms[0].fields),
|
||||
['description', 'keywords', 'id', 'DELETE'])
|
||||
|
||||
def test_get_fieldsets(self):
|
||||
# Test that get_fieldsets is called when figuring out form fields.
|
||||
# Refs #18681.
|
||||
class MediaForm(ModelForm):
|
||||
class Meta:
|
||||
model = Media
|
||||
fields = '__all__'
|
||||
|
||||
class MediaInline(GenericTabularInline):
|
||||
form = MediaForm
|
||||
model = Media
|
||||
can_delete = False
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
return [(None, {'fields': ['url', 'description']})]
|
||||
|
||||
ma = MediaInline(Media, self.site)
|
||||
form = ma.get_formset(None).form
|
||||
self.assertEqual(form._meta.fields, ['url', 'description'])
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user