mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +00:00
newforms-admin: Merged to [6050]
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6051 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
bd01c6ee57
commit
976acdc774
1
AUTHORS
1
AUTHORS
@ -260,6 +260,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Vasiliy Stavenko <stavenko@gmail.com>
|
Vasiliy Stavenko <stavenko@gmail.com>
|
||||||
Thomas Steinacher <http://www.eggdrop.ch/>
|
Thomas Steinacher <http://www.eggdrop.ch/>
|
||||||
nowell strite
|
nowell strite
|
||||||
|
Thomas Stromberg <tstromberg@google.com>
|
||||||
Sundance
|
Sundance
|
||||||
SuperJared
|
SuperJared
|
||||||
Radek Švarz <http://www.svarz.cz/translate/>
|
Radek Švarz <http://www.svarz.cz/translate/>
|
||||||
|
@ -40,7 +40,7 @@ class CsrfMiddleware(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
if request.POST:
|
if request.method == 'POST':
|
||||||
try:
|
try:
|
||||||
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
|
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -45,7 +45,7 @@ PROVINCE_CHOICES = (
|
|||||||
('IM', 'Imperia'),
|
('IM', 'Imperia'),
|
||||||
('IS', 'Isernia'),
|
('IS', 'Isernia'),
|
||||||
('SP', 'La Spezia'),
|
('SP', 'La Spezia'),
|
||||||
('AQ', u'L’Acquila'),
|
('AQ', u'L’Aquila'),
|
||||||
('LT', 'Latina'),
|
('LT', 'Latina'),
|
||||||
('LE', 'Lecce'),
|
('LE', 'Lecce'),
|
||||||
('LC', 'Lecco'),
|
('LC', 'Lecco'),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management.color import color_style
|
from django.core.management.color import color_style
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
class CommandError(Exception):
|
class CommandError(Exception):
|
||||||
pass
|
pass
|
||||||
@ -44,7 +45,7 @@ class BaseCommand(object):
|
|||||||
sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e)))
|
sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e)))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def validate(self, app=None):
|
def validate(self, app=None, display_num_errors=False):
|
||||||
"""
|
"""
|
||||||
Validates the given app, raising CommandError for any errors.
|
Validates the given app, raising CommandError for any errors.
|
||||||
|
|
||||||
@ -61,6 +62,8 @@ class BaseCommand(object):
|
|||||||
s.seek(0)
|
s.seek(0)
|
||||||
error_text = s.read()
|
error_text = s.read()
|
||||||
raise CommandError("One or more models did not validate:\n%s" % error_text)
|
raise CommandError("One or more models did not validate:\n%s" % error_text)
|
||||||
|
if display_num_errors:
|
||||||
|
print "%s error%s found" % (num_errors, num_errors != 1 and 's' or '')
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -119,7 +122,6 @@ class NoArgsCommand(BaseCommand):
|
|||||||
|
|
||||||
def copy_helper(style, app_or_project, name, directory, other_name=''):
|
def copy_helper(style, app_or_project, name, directory, other_name=''):
|
||||||
import django
|
import django
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
||||||
@ -155,5 +157,15 @@ def copy_helper(style, app_or_project, name, directory, other_name=''):
|
|||||||
fp_new.close()
|
fp_new.close()
|
||||||
try:
|
try:
|
||||||
shutil.copymode(path_old, path_new)
|
shutil.copymode(path_old, path_new)
|
||||||
|
_make_writeable(path_new)
|
||||||
except OSError:
|
except OSError:
|
||||||
sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
|
sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
|
||||||
|
|
||||||
|
def _make_writeable(filename):
|
||||||
|
"Makes sure that the file is writeable. Useful if our source is read-only."
|
||||||
|
import stat
|
||||||
|
if not os.access(filename, os.W_OK):
|
||||||
|
st = os.stat(filename)
|
||||||
|
new_permissions = stat.S_IMODE(st.st_mode) | stat.S_IWUSR
|
||||||
|
os.chmod(filename, new_permissions)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import sys
|
|||||||
|
|
||||||
def color_style():
|
def color_style():
|
||||||
"Returns a Style object with the Django color scheme."
|
"Returns a Style object with the Django color scheme."
|
||||||
if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
|
if sys.platform == 'win32' or sys.platform == 'Pocket PC' or sys.platform.startswith('java') or not sys.stdout.isatty():
|
||||||
return no_style()
|
return no_style()
|
||||||
class dummy: pass
|
class dummy: pass
|
||||||
style = dummy()
|
style = dummy()
|
||||||
|
@ -37,7 +37,7 @@ class Command(BaseCommand):
|
|||||||
def inner_run():
|
def inner_run():
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
print "Validating models..."
|
print "Validating models..."
|
||||||
self.validate()
|
self.validate(display_num_errors=True)
|
||||||
print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)
|
print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)
|
||||||
print "Development server is running at http://%s:%s/" % (addr, port)
|
print "Development server is running at http://%s:%s/" % (addr, port)
|
||||||
print "Quit the server with %s." % quit_command
|
print "Quit the server with %s." % quit_command
|
||||||
|
@ -28,11 +28,6 @@ class Command(LabelCommand):
|
|||||||
# Create a random SECRET_KEY hash, and put it in the main settings.
|
# Create a random SECRET_KEY hash, and put it in the main settings.
|
||||||
main_settings_file = os.path.join(directory, project_name, 'settings.py')
|
main_settings_file = os.path.join(directory, project_name, 'settings.py')
|
||||||
settings_contents = open(main_settings_file, 'r').read()
|
settings_contents = open(main_settings_file, 'r').read()
|
||||||
|
|
||||||
# If settings.py was copied from a read-only source, make it writeable.
|
|
||||||
if not os.access(main_settings_file, os.W_OK):
|
|
||||||
os.chmod(main_settings_file, 0600)
|
|
||||||
|
|
||||||
fp = open(main_settings_file, 'w')
|
fp = open(main_settings_file, 'w')
|
||||||
secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
|
secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
|
||||||
settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
|
settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
|
||||||
|
@ -6,4 +6,4 @@ class Command(NoArgsCommand):
|
|||||||
requires_model_validation = False
|
requires_model_validation = False
|
||||||
|
|
||||||
def handle_noargs(self, **options):
|
def handle_noargs(self, **options):
|
||||||
self.validate()
|
self.validate(display_num_errors=True)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/).
|
SQLite3 backend for django.
|
||||||
|
|
||||||
|
Python 2.3 and 2.4 require pysqlite2 (http://pysqlite.org/).
|
||||||
|
|
||||||
|
Python 2.5 and later use the sqlite3 module in the standard library.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
|
from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
|
||||||
|
@ -355,8 +355,8 @@ def unordered_list(value):
|
|||||||
Recursively takes a self-nested list and returns an HTML unordered list --
|
Recursively takes a self-nested list and returns an HTML unordered list --
|
||||||
WITHOUT opening and closing <ul> tags.
|
WITHOUT opening and closing <ul> tags.
|
||||||
|
|
||||||
The list is assumed to be in the proper format. For example, if ``var`` contains
|
The list is assumed to be in the proper format. For example, if ``var``
|
||||||
``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
|
contains: ``['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']]``,
|
||||||
then ``{{ var|unordered_list }}`` would return::
|
then ``{{ var|unordered_list }}`` would return::
|
||||||
|
|
||||||
<li>States
|
<li>States
|
||||||
@ -371,14 +371,61 @@ def unordered_list(value):
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
"""
|
"""
|
||||||
def _helper(value, tabs):
|
def convert_old_style_list(list_):
|
||||||
|
"""
|
||||||
|
Converts old style lists to the new easier to understand format.
|
||||||
|
|
||||||
|
The old list format looked like:
|
||||||
|
['Item 1', [['Item 1.1', []], ['Item 1.2', []]]
|
||||||
|
|
||||||
|
And it is converted to:
|
||||||
|
['Item 1', ['Item 1.1', 'Item 1.2]]
|
||||||
|
"""
|
||||||
|
if not isinstance(list_, (tuple, list)) or len(list_) != 2:
|
||||||
|
return list_, False
|
||||||
|
first_item, second_item = list_
|
||||||
|
if second_item == []:
|
||||||
|
return [first_item], True
|
||||||
|
old_style_list = True
|
||||||
|
new_second_item = []
|
||||||
|
for sublist in second_item:
|
||||||
|
item, old_style_list = convert_old_style_list(sublist)
|
||||||
|
if not old_style_list:
|
||||||
|
break
|
||||||
|
new_second_item.extend(item)
|
||||||
|
if old_style_list:
|
||||||
|
second_item = new_second_item
|
||||||
|
return [first_item, second_item], old_style_list
|
||||||
|
def _helper(list_, tabs=1):
|
||||||
indent = u'\t' * tabs
|
indent = u'\t' * tabs
|
||||||
if value[1]:
|
output = []
|
||||||
return u'%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, force_unicode(value[0]), indent,
|
|
||||||
u'\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
|
list_length = len(list_)
|
||||||
else:
|
i = 0
|
||||||
return u'%s<li>%s</li>' % (indent, force_unicode(value[0]))
|
while i < list_length:
|
||||||
return _helper(value, 1)
|
title = list_[i]
|
||||||
|
sublist = ''
|
||||||
|
sublist_item = None
|
||||||
|
if isinstance(title, (list, tuple)):
|
||||||
|
sublist_item = title
|
||||||
|
title = ''
|
||||||
|
elif i < list_length - 1:
|
||||||
|
next_item = list_[i+1]
|
||||||
|
if next_item and isinstance(next_item, (list, tuple)):
|
||||||
|
# The next item is a sub-list.
|
||||||
|
sublist_item = next_item
|
||||||
|
# We've processed the next item now too.
|
||||||
|
i += 1
|
||||||
|
if sublist_item:
|
||||||
|
sublist = _helper(sublist_item, tabs+1)
|
||||||
|
sublist = '\n%s<ul>\n%s\n%s</ul>\n%s' % (indent, sublist,
|
||||||
|
indent, indent)
|
||||||
|
output.append('%s<li>%s%s</li>' % (indent, force_unicode(title),
|
||||||
|
sublist))
|
||||||
|
i += 1
|
||||||
|
return '\n'.join(output)
|
||||||
|
value, converted = convert_old_style_list(value)
|
||||||
|
return _helper(value)
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# INTEGERS #
|
# INTEGERS #
|
||||||
|
@ -11,6 +11,7 @@ from django.core.handlers.wsgi import WSGIRequest
|
|||||||
from django.core.signals import got_request_exception
|
from django.core.signals import got_request_exception
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.http import SimpleCookie, HttpRequest
|
from django.http import SimpleCookie, HttpRequest
|
||||||
|
from django.template import TemplateDoesNotExist
|
||||||
from django.test import signals
|
from django.test import signals
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
@ -165,7 +166,25 @@ class Client:
|
|||||||
# Capture exceptions created by the handler
|
# Capture exceptions created by the handler
|
||||||
dispatcher.connect(self.store_exc_info, signal=got_request_exception)
|
dispatcher.connect(self.store_exc_info, signal=got_request_exception)
|
||||||
|
|
||||||
response = self.handler(environ)
|
try:
|
||||||
|
response = self.handler(environ)
|
||||||
|
except TemplateDoesNotExist, e:
|
||||||
|
# If the view raises an exception, Django will attempt to show
|
||||||
|
# the 500.html template. If that template is not available,
|
||||||
|
# we should ignore the error in favor of re-raising the
|
||||||
|
# underlying exception that caused the 500 error. Any other
|
||||||
|
# template found to be missing during view error handling
|
||||||
|
# should be reported as-is.
|
||||||
|
if e.args != ('500.html',):
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Look for a signalled exception and reraise it
|
||||||
|
if self.exc_info:
|
||||||
|
raise self.exc_info[1], None, self.exc_info[2]
|
||||||
|
|
||||||
|
# Save the client and request that stimulated the response
|
||||||
|
response.client = self
|
||||||
|
response.request = request
|
||||||
|
|
||||||
# Add any rendered template detail to the response
|
# Add any rendered template detail to the response
|
||||||
# If there was only one template rendered (the most likely case),
|
# If there was only one template rendered (the most likely case),
|
||||||
@ -179,10 +198,6 @@ class Client:
|
|||||||
else:
|
else:
|
||||||
setattr(response, detail, None)
|
setattr(response, detail, None)
|
||||||
|
|
||||||
# Look for a signalled exception and reraise it
|
|
||||||
if self.exc_info:
|
|
||||||
raise self.exc_info[1], None, self.exc_info[2]
|
|
||||||
|
|
||||||
# Update persistent cookie data
|
# Update persistent cookie data
|
||||||
if response.cookies:
|
if response.cookies:
|
||||||
self.cookies.update(response.cookies)
|
self.cookies.update(response.cookies)
|
||||||
|
@ -1,14 +1,28 @@
|
|||||||
import re, unittest
|
import re
|
||||||
from urlparse import urlparse
|
import unittest
|
||||||
|
from urlparse import urlsplit
|
||||||
|
|
||||||
|
from django.http import QueryDict
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.db.models import get_apps
|
|
||||||
from django.test import _doctest as doctest
|
from django.test import _doctest as doctest
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
|
|
||||||
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
|
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
|
||||||
|
|
||||||
|
def to_list(value):
|
||||||
|
"""
|
||||||
|
Puts value into a list if it's not already one.
|
||||||
|
Returns an empty list if value is None.
|
||||||
|
"""
|
||||||
|
if value is None:
|
||||||
|
value = []
|
||||||
|
elif not isinstance(value, list):
|
||||||
|
value = [value]
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class OutputChecker(doctest.OutputChecker):
|
class OutputChecker(doctest.OutputChecker):
|
||||||
def check_output(self, want, got, optionflags):
|
def check_output(self, want, got, optionflags):
|
||||||
ok = doctest.OutputChecker.check_output(self, want, got, optionflags)
|
ok = doctest.OutputChecker.check_output(self, want, got, optionflags)
|
||||||
@ -20,28 +34,27 @@ class OutputChecker(doctest.OutputChecker):
|
|||||||
if not ok:
|
if not ok:
|
||||||
return normalize_long_ints(want) == normalize_long_ints(got)
|
return normalize_long_ints(want) == normalize_long_ints(got)
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
class DocTestRunner(doctest.DocTestRunner):
|
class DocTestRunner(doctest.DocTestRunner):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
doctest.DocTestRunner.__init__(self, *args, **kwargs)
|
doctest.DocTestRunner.__init__(self, *args, **kwargs)
|
||||||
self.optionflags = doctest.ELLIPSIS
|
self.optionflags = doctest.ELLIPSIS
|
||||||
|
|
||||||
def report_unexpected_exception(self, out, test, example, exc_info):
|
def report_unexpected_exception(self, out, test, example, exc_info):
|
||||||
doctest.DocTestRunner.report_unexpected_exception(self,out,test,example,exc_info)
|
doctest.DocTestRunner.report_unexpected_exception(self, out, test,
|
||||||
|
example, exc_info)
|
||||||
# Rollback, in case of database errors. Otherwise they'd have
|
# Rollback, in case of database errors. Otherwise they'd have
|
||||||
# side effects on other tests.
|
# side effects on other tests.
|
||||||
from django.db import transaction
|
|
||||||
transaction.rollback_unless_managed()
|
transaction.rollback_unless_managed()
|
||||||
|
|
||||||
class TestCase(unittest.TestCase):
|
class TestCase(unittest.TestCase):
|
||||||
def _pre_setup(self):
|
def _pre_setup(self):
|
||||||
"""Perform any pre-test setup. This includes:
|
"""Performs any pre-test setup. This includes:
|
||||||
|
|
||||||
* If the Test Case class has a 'fixtures' member, clearing the
|
* If the Test Case class has a 'fixtures' member, clearing the
|
||||||
database and installing the named fixtures at the start of each test.
|
database and installing the named fixtures at the start of each
|
||||||
|
test.
|
||||||
* Clearing the mail test outbox.
|
* Clearing the mail test outbox.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
call_command('flush', verbosity=0, interactive=False)
|
call_command('flush', verbosity=0, interactive=False)
|
||||||
if hasattr(self, 'fixtures'):
|
if hasattr(self, 'fixtures'):
|
||||||
@ -60,97 +73,120 @@ class TestCase(unittest.TestCase):
|
|||||||
self._pre_setup()
|
self._pre_setup()
|
||||||
super(TestCase, self).__call__(result)
|
super(TestCase, self).__call__(result)
|
||||||
|
|
||||||
def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200):
|
def assertRedirects(self, response, expected_url, status_code=302,
|
||||||
"""Assert that a response redirected to a specific URL, and that the
|
target_status_code=200):
|
||||||
|
"""Asserts that a response redirected to a specific URL, and that the
|
||||||
redirect URL can be loaded.
|
redirect URL can be loaded.
|
||||||
|
|
||||||
"""
|
Note that assertRedirects won't work for external links since it uses
|
||||||
self.assertEqual(response.status_code, status_code,
|
TestClient to do a request.
|
||||||
"Response didn't redirect as expected: Response code was %d (expected %d)" %
|
|
||||||
(response.status_code, status_code))
|
|
||||||
scheme, netloc, path, params, query, fragment = urlparse(response['Location'])
|
|
||||||
self.assertEqual(path, expected_path,
|
|
||||||
"Response redirected to '%s', expected '%s'" % (path, expected_path))
|
|
||||||
redirect_response = self.client.get(path)
|
|
||||||
self.assertEqual(redirect_response.status_code, target_status_code,
|
|
||||||
"Couldn't retrieve redirection page '%s': response code was %d (expected %d)" %
|
|
||||||
(path, redirect_response.status_code, target_status_code))
|
|
||||||
|
|
||||||
def assertContains(self, response, text, count=None, status_code=200):
|
|
||||||
"""Assert that a response indicates that a page was retreived successfully,
|
|
||||||
(i.e., the HTTP status code was as expected), and that ``text`` occurs ``count``
|
|
||||||
times in the content of the response. If ``count`` is None, the count doesn't
|
|
||||||
matter - the assertion is true if the text occurs at least once in the response.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.assertEqual(response.status_code, status_code,
|
self.assertEqual(response.status_code, status_code,
|
||||||
"Couldn't retrieve page: Response code was %d (expected %d)'" %
|
("Response didn't redirect as expected: Response code was %d"
|
||||||
|
" (expected %d)" % (response.status_code, status_code)))
|
||||||
|
scheme, netloc, path, query, fragment = urlsplit(response['Location'])
|
||||||
|
url = path
|
||||||
|
if query:
|
||||||
|
url += '?' + query
|
||||||
|
if fragment:
|
||||||
|
url += '#' + fragment
|
||||||
|
self.assertEqual(url, expected_url,
|
||||||
|
"Response redirected to '%s', expected '%s'" % (url, expected_url))
|
||||||
|
|
||||||
|
# Get the redirection page, using the same client that was used
|
||||||
|
# to obtain the original response.
|
||||||
|
redirect_response = response.client.get(path, QueryDict(query))
|
||||||
|
self.assertEqual(redirect_response.status_code, target_status_code,
|
||||||
|
("Couldn't retrieve redirection page '%s': response code was %d"
|
||||||
|
" (expected %d)") %
|
||||||
|
(path, redirect_response.status_code, target_status_code))
|
||||||
|
|
||||||
|
def assertContains(self, response, text, count=None, status_code=200):
|
||||||
|
"""
|
||||||
|
Asserts that a response indicates that a page was retreived
|
||||||
|
successfully, (i.e., the HTTP status code was as expected), and that
|
||||||
|
``text`` occurs ``count`` times in the content of the response.
|
||||||
|
If ``count`` is None, the count doesn't matter - the assertion is true
|
||||||
|
if the text occurs at least once in the response.
|
||||||
|
"""
|
||||||
|
self.assertEqual(response.status_code, status_code,
|
||||||
|
"Couldn't retrieve page: Response code was %d (expected %d)'" %
|
||||||
(response.status_code, status_code))
|
(response.status_code, status_code))
|
||||||
real_count = response.content.count(text)
|
real_count = response.content.count(text)
|
||||||
if count is not None:
|
if count is not None:
|
||||||
self.assertEqual(real_count, count,
|
self.assertEqual(real_count, count,
|
||||||
"Found %d instances of '%s' in response (expected %d)" % (real_count, text, count))
|
"Found %d instances of '%s' in response (expected %d)" %
|
||||||
|
(real_count, text, count))
|
||||||
else:
|
else:
|
||||||
self.failUnless(real_count != 0, "Couldn't find '%s' in response" % text)
|
self.failUnless(real_count != 0,
|
||||||
|
"Couldn't find '%s' in response" % text)
|
||||||
|
|
||||||
def assertFormError(self, response, form, field, errors):
|
def assertFormError(self, response, form, field, errors):
|
||||||
"Assert that a form used to render the response has a specific field error"
|
"""
|
||||||
if not response.context:
|
Asserts that a form used to render the response has a specific field
|
||||||
self.fail('Response did not use any contexts to render the response')
|
error.
|
||||||
|
"""
|
||||||
|
# Put context(s) into a list to simplify processing.
|
||||||
|
contexts = to_list(response.context)
|
||||||
|
if not contexts:
|
||||||
|
self.fail('Response did not use any contexts to render the'
|
||||||
|
' response')
|
||||||
|
|
||||||
# If there is a single context, put it into a list to simplify processing
|
# Put error(s) into a list to simplify processing.
|
||||||
if not isinstance(response.context, list):
|
errors = to_list(errors)
|
||||||
contexts = [response.context]
|
|
||||||
else:
|
|
||||||
contexts = response.context
|
|
||||||
|
|
||||||
# If a single error string is provided, make it a list to simplify processing
|
|
||||||
if not isinstance(errors, list):
|
|
||||||
errors = [errors]
|
|
||||||
|
|
||||||
# Search all contexts for the error.
|
# Search all contexts for the error.
|
||||||
found_form = False
|
found_form = False
|
||||||
for i,context in enumerate(contexts):
|
for i,context in enumerate(contexts):
|
||||||
if form in context:
|
if form not in context:
|
||||||
found_form = True
|
continue
|
||||||
for err in errors:
|
found_form = True
|
||||||
if field:
|
for err in errors:
|
||||||
if field in context[form].errors:
|
if field:
|
||||||
self.failUnless(err in context[form].errors[field],
|
if field in context[form].errors:
|
||||||
"The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %
|
field_errors = context[form].errors[field]
|
||||||
(field, form, i, err, list(context[form].errors[field])))
|
self.failUnless(err in field_errors,
|
||||||
elif field in context[form].fields:
|
"The field '%s' on form '%s' in"
|
||||||
self.fail("The field '%s' on form '%s' in context %d contains no errors" %
|
" context %d does not contain the"
|
||||||
(field, form, i))
|
" error '%s' (actual errors: %s)" %
|
||||||
else:
|
(field, form, i, err,
|
||||||
self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field))
|
list(field_errors)))
|
||||||
|
elif field in context[form].fields:
|
||||||
|
self.fail("The field '%s' on form '%s' in context %d"
|
||||||
|
" contains no errors" % (field, form, i))
|
||||||
else:
|
else:
|
||||||
self.failUnless(err in context[form].non_field_errors(),
|
self.fail("The form '%s' in context %d does not"
|
||||||
"The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %
|
" contain the field '%s'" %
|
||||||
(form, i, err, list(context[form].non_field_errors())))
|
(form, i, field))
|
||||||
|
else:
|
||||||
|
non_field_errors = context[form].non_field_errors()
|
||||||
|
self.failUnless(err in non_field_errors,
|
||||||
|
"The form '%s' in context %d does not contain the"
|
||||||
|
" non-field error '%s' (actual errors: %s)" %
|
||||||
|
(form, i, err, non_field_errors))
|
||||||
if not found_form:
|
if not found_form:
|
||||||
self.fail("The form '%s' was not used to render the response" % form)
|
self.fail("The form '%s' was not used to render the response" %
|
||||||
|
form)
|
||||||
|
|
||||||
def assertTemplateUsed(self, response, template_name):
|
def assertTemplateUsed(self, response, template_name):
|
||||||
"Assert that the template with the provided name was used in rendering the response"
|
"""
|
||||||
if isinstance(response.template, list):
|
Asserts that the template with the provided name was used in rendering
|
||||||
template_names = [t.name for t in response.template]
|
the response.
|
||||||
self.failUnless(template_name in template_names,
|
"""
|
||||||
u"Template '%s' was not one of the templates used to render the response. Templates used: %s" %
|
template_names = [t.name for t in to_list(response.template)]
|
||||||
(template_name, u', '.join(template_names)))
|
if not template_names:
|
||||||
elif response.template:
|
|
||||||
self.assertEqual(template_name, response.template.name,
|
|
||||||
u"Template '%s' was not used to render the response. Actual template was '%s'" %
|
|
||||||
(template_name, response.template.name))
|
|
||||||
else:
|
|
||||||
self.fail('No templates used to render the response')
|
self.fail('No templates used to render the response')
|
||||||
|
self.failUnless(template_name in template_names,
|
||||||
|
(u"Template '%s' was not a template used to render the response."
|
||||||
|
u" Actual template(s) used: %s") % (template_name,
|
||||||
|
u', '.join(template_names)))
|
||||||
|
|
||||||
def assertTemplateNotUsed(self, response, template_name):
|
def assertTemplateNotUsed(self, response, template_name):
|
||||||
"Assert that the template with the provided name was NOT used in rendering the response"
|
"""
|
||||||
if isinstance(response.template, list):
|
Asserts that the template with the provided name was NOT used in
|
||||||
self.failIf(template_name in [t.name for t in response.template],
|
rendering the response.
|
||||||
u"Template '%s' was used unexpectedly in rendering the response" % template_name)
|
"""
|
||||||
elif response.template:
|
template_names = [t.name for t in to_list(response.template)]
|
||||||
self.assertNotEqual(template_name, response.template.name,
|
self.failIf(template_name in template_names,
|
||||||
u"Template '%s' was used unexpectedly in rendering the response" % template_name)
|
(u"Template '%s' was used unexpectedly in rendering the"
|
||||||
|
u" response") % template_name)
|
||||||
|
@ -190,7 +190,7 @@ function that comes with Django::
|
|||||||
>>> from django.contrib.auth.models import User
|
>>> from django.contrib.auth.models import User
|
||||||
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
|
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
|
||||||
|
|
||||||
# At this point, user is a User object ready to be saved
|
# At this point, user is a User object that has already been saved
|
||||||
# to the database. You can continue to change its attributes
|
# to the database. You can continue to change its attributes
|
||||||
# if you want to change other fields.
|
# if you want to change other fields.
|
||||||
>>> user.is_staff = True
|
>>> user.is_staff = True
|
||||||
|
@ -176,9 +176,11 @@ just implements the cache interface without doing anything.
|
|||||||
|
|
||||||
This is useful if you have a production site that uses heavy-duty caching in
|
This is useful if you have a production site that uses heavy-duty caching in
|
||||||
various places but a development/test environment on which you don't want to
|
various places but a development/test environment on which you don't want to
|
||||||
cache. In that case, set ``CACHE_BACKEND`` to ``"dummy:///"`` in the settings
|
cache. As a result, your development environment won't use caching and your
|
||||||
file for your development environment. As a result, your development
|
production environment still will. To activate dummy caching, set
|
||||||
environment won't use caching and your production environment still will.
|
``CACHE_BACKEND`` like so::
|
||||||
|
|
||||||
|
CACHE_BACKEND = 'dummy:///'
|
||||||
|
|
||||||
CACHE_BACKEND arguments
|
CACHE_BACKEND arguments
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -160,7 +160,7 @@ When you save an object, Django performs the following steps:
|
|||||||
is used to provide notification that an object has been successfully
|
is used to provide notification that an object has been successfully
|
||||||
saved. (These signals are not yet documented.)
|
saved. (These signals are not yet documented.)
|
||||||
|
|
||||||
Raw Saves
|
Raw saves
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
@ -15,6 +15,18 @@ repository.
|
|||||||
|
|
||||||
.. _installing the development version: ../install/#installing-the-development-version
|
.. _installing the development version: ../install/#installing-the-development-version
|
||||||
|
|
||||||
|
FreeBSD
|
||||||
|
=======
|
||||||
|
|
||||||
|
The `FreeBSD`_ ports system offers both Django 0.96 (`py-django`_) and a more
|
||||||
|
recent, but not current, version based on Django's trunk (`py-django-devel`_).
|
||||||
|
These are installed in the normal FreeBSD way; for Django 0.96, for example, type:
|
||||||
|
``cd /usr/ports/www/py-django && sudo make install clean``.
|
||||||
|
|
||||||
|
.. _FreeBSD: http://www.freebsd.org/
|
||||||
|
.. _py-django: http://www.freebsd.org/cgi/cvsweb.cgi/ports/www/py-django/
|
||||||
|
.. _py-django-devel: http://www.freebsd.org/cgi/cvsweb.cgi/ports/www/py-django-devel/
|
||||||
|
|
||||||
Linux distributions
|
Linux distributions
|
||||||
===================
|
===================
|
||||||
|
|
||||||
@ -33,17 +45,6 @@ plan to use with Django.
|
|||||||
.. _Debian GNU/Linux: http://www.debian.org/
|
.. _Debian GNU/Linux: http://www.debian.org/
|
||||||
.. _packaged version of Django: http://packages.debian.org/stable/python/python-django
|
.. _packaged version of Django: http://packages.debian.org/stable/python/python-django
|
||||||
|
|
||||||
Ubuntu
|
|
||||||
------
|
|
||||||
|
|
||||||
The Debian ``python-django`` package is also available for `Ubuntu Linux`_, in
|
|
||||||
the "universe" repository for Ubuntu 7.04 ("Feisty Fawn"). The `current Ubuntu
|
|
||||||
package`_ is also based on Django 0.95.1 and can be installed in the same
|
|
||||||
fashion as for Debian.
|
|
||||||
|
|
||||||
.. _Ubuntu Linux: http://www.ubuntu.com/
|
|
||||||
.. _current Ubuntu package: http://packages.ubuntu.com/feisty/python/python-django
|
|
||||||
|
|
||||||
Fedora
|
Fedora
|
||||||
------
|
------
|
||||||
|
|
||||||
@ -65,6 +66,18 @@ The `current Gentoo build`_ can be installed by typing ``emerge django``.
|
|||||||
.. _Gentoo Linux: http://www.gentoo.org/
|
.. _Gentoo Linux: http://www.gentoo.org/
|
||||||
.. _current Gentoo build: http://packages.gentoo.org/packages/?category=dev-python;name=django
|
.. _current Gentoo build: http://packages.gentoo.org/packages/?category=dev-python;name=django
|
||||||
|
|
||||||
|
Ubuntu
|
||||||
|
------
|
||||||
|
|
||||||
|
The Debian ``python-django`` package is also available for `Ubuntu Linux`_, in
|
||||||
|
the "universe" repository for Ubuntu 7.04 ("Feisty Fawn"). The `current Ubuntu
|
||||||
|
package`_ is also based on Django 0.95.1 and can be installed in the same
|
||||||
|
fashion as for Debian.
|
||||||
|
|
||||||
|
.. _Ubuntu Linux: http://www.ubuntu.com/
|
||||||
|
.. _current Ubuntu package: http://packages.ubuntu.com/feisty/python/python-django
|
||||||
|
|
||||||
|
|
||||||
Mac OS X
|
Mac OS X
|
||||||
========
|
========
|
||||||
|
|
||||||
|
@ -479,6 +479,9 @@ This is useful in a number of ways:
|
|||||||
Note that this server can only run on the default port on localhost; it does
|
Note that this server can only run on the default port on localhost; it does
|
||||||
not yet accept a ``host`` or ``port`` parameter.
|
not yet accept a ``host`` or ``port`` parameter.
|
||||||
|
|
||||||
|
Also note that it does *not* automatically detect changes to your Python source
|
||||||
|
code (as ``runserver`` does). It does, however, detect changes to templates.
|
||||||
|
|
||||||
.. _unit tests: ../testing/
|
.. _unit tests: ../testing/
|
||||||
|
|
||||||
validate
|
validate
|
||||||
|
@ -262,7 +262,8 @@ else. This is done using the PythonImport_ directive to mod_python. You need
|
|||||||
to ensure that you have specified the ``PythonInterpreter`` directive to
|
to ensure that you have specified the ``PythonInterpreter`` directive to
|
||||||
mod_python as described above__ (you need to do this even if you aren't
|
mod_python as described above__ (you need to do this even if you aren't
|
||||||
serving multiple installations in this case). Then add the ``PythonImport``
|
serving multiple installations in this case). Then add the ``PythonImport``
|
||||||
line inside the ``Location`` or ``VirtualHost`` section. For example::
|
line in the main server configuration (i.e., outside the ``Location`` or
|
||||||
|
``VirtualHost`` sections). For example::
|
||||||
|
|
||||||
PythonInterpreter my_django
|
PythonInterpreter my_django
|
||||||
PythonImport /path/to/my/project/file.py my_django
|
PythonImport /path/to/my/project/file.py my_django
|
||||||
|
@ -1301,9 +1301,14 @@ unordered_list
|
|||||||
Recursively takes a self-nested list and returns an HTML unordered list --
|
Recursively takes a self-nested list and returns an HTML unordered list --
|
||||||
WITHOUT opening and closing <ul> tags.
|
WITHOUT opening and closing <ul> tags.
|
||||||
|
|
||||||
|
**Changed in Django development version**
|
||||||
|
|
||||||
|
The format accepted by ``unordered_list`` has changed to an easier to
|
||||||
|
understand format.
|
||||||
|
|
||||||
The list is assumed to be in the proper format. For example, if ``var`` contains
|
The list is assumed to be in the proper format. For example, if ``var`` contains
|
||||||
``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
|
``['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']]``, then
|
||||||
then ``{{ var|unordered_list }}`` would return::
|
``{{ var|unordered_list }}`` would return::
|
||||||
|
|
||||||
<li>States
|
<li>States
|
||||||
<ul>
|
<ul>
|
||||||
@ -1317,6 +1322,9 @@ then ``{{ var|unordered_list }}`` would return::
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
Note: the previous more restrictive and verbose format is still supported:
|
||||||
|
``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
|
||||||
|
|
||||||
upper
|
upper
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
@ -577,13 +577,25 @@ Specifically, a ``Response`` object has the following attributes:
|
|||||||
=============== ==========================================================
|
=============== ==========================================================
|
||||||
Attribute Description
|
Attribute Description
|
||||||
=============== ==========================================================
|
=============== ==========================================================
|
||||||
``status_code`` The HTTP status of the response, as an integer. See
|
``client`` The test client that was used to make the request that
|
||||||
RFC2616_ for a full list of HTTP status codes.
|
resulted in the response.
|
||||||
|
|
||||||
``content`` The body of the response, as a string. This is the final
|
``content`` The body of the response, as a string. This is the final
|
||||||
page content as rendered by the view, or any error
|
page content as rendered by the view, or any error
|
||||||
message (such as the URL for a 302 redirect).
|
message (such as the URL for a 302 redirect).
|
||||||
|
|
||||||
|
``context`` The template ``Context`` instance that was used to render
|
||||||
|
the template that produced the response content.
|
||||||
|
|
||||||
|
If the rendered page used multiple templates, then
|
||||||
|
``context`` will be a list of ``Context``
|
||||||
|
objects, in the order in which they were rendered.
|
||||||
|
|
||||||
|
``request`` The request data that stimulated the response.
|
||||||
|
|
||||||
|
``status_code`` The HTTP status of the response, as an integer. See
|
||||||
|
RFC2616_ for a full list of HTTP status codes.
|
||||||
|
|
||||||
``template`` The ``Template`` instance that was used to render the
|
``template`` The ``Template`` instance that was used to render the
|
||||||
final content. Use ``template.name`` to get the
|
final content. Use ``template.name`` to get the
|
||||||
template's file name, if the template was loaded from a
|
template's file name, if the template was loaded from a
|
||||||
@ -594,13 +606,6 @@ Specifically, a ``Response`` object has the following attributes:
|
|||||||
using `template inheritance`_ -- then ``template`` will
|
using `template inheritance`_ -- then ``template`` will
|
||||||
be a list of ``Template`` instances, in the order in
|
be a list of ``Template`` instances, in the order in
|
||||||
which they were rendered.
|
which they were rendered.
|
||||||
|
|
||||||
``context`` The template ``Context`` instance that was used to render
|
|
||||||
the template that produced the response content.
|
|
||||||
|
|
||||||
As with ``template``, if the rendered page used multiple
|
|
||||||
templates, then ``context`` will be a list of ``Context``
|
|
||||||
objects, in the order in which they were rendered.
|
|
||||||
=============== ==========================================================
|
=============== ==========================================================
|
||||||
|
|
||||||
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
@ -826,10 +831,10 @@ useful for testing Web applications:
|
|||||||
Asserts that the template with the given name was *not* used in rendering
|
Asserts that the template with the given name was *not* used in rendering
|
||||||
the response.
|
the response.
|
||||||
|
|
||||||
``assertRedirects(response, expected_path, status_code=302, target_status_code=200)``
|
``assertRedirects(response, expected_url, status_code=302, target_status_code=200)``
|
||||||
Asserts that the response return a ``status_code`` redirect status,
|
Asserts that the response return a ``status_code`` redirect status,
|
||||||
it redirected to ``expected_path`` and the subsequent page was received with
|
it redirected to ``expected_url`` (including any GET data), and the subsequent
|
||||||
``target_status_code``.
|
page was received with ``target_status_code``.
|
||||||
|
|
||||||
``assertTemplateUsed(response, template_name)``
|
``assertTemplateUsed(response, template_name)``
|
||||||
Asserts that the template with the given name was used in rendering the
|
Asserts that the template with the given name was used in rendering the
|
||||||
|
@ -259,7 +259,7 @@ These concepts are represented by simple Python classes. Edit the
|
|||||||
choice = models.CharField(max_length=200)
|
choice = models.CharField(max_length=200)
|
||||||
votes = models.IntegerField()
|
votes = models.IntegerField()
|
||||||
|
|
||||||
.. adminition:: Errors about ``max_length``
|
.. admonition:: Errors about ``max_length``
|
||||||
|
|
||||||
If Django gives you an error message saying that ``max_length`` is
|
If Django gives you an error message saying that ``max_length`` is
|
||||||
not a valid argument, you're most likely using an old version of
|
not a valid argument, you're most likely using an old version of
|
||||||
@ -383,7 +383,7 @@ Note the following:
|
|||||||
the SQL to the database.
|
the SQL to the database.
|
||||||
|
|
||||||
If you're interested, also run the following commands:
|
If you're interested, also run the following commands:
|
||||||
* ``python manage.py validate polls`` -- Checks for any errors in the
|
* ``python manage.py validate`` -- Checks for any errors in the
|
||||||
construction of your models.
|
construction of your models.
|
||||||
|
|
||||||
* ``python manage.py sqlcustom polls`` -- Outputs any custom SQL statements
|
* ``python manage.py sqlcustom polls`` -- Outputs any custom SQL statements
|
||||||
|
@ -86,6 +86,13 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Check that the response was a 302 (redirect)
|
# Check that the response was a 302 (redirect)
|
||||||
self.assertRedirects(response, '/test_client/get_view/')
|
self.assertRedirects(response, '/test_client/get_view/')
|
||||||
|
|
||||||
|
def test_redirect_with_query(self):
|
||||||
|
"GET a URL that redirects with given GET parameters"
|
||||||
|
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
|
||||||
|
|
||||||
|
# Check if parameters are intact
|
||||||
|
self.assertRedirects(response, '/test_client/get_view/?var=value')
|
||||||
|
|
||||||
def test_permanent_redirect(self):
|
def test_permanent_redirect(self):
|
||||||
"GET a URL that redirects permanently elsewhere"
|
"GET a URL that redirects permanently elsewhere"
|
||||||
@ -224,10 +231,11 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Get the page without logging in. Should result in 302.
|
# Get the page without logging in. Should result in 302.
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
self.assertRedirects(response, '/accounts/login/')
|
self.assertRedirects(response, '/accounts/login/?next=/test_client/login_protected_view/')
|
||||||
|
|
||||||
# Log in
|
# Log in
|
||||||
self.client.login(username='testclient', password='password')
|
login = self.client.login(username='testclient', password='password')
|
||||||
|
self.assertTrue(login, 'Could not log in')
|
||||||
|
|
||||||
# Request a page that requires a login
|
# Request a page that requires a login
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
@ -261,7 +269,7 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Request a page that requires a login
|
# Request a page that requires a login
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
self.assertRedirects(response, '/accounts/login/')
|
self.assertRedirects(response, '/accounts/login/?next=/test_client/login_protected_view/')
|
||||||
|
|
||||||
def test_session_modifying_view(self):
|
def test_session_modifying_view(self):
|
||||||
"Request a page that modifies the session"
|
"Request a page that modifies the session"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
|
|
||||||
from django.core.mail import EmailMessage, SMTPConnection
|
from django.core.mail import EmailMessage, SMTPConnection
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
|
||||||
@ -11,7 +12,7 @@ def get_view(request):
|
|||||||
"A simple view that expects a GET request, and returns a rendered template"
|
"A simple view that expects a GET request, and returns a rendered template"
|
||||||
t = Template('This is a test. {{ var }} is the value.', name='GET Template')
|
t = Template('This is a test. {{ var }} is the value.', name='GET Template')
|
||||||
c = Context({'var': request.GET.get('var', 42)})
|
c = Context({'var': request.GET.get('var', 42)})
|
||||||
|
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def post_view(request):
|
def post_view(request):
|
||||||
@ -28,9 +29,9 @@ def post_view(request):
|
|||||||
else:
|
else:
|
||||||
t = Template('Viewing GET page.', name='Empty GET Template')
|
t = Template('Viewing GET page.', name='Empty GET Template')
|
||||||
c = Context()
|
c = Context()
|
||||||
|
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def raw_post_view(request):
|
def raw_post_view(request):
|
||||||
"""A view which expects raw XML to be posted and returns content extracted
|
"""A view which expects raw XML to be posted and returns content extracted
|
||||||
from the XML"""
|
from the XML"""
|
||||||
@ -48,7 +49,12 @@ def raw_post_view(request):
|
|||||||
|
|
||||||
def redirect_view(request):
|
def redirect_view(request):
|
||||||
"A view that redirects all requests to the GET view"
|
"A view that redirects all requests to the GET view"
|
||||||
return HttpResponseRedirect('/test_client/get_view/')
|
if request.GET:
|
||||||
|
from urllib import urlencode
|
||||||
|
query = '?' + urlencode(request.GET, True)
|
||||||
|
else:
|
||||||
|
query = ''
|
||||||
|
return HttpResponseRedirect('/test_client/get_view/' + query)
|
||||||
|
|
||||||
def double_redirect_view(request):
|
def double_redirect_view(request):
|
||||||
"A view that redirects all requests to a redirection view"
|
"A view that redirects all requests to a redirection view"
|
||||||
@ -72,7 +78,7 @@ class TestForm(Form):
|
|||||||
value = fields.IntegerField()
|
value = fields.IntegerField()
|
||||||
single = fields.ChoiceField(choices=TestChoices)
|
single = fields.ChoiceField(choices=TestChoices)
|
||||||
multi = fields.MultipleChoiceField(choices=TestChoices)
|
multi = fields.MultipleChoiceField(choices=TestChoices)
|
||||||
|
|
||||||
def form_view(request):
|
def form_view(request):
|
||||||
"A view that tests a simple form"
|
"A view that tests a simple form"
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -87,7 +93,7 @@ def form_view(request):
|
|||||||
form = TestForm(request.GET)
|
form = TestForm(request.GET)
|
||||||
t = Template('Viewing base form. {{ form }}.', name='Form GET Template')
|
t = Template('Viewing base form. {{ form }}.', name='Form GET Template')
|
||||||
c = Context({'form': form})
|
c = Context({'form': form})
|
||||||
|
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def form_view_with_template(request):
|
def form_view_with_template(request):
|
||||||
@ -101,26 +107,26 @@ def form_view_with_template(request):
|
|||||||
else:
|
else:
|
||||||
form = TestForm()
|
form = TestForm()
|
||||||
message = 'GET form page'
|
message = 'GET form page'
|
||||||
return render_to_response('form_view.html',
|
return render_to_response('form_view.html',
|
||||||
{
|
{
|
||||||
'form': form,
|
'form': form,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def login_protected_view(request):
|
def login_protected_view(request):
|
||||||
"A simple view that is login protected."
|
"A simple view that is login protected."
|
||||||
t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
|
t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
|
||||||
c = Context({'user': request.user})
|
c = Context({'user': request.user})
|
||||||
|
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
login_protected_view = login_required(login_protected_view)
|
login_protected_view = login_required(login_protected_view)
|
||||||
|
|
||||||
def session_view(request):
|
def session_view(request):
|
||||||
"A view that modifies the session"
|
"A view that modifies the session"
|
||||||
request.session['tobacconist'] = 'hovercraft'
|
request.session['tobacconist'] = 'hovercraft'
|
||||||
|
|
||||||
t = Template('This is a view that modifies the session.',
|
t = Template('This is a view that modifies the session.',
|
||||||
name='Session Modifying View Template')
|
name='Session Modifying View Template')
|
||||||
c = Context()
|
c = Context()
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
@ -131,25 +137,25 @@ def broken_view(request):
|
|||||||
|
|
||||||
def mail_sending_view(request):
|
def mail_sending_view(request):
|
||||||
EmailMessage(
|
EmailMessage(
|
||||||
"Test message",
|
"Test message",
|
||||||
"This is a test email",
|
"This is a test email",
|
||||||
"from@example.com",
|
"from@example.com",
|
||||||
['first@example.com', 'second@example.com']).send()
|
['first@example.com', 'second@example.com']).send()
|
||||||
return HttpResponse("Mail sent")
|
return HttpResponse("Mail sent")
|
||||||
|
|
||||||
def mass_mail_sending_view(request):
|
def mass_mail_sending_view(request):
|
||||||
m1 = EmailMessage(
|
m1 = EmailMessage(
|
||||||
'First Test message',
|
'First Test message',
|
||||||
'This is the first test email',
|
'This is the first test email',
|
||||||
'from@example.com',
|
'from@example.com',
|
||||||
['first@example.com', 'second@example.com'])
|
['first@example.com', 'second@example.com'])
|
||||||
m2 = EmailMessage(
|
m2 = EmailMessage(
|
||||||
'Second Test message',
|
'Second Test message',
|
||||||
'This is the second test email',
|
'This is the second test email',
|
||||||
'from@example.com',
|
'from@example.com',
|
||||||
['second@example.com', 'third@example.com'])
|
['second@example.com', 'third@example.com'])
|
||||||
|
|
||||||
c = SMTPConnection()
|
c = SMTPConnection()
|
||||||
c.send_messages([m1,m2])
|
c.send_messages([m1,m2])
|
||||||
|
|
||||||
return HttpResponse("Mail sent")
|
return HttpResponse("Mail sent")
|
||||||
|
@ -266,6 +266,22 @@ u'bc'
|
|||||||
>>> slice_(u'abcdefg', u'0::2')
|
>>> slice_(u'abcdefg', u'0::2')
|
||||||
u'aceg'
|
u'aceg'
|
||||||
|
|
||||||
|
>>> unordered_list([u'item 1', u'item 2'])
|
||||||
|
u'\t<li>item 1</li>\n\t<li>item 2</li>'
|
||||||
|
|
||||||
|
>>> unordered_list([u'item 1', [u'item 1.1']])
|
||||||
|
u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
|
||||||
|
|
||||||
|
>>> unordered_list([u'item 1', [u'item 1.1', u'item1.2'], u'item 2'])
|
||||||
|
u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item1.2</li>\n\t</ul>\n\t</li>\n\t<li>item 2</li>'
|
||||||
|
|
||||||
|
>>> unordered_list([u'item 1', [u'item 1.1', [u'item 1.1.1', [u'item 1.1.1.1']]]])
|
||||||
|
u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1\n\t\t<ul>\n\t\t\t<li>item 1.1.1\n\t\t\t<ul>\n\t\t\t\t<li>item 1.1.1.1</li>\n\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\t\t</li>\n\t</ul>\n\t</li>'
|
||||||
|
|
||||||
|
>>> unordered_list(['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']])
|
||||||
|
u'\t<li>States\n\t<ul>\n\t\t<li>Kansas\n\t\t<ul>\n\t\t\t<li>Lawrence</li>\n\t\t\t<li>Topeka</li>\n\t\t</ul>\n\t\t</li>\n\t\t<li>Illinois</li>\n\t</ul>\n\t</li>'
|
||||||
|
|
||||||
|
# Old format for unordered lists should still work
|
||||||
>>> unordered_list([u'item 1', []])
|
>>> unordered_list([u'item 1', []])
|
||||||
u'\t<li>item 1</li>'
|
u'\t<li>item 1</li>'
|
||||||
|
|
||||||
@ -275,6 +291,9 @@ u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
|
|||||||
>>> unordered_list([u'item 1', [[u'item 1.1', []], [u'item 1.2', []]]])
|
>>> unordered_list([u'item 1', [[u'item 1.1', []], [u'item 1.2', []]]])
|
||||||
u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
|
u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
|
||||||
|
|
||||||
|
>>> unordered_list(['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]])
|
||||||
|
u'\t<li>States\n\t<ul>\n\t\t<li>Kansas\n\t\t<ul>\n\t\t\t<li>Lawrence</li>\n\t\t\t<li>Topeka</li>\n\t\t</ul>\n\t\t</li>\n\t\t<li>Illinois</li>\n\t</ul>\n\t</li>'
|
||||||
|
|
||||||
>>> add(u'1', u'2')
|
>>> add(u'1', u'2')
|
||||||
3
|
3
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"pk": "1",
|
||||||
|
"model": "auth.user",
|
||||||
|
"fields": {
|
||||||
|
"username": "testclient",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "Client",
|
||||||
|
"is_active": true,
|
||||||
|
"is_superuser": false,
|
||||||
|
"is_staff": false,
|
||||||
|
"last_login": "2006-12-17 07:03:31",
|
||||||
|
"groups": [],
|
||||||
|
"user_permissions": [],
|
||||||
|
"password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",
|
||||||
|
"email": "testclient@example.com",
|
||||||
|
"date_joined": "2006-12-17 07:03:31"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -75,7 +75,7 @@ class AssertTemplateUsedTests(TestCase):
|
|||||||
try:
|
try:
|
||||||
self.assertTemplateUsed(response, 'Empty POST Template')
|
self.assertTemplateUsed(response, 'Empty POST Template')
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEquals(str(e), "Template 'Empty POST Template' was not used to render the response. Actual template was 'Empty GET Template'")
|
self.assertEquals(str(e), "Template 'Empty POST Template' was not a template used to render the response. Actual template(s) used: Empty GET Template")
|
||||||
|
|
||||||
def test_multiple_context(self):
|
def test_multiple_context(self):
|
||||||
"Template assertions work when there are multiple contexts"
|
"Template assertions work when there are multiple contexts"
|
||||||
@ -101,7 +101,7 @@ class AssertTemplateUsedTests(TestCase):
|
|||||||
try:
|
try:
|
||||||
self.assertTemplateUsed(response, "Valid POST Template")
|
self.assertTemplateUsed(response, "Valid POST Template")
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEquals(str(e), "Template 'Valid POST Template' was not one of the templates used to render the response. Templates used: form_view.html, base.html")
|
self.assertEquals(str(e), "Template 'Valid POST Template' was not a template used to render the response. Actual template(s) used: form_view.html, base.html")
|
||||||
|
|
||||||
class AssertRedirectsTests(TestCase):
|
class AssertRedirectsTests(TestCase):
|
||||||
def test_redirect_page(self):
|
def test_redirect_page(self):
|
||||||
@ -112,6 +112,14 @@ class AssertRedirectsTests(TestCase):
|
|||||||
self.assertRedirects(response, '/test_client/get_view/')
|
self.assertRedirects(response, '/test_client/get_view/')
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEquals(str(e), "Response didn't redirect as expected: Response code was 301 (expected 302)")
|
self.assertEquals(str(e), "Response didn't redirect as expected: Response code was 301 (expected 302)")
|
||||||
|
|
||||||
|
def test_lost_query(self):
|
||||||
|
"An assertion is raised if the redirect location doesn't preserve GET parameters"
|
||||||
|
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
|
||||||
|
try:
|
||||||
|
self.assertRedirects(response, '/test_client/get_view/')
|
||||||
|
except AssertionError, e:
|
||||||
|
self.assertEquals(str(e), "Response redirected to '/test_client/get_view/?var=value', expected '/test_client/get_view/'")
|
||||||
|
|
||||||
def test_incorrect_target(self):
|
def test_incorrect_target(self):
|
||||||
"An assertion is raised if the response redirects to another target"
|
"An assertion is raised if the response redirects to another target"
|
||||||
@ -203,8 +211,29 @@ class AssertFormErrorTests(TestCase):
|
|||||||
self.assertFormError(response, 'form', 'email', 'Some error.')
|
self.assertFormError(response, 'form', 'email', 'Some error.')
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEqual(str(e), "The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [u'Enter a valid e-mail address.'])")
|
self.assertEqual(str(e), "The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [u'Enter a valid e-mail address.'])")
|
||||||
|
|
||||||
|
def test_unknown_nonfield_error(self):
|
||||||
|
"""
|
||||||
|
Checks that an assertion is raised if the form's non field errors
|
||||||
|
doesn't contain the provided error.
|
||||||
|
"""
|
||||||
|
post_data = {
|
||||||
|
'text': 'Hello World',
|
||||||
|
'email': 'not an email address',
|
||||||
|
'value': 37,
|
||||||
|
'single': 'b',
|
||||||
|
'multi': ('b','c','e')
|
||||||
|
}
|
||||||
|
response = self.client.post('/test_client/form_view/', post_data)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, "Invalid POST Template")
|
||||||
|
|
||||||
class AssertFileUploadTests(TestCase):
|
try:
|
||||||
|
self.assertFormError(response, 'form', None, 'Some error.')
|
||||||
|
except AssertionError, e:
|
||||||
|
self.assertEqual(str(e), "The form 'form' in context 0 does not contain the non-field error 'Some error.' (actual errors: )")
|
||||||
|
|
||||||
|
class FileUploadTests(TestCase):
|
||||||
def test_simple_upload(self):
|
def test_simple_upload(self):
|
||||||
fd = open(os.path.join(os.path.dirname(__file__), "views.py"))
|
fd = open(os.path.join(os.path.dirname(__file__), "views.py"))
|
||||||
post_data = {
|
post_data = {
|
||||||
@ -213,3 +242,22 @@ class AssertFileUploadTests(TestCase):
|
|||||||
}
|
}
|
||||||
response = self.client.post('/test_client_regress/file_upload/', post_data)
|
response = self.client.post('/test_client_regress/file_upload/', post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
class LoginTests(TestCase):
|
||||||
|
fixtures = ['testdata']
|
||||||
|
|
||||||
|
def test_login_different_client(self):
|
||||||
|
"Check that using a different test client doesn't violate authentication"
|
||||||
|
|
||||||
|
# Create a second client, and log in.
|
||||||
|
c = Client()
|
||||||
|
login = c.login(username='testclient', password='password')
|
||||||
|
self.assertTrue(login, 'Could not log in')
|
||||||
|
|
||||||
|
# Get a redirection page with the second client.
|
||||||
|
response = c.get("/test_client_regress/login_protected_redirect_view/")
|
||||||
|
|
||||||
|
# At this points, the self.client isn't logged in.
|
||||||
|
# Check that assertRedirects uses the original client, not the
|
||||||
|
# default client.
|
||||||
|
self.assertRedirects(response, "/test_client_regress/get_view/")
|
||||||
|
@ -4,4 +4,6 @@ import views
|
|||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^no_template_view/$', views.no_template_view),
|
(r'^no_template_view/$', views.no_template_view),
|
||||||
(r'^file_upload/$', views.file_upload_view),
|
(r'^file_upload/$', views.file_upload_view),
|
||||||
|
(r'^get_view/$', views.get_view),
|
||||||
|
(r'^login_protected_redirect_view/$', views.login_protected_redirect_view)
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core.mail import EmailMessage, SMTPConnection
|
from django.core.mail import EmailMessage, SMTPConnection
|
||||||
from django.http import HttpResponse, HttpResponseServerError
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
|
|
||||||
def no_template_view(request):
|
def no_template_view(request):
|
||||||
@ -18,3 +19,12 @@ def file_upload_view(request):
|
|||||||
else:
|
else:
|
||||||
return HttpResponseServerError()
|
return HttpResponseServerError()
|
||||||
|
|
||||||
|
def get_view(request):
|
||||||
|
"A simple login protected view"
|
||||||
|
return HttpResponse("Hello world")
|
||||||
|
get_view = login_required(get_view)
|
||||||
|
|
||||||
|
def login_protected_redirect_view(request):
|
||||||
|
"A view that redirects all requests to the GET view"
|
||||||
|
return HttpResponseRedirect('/test_client_regress/get_view/')
|
||||||
|
login_protected_redirect_view = login_required(login_protected_redirect_view)
|
Loading…
x
Reference in New Issue
Block a user