1
0
mirror of https://github.com/django/django.git synced 2025-07-03 17:29:12 +00:00

gis: Merged 6672-6783 vis svnmerge from trunk

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6815 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jeremy Dunck 2007-12-01 22:12:44 +00:00
parent 85ce45bc44
commit 23384af79b
96 changed files with 7511 additions and 4596 deletions

View File

@ -71,6 +71,7 @@ answer newbie questions, and generally made Django that much better:
Jonathan Buchanan <jonathan.buchanan@gmail.com>
Trevor Caira <trevor@caira.com>
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
Graham Carlyle <graham.carlyle@maplecroft.net>
Antonio Cavedoni <http://cavedoni.com/>
C8E
cedric@terramater.net
@ -100,6 +101,7 @@ answer newbie questions, and generally made Django that much better:
Alex Dedul
deric@monowerks.com
Max Derkachev <mderk@yandex.ru>
Rajesh Dhawan <rajesh.dhawan@gmail.com>
Sander Dijkhuis <sander.dijkhuis@gmail.com>
Jordan Dimov <s3x3y1@gmail.com>
dne@mayonnaise.net
@ -187,6 +189,7 @@ answer newbie questions, and generally made Django that much better:
krzysiek.pawlik@silvermedia.pl
Joseph Kocherhans
konrad@gwu.edu
knox <christobzr@gmail.com>
kurtiss@meetro.com
lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
@ -272,6 +275,7 @@ answer newbie questions, and generally made Django that much better:
Vinay Sajip <vinay_sajip@yahoo.co.uk>
David Schein
scott@staplefish.com
Ilya Semenov <semenov@inetss.com>
serbaut@gmail.com
John Shaffer <jshaffer2112@gmail.com>
Pete Shinners <pete@shinners.org>

1
README
View File

@ -34,4 +34,3 @@ To contribute to Django:
* Check out http://www.djangoproject.com/community/ for information
about getting involved.

View File

@ -11,11 +11,10 @@ except NameError:
def compile_messages(locale=None):
basedirs = [os.path.join('conf', 'locale'), 'locale']
basedirs = (os.path.join('conf', 'locale'), 'locale')
if os.environ.get('DJANGO_SETTINGS_MODULE'):
from django.conf import settings
if hasattr(settings, 'LOCALE_PATHS'):
basedirs += settings.LOCALE_PATHS
basedirs += settings.LOCALE_PATHS
# Gather existing directories.
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))

View File

@ -90,6 +90,8 @@ LANGUAGES_BIDI = ("he", "ar", "fa")
# to load the internationalization machinery.
USE_I18N = True
LOCALE_PATHS = ()
# Not-necessarily-technical managers of the site. They get broken link
# notifications and other various e-mails.
MANAGERS = ADMINS

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,12 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"POT-Creation-Date: 2007-11-29 10:58-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
@ -45,64 +45,73 @@ msgstr ""
msgid "Clear all"
msgstr ""
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/dateparse.js:32
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@
*/
/* Block IE 5 */
@import "null?\"\{";
@import "null.css?\"\{";
/* Import other styles */
@import url('global.css');
@import url('layout.css');
/* Import patch for IE 6 Windows */
/*\*/ @import "patch-iewin.css"; /**/
/*\*/ @import "patch-iewin.css"; /**/

View File

@ -1,6 +1,16 @@
// Handles related-objects functionality: lookup link for raw_id_admin=True
// and Add Another links.
function html_unescape(text) {
// Unescape a string that was escaped using django.utils.html.escape.
text = text.replace(/&lt;/g, '<');
text = text.replace(/&gt;/g, '>');
text = text.replace(/&quot;/g, '"');
text = text.replace(/&#39;/g, "'");
text = text.replace(/&amp;/g, '&');
return text;
}
function showRelatedObjectLookupPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^lookup_/, '');
// IE doesn't like periods in the window name, so convert temporarily.
@ -42,6 +52,10 @@ function showAddAnotherPopup(triggeringLink) {
}
function dismissAddAnotherPopup(win, newId, newRepr) {
// newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = win.name.replace(/___/g, '.');
var elem = document.getElementById(name);
if (elem) {

View File

@ -5,6 +5,6 @@
{% if bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% field_widget bound_field %}
{% if not bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% if bound_field.field.help_text %}<p class="help">{{ bound_field.field.help_text }}</p>{% endif %}
{% if bound_field.field.help_text %}<p class="help">{{ bound_field.field.help_text|safe }}</p>{% endif %}
{% endfor %}
</div>

View File

@ -13,7 +13,7 @@
{% for library in filter_libraries %}
<div class="module">
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
{% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
{% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr />{% endif %}
{% for filter in library.list|dictsort:"name" %}
<h3 id="{{ filter.name }}">{{ filter.name }}</h3>
<p>{{ filter.title }}</p>

View File

@ -13,7 +13,7 @@
{% for library in tag_libraries %}
<div class="module">
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
{% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
{% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr />{% endif %}
{% for tag in library.list|dictsort:"name" %}
<h3 id="{{ tag.name }}">{{ tag.name }}</h3>
<h4>{{ tag.title }}</h4>

View File

@ -29,10 +29,10 @@
{% for view in site_views.list|dictsort:"url" %}
{% ifchanged %}
<h3><a href="{{ view.module }}.{{ view.name }}/"/>{{ view.url|escape }}</a></h3>
<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3>
<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
<p>{{ view.title }}</p>
<hr>
<hr />
{% endifchanged %}
{% endfor %}
</div>

View File

@ -148,6 +148,8 @@ def items_for_result(cl, result):
# function has an "allow_tags" attribute set to True.
if not allow_tags:
result_repr = escape(result_repr)
else:
result_repr = mark_safe(result_repr)
else:
field_val = getattr(result, f.attname)
@ -185,7 +187,7 @@ def items_for_result(cl, result):
else:
result_repr = escape(field_val)
if force_unicode(result_repr) == '':
result_repr = '&nbsp;'
result_repr = mark_safe('&nbsp;')
# If list_display_links not defined, add the link tag to the first field
if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
table_tag = {True:'th', False:'td'}[first]

View File

@ -118,7 +118,7 @@ class FieldWrapper(object):
return not isinstance(self.field, models.AutoField)
def header_class_attribute(self):
return self.field.blank and ' class="optional"' or ''
return self.field.blank and mark_safe(' class="optional"') or ''
def use_raw_id_admin(self):
return isinstance(self.field.rel, (models.ManyToOneRel, models.ManyToManyRel)) \

View File

@ -159,7 +159,7 @@ class AdminBoundField(object):
return repr(self.__dict__)
def html_error_list(self):
return " ".join([form_field.html_error_list() for form_field in self.form_fields if form_field.errors])
return mark_safe(" ".join([form_field.html_error_list() for form_field in self.form_fields if form_field.errors]))
def original_url(self):
if self.is_file_field and self.original and self.field.attname:
@ -273,10 +273,9 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value)
if "_popup" in request.POST:
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
pk_value = '"%s"' % pk_value.replace('"', '\\"')
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
(pk_value, force_unicode(new_object).replace('"', '\\"')))
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(pk_value), escape(new_object)))
elif "_addanother" in request.POST:
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect(request.path)

View File

@ -102,7 +102,7 @@ class Comment(models.Model):
date_hierarchy = 'submit_date'
search_fields = ('comment', 'user__username')
def __repr__(self):
def __unicode__(self):
return "%s: %s..." % (self.user.username, self.comment[:100])
def get_absolute_url(self):
@ -190,7 +190,7 @@ class FreeComment(models.Model):
date_hierarchy = 'submit_date'
search_fields = ('comment', 'person_name')
def __repr__(self):
def __unicode__(self):
return "%s: %s..." % (self.person_name, self.comment[:100])
def get_absolute_url(self):
@ -244,7 +244,7 @@ class KarmaScore(models.Model):
verbose_name_plural = _('karma scores')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("%(score)d rating by %(user)s") % {'score': self.score, 'user': self.user}
class UserFlagManager(models.Manager):
@ -275,7 +275,7 @@ class UserFlag(models.Model):
verbose_name_plural = _('user flags')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("Flag by %r") % self.user
class ModeratorDeletion(models.Model):
@ -287,5 +287,5 @@ class ModeratorDeletion(models.Model):
verbose_name_plural = _('moderator deletions')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("Moderator deletion by %r") % self.user

View File

@ -0,0 +1,13 @@
# coding: utf-8
r"""
>>> from django.contrib.comments.models import Comment
>>> from django.contrib.auth.models import User
>>> u = User.objects.create_user('commenttestuser', 'commenttest@example.com', 'testpw')
>>> c = Comment(user=u, comment=u'\xe2')
>>> c
<Comment: commenttestuser: â...>
>>> print c
commenttestuser: â...
"""

View File

@ -0,0 +1 @@
""" models.py (even empty) currently required by the runtests.py to enable unit tests """

View File

@ -109,7 +109,7 @@ class FormPreview(object):
data = [(bf.name, bf.data) for bf in form] + [settings.SECRET_KEY]
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
return md5.new(pickled).hexdigest()
def failed_hash(self, request):

View File

@ -0,0 +1,12 @@
"""
This is a urlconf to be loaded by tests.py. Add any urls needed
for tests only.
"""
from django.conf.urls.defaults import *
from django.contrib.formtools.tests import *
urlpatterns = patterns('',
(r'^test1/', TestFormPreview(TestForm)),
)

View File

@ -0,0 +1,93 @@
from django import newforms as forms
from django.contrib.formtools import preview
from django import http
from django.conf import settings
from django.test import TestCase
from django.test.client import Client
success_string = "Done was called!"
test_data = {'field1': u'foo',
'field1_': u'asdf'}
class TestFormPreview(preview.FormPreview):
def done(self, request, cleaned_data):
return http.HttpResponse(success_string)
class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
class PreviewTests(TestCase):
def setUp(self):
settings.ROOT_URLCONF = 'django.contrib.formtools.test_urls'
# Create a FormPreview instance to share between tests
self.preview = preview.FormPreview(TestForm)
input_template = '<input type="hidden" name="%s" value="%s" />'
self.input = input_template % (self.preview.unused_name('stage'), "%d")
def test_unused_name(self):
"""
Verifies name mangling to get uniue field name.
"""
self.assertEqual(self.preview.unused_name('field1'), 'field1__')
def test_form_get(self):
"""
Test contrib.formtools.preview form retrieval.
Use the client library to see if we can sucessfully retrieve
the form (mostly testing the setup ROOT_URLCONF
process). Verify that an additional hidden input field
is created to manage the stage.
"""
response = self.client.get('/test1/')
stage = self.input % 1
self.assertContains(response, stage, 1)
def test_form_preview(self):
"""
Test contrib.formtools.preview form preview rendering.
Use the client library to POST to the form to see if a preview
is returned. If we do get a form back check that the hidden
value is correctly managing the state of the form.
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
test_data.update({'stage': 1})
response = self.client.post('/test1/', test_data)
# Check to confirm stage is set to 2 in output form.
stage = self.input % 2
self.assertContains(response, stage, 1)
def test_form_submit(self):
"""
Test contrib.formtools.preview form submittal.
Use the client library to POST to the form with stage set to 3
to see if our forms done() method is called. Check first
without the security hash, verify failure, retry with security
hash and verify sucess.
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
test_data.update({'stage': 2})
response = self.client.post('/test1/', test_data)
self.failIfEqual(response.content, success_string)
hash = self.preview.security_hash(None, TestForm(test_data))
test_data.update({'hash': hash})
response = self.client.post('/test1/', test_data)
self.assertEqual(response.content, success_string)
if __name__ == '__main__':
unittest.main()

View File

@ -33,6 +33,8 @@ PROVINCES_NORMALIZED = {
'british columbia': 'BC',
'mb': 'MB',
'manitoba': 'MB',
'nb': 'NB',
'new brunswick': 'NB',
'nf': 'NF',
'newfoundland': 'NF',
'newfoundland and labrador': 'NF',

View File

@ -16,7 +16,7 @@ class BaseCache(object):
def add(self, key, value, timeout=None):
"""
Set a value in the cache if the key does not already exist. If
Set a value in the cache if the key does not already exist. If
timeout is given, that timeout will be used for the key; otherwise
the default cache timeout will be used.
"""
@ -24,14 +24,14 @@ class BaseCache(object):
def get(self, key, default=None):
"""
Fetch a given key from the cache. If the key does not exist, return
Fetch a given key from the cache. If the key does not exist, return
default, which itself defaults to None.
"""
raise NotImplementedError
def set(self, key, value, timeout=None):
"""
Set a value in the cache. If timeout is given, that timeout will be
Set a value in the cache. If timeout is given, that timeout will be
used for the key; otherwise the default cache timeout will be used.
"""
raise NotImplementedError
@ -44,10 +44,10 @@ class BaseCache(object):
def get_many(self, keys):
"""
Fetch a bunch of keys from the cache. For certain backends (memcached,
Fetch a bunch of keys from the cache. For certain backends (memcached,
pgsql) this can be *much* faster when fetching multiple values.
Returns a dict mapping each key in keys to its value. If the given
Returns a dict mapping each key in keys to its value. If the given
key is missing, it will be missing from the response dict.
"""
d = {}
@ -64,4 +64,3 @@ class BaseCache(object):
return self.get(key) is not None
__contains__ = has_key

View File

@ -16,8 +16,12 @@ class CacheClass(SimpleCacheClass):
def add(self, key, value, timeout=None):
self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try:
SimpleCacheClass.add(self, key, value, timeout)
try:
super(CacheClass, self).add(key, pickle.dumps(value), timeout)
except pickle.PickleError:
pass
finally:
self._lock.writer_leaves()
@ -49,6 +53,7 @@ class CacheClass(SimpleCacheClass):
def set(self, key, value, timeout=None):
self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try:
try:
super(CacheClass, self).set(key, pickle.dumps(value), timeout)

View File

@ -52,7 +52,7 @@ def load_command_class(app_name, name):
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
{}, {}, ['Command']), 'Command')()
def get_commands(load_user_commands=True, project_directory=None):
def get_commands():
"""
Returns a dictionary of commands against the application in which
those commands can be found. This works by looking for a
@ -60,10 +60,10 @@ def get_commands(load_user_commands=True, project_directory=None):
application -- if a commands package exists, all commands in that
package are registered.
Core commands are always included; user-defined commands will also
be included if ``load_user_commands`` is True. If a project directory
is provided, the startproject command will be disabled, and the
startapp command will be modified to use that directory.
Core commands are always included. If a settings module has been
specified, user-defined commands will also be included, the
startproject command will be disabled, and the startapp command
will be modified to use the directory in which that module appears.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
@ -80,16 +80,27 @@ def get_commands(load_user_commands=True, project_directory=None):
if _commands is None:
_commands = dict([(name, 'django.core')
for name in find_commands(__path__[0])])
if load_user_commands:
# Get commands from all installed apps.
# Get commands from all installed apps.
try:
from django.conf import settings
for app_name in settings.INSTALLED_APPS:
try:
path = find_management_module(app_name)
_commands.update(dict([(name, app_name)
for name in find_commands(path)]))
except ImportError:
pass # No management module - ignore this app
apps = settings.INSTALLED_APPS
except (AttributeError, EnvironmentError):
apps = []
for app_name in apps:
try:
path = find_management_module(app_name)
_commands.update(dict([(name, app_name)
for name in find_commands(path)]))
except ImportError:
pass # No management module - ignore this app
# Try to determine the project directory
try:
from django.conf import settings
project_directory = setup_environ(__import__(settings.SETTINGS_MODULE))
except (AttributeError, EnvironmentError, ImportError):
project_directory = None
if project_directory:
# Remove the "startproject" command from self.commands, because
@ -146,8 +157,6 @@ class ManagementUtility(object):
def __init__(self, argv=None):
self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0])
self.project_directory = None
self.user_commands = False
def main_help_text(self):
"""
@ -159,8 +168,7 @@ class ManagementUtility(object):
usage.append("Type '%s help <subcommand>' for help on a specific"
" subcommand." % self.prog_name)
usage.append('Available subcommands:')
commands = get_commands(self.user_commands,
self.project_directory).keys()
commands = get_commands().keys()
commands.sort()
for cmd in commands:
usage.append(' %s' % cmd)
@ -173,8 +181,7 @@ class ManagementUtility(object):
django-admin.py or manage.py) if it can't be found.
"""
try:
app_name = get_commands(self.user_commands,
self.project_directory)[subcommand]
app_name = get_commands()[subcommand]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
@ -235,8 +242,6 @@ class ProjectManagementUtility(ManagementUtility):
"""
def __init__(self, argv, project_directory):
super(ProjectManagementUtility, self).__init__(argv)
self.project_directory = project_directory
self.user_commands = True
def setup_environ(settings_mod):
"""

View File

@ -172,14 +172,13 @@ def copy_helper(style, app_or_project, name, directory, other_name=''):
"""
Copies either a Django application layout template or a Django project
layout template into the specified directory.
* style - A color style object (see django.core.management.color).
* app_or_project - The string 'app' or 'project'.
* name - The name of the application or project.
* directory - The directory to copy the layout template to.
* other_name - When copying an application layout, this should be the name
of the project.
"""
# style -- A color style object (see django.core.management.color).
# app_or_project -- The string 'app' or 'project'.
# name -- The name of the application or project.
# directory -- The directory to which the layout template should be copied.
# other_name -- When copying an application layout, this should be the name
# of the project.
import re
import shutil
other = {'project': 'app', 'app': 'project'}[app_or_project]

View File

@ -91,7 +91,7 @@ class ObjectPaginator(object):
a template for loop.
"""
if self._page_range is None:
self._page_range = range(1, self._pages + 1)
self._page_range = range(1, self.pages + 1)
return self._page_range
hits = property(_get_hits)

View File

@ -8,7 +8,6 @@ been reviewed for security issues. Don't use it for production use.
"""
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from types import ListType, StringType
import mimetypes
import os
import re
@ -72,7 +71,7 @@ def _formatparam(param, value=None, quote=1):
class Headers(object):
"""Manage a collection of HTTP response headers"""
def __init__(self,headers):
if type(headers) is not ListType:
if not isinstance(headers, list):
raise TypeError("Headers must be a list of name/value tuples")
self._headers = headers
@ -327,7 +326,7 @@ class ServerHandler(object):
"""Compute Content-Length or switch to chunked encoding if possible"""
try:
blocks = len(self.result)
except (TypeError,AttributeError,NotImplementedError):
except (TypeError, AttributeError, NotImplementedError):
pass
else:
if blocks==1:
@ -356,14 +355,14 @@ class ServerHandler(object):
elif self.headers is not None:
raise AssertionError("Headers already set!")
assert type(status) is StringType,"Status must be a string"
assert isinstance(status, str),"Status must be a string"
assert len(status)>=4,"Status must be at least 4 characters"
assert int(status[:3]),"Status message must begin w/3-digit code"
assert status[3]==" ", "Status message must have a space after code"
if __debug__:
for name,val in headers:
assert type(name) is StringType,"Header names must be strings"
assert type(val) is StringType,"Header values must be strings"
assert isinstance(name, str),"Header names must be strings"
assert isinstance(val, str),"Header values must be strings"
assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
self.status = status
self.headers = self.headers_class(headers)
@ -386,7 +385,7 @@ class ServerHandler(object):
def write(self, data):
"""'write()' callable as specified by PEP 333"""
assert type(data) is StringType,"write() argument must be string"
assert isinstance(data, str), "write() argument must be string"
if not self.status:
raise AssertionError("write() before start_response()")

View File

@ -471,5 +471,5 @@ def method_get_order(ordered_obj, self):
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
##############################################
def get_absolute_url(opts, func, self):
return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self)
def get_absolute_url(opts, func, self, *args, **kwargs):
return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self, *args, **kwargs)

View File

@ -396,7 +396,7 @@ class Field(object):
"Returns a django.newforms.Field instance for this database Field."
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
if self.choices:
defaults['widget'] = forms.Select(choices=self.get_choices())
defaults['widget'] = forms.Select(choices=self.get_choices(include_blank=self.blank or not (self.has_default() or 'initial' in kwargs)))
if self.has_default():
defaults['initial'] = self.get_default()
defaults.update(kwargs)

View File

@ -28,10 +28,10 @@ class Creator(object):
def __get__(self, obj, type=None):
if obj is None:
raise AttributeError('Can only be accessed via an instance.')
return self.value
return obj.__dict__[self.field.name]
def __set__(self, obj, value):
self.value = self.field.to_python(value)
obj.__dict__[self.field.name] = self.field.to_python(value)
def make_contrib(func=None):
"""

View File

@ -1,14 +1,18 @@
from django.conf import settings
from django.core.cache import cache
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
class CacheMiddleware(object):
"""
Cache middleware. If this is enabled, each Django-powered page will be
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs.
cached (based on URLs).
Only parameter-less GET or HEAD-requests with status code 200 are cached.
The number of seconds each page is stored for is set by the
"max-age" section of the response's "Cache-Control" header, falling back to
the CACHE_MIDDLEWARE_SECONDS setting if the section was not found.
If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
(i.e., those not made by a logged-in user) will be cached. This is a
simple and effective way of avoiding the caching of the Django admin (and
@ -78,7 +82,16 @@ class CacheMiddleware(object):
return response
if not response.status_code == 200:
return response
patch_response_headers(response, self.cache_timeout)
cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix)
cache.set(cache_key, response, self.cache_timeout)
# Try to get the timeout from the "max-age" section of the "Cache-
# Control" header before reverting to using the default cache_timeout
# length.
timeout = get_max_age(response)
if timeout == None:
timeout = self.cache_timeout
elif timeout == 0:
# max-age was set to 0, don't bother caching.
return response
patch_response_headers(response, timeout)
cache_key = learn_cache_key(request, response, timeout, self.key_prefix)
cache.set(cache_key, response, timeout)
return response

View File

@ -1,4 +1,5 @@
import re
from django.utils.text import compress_string
from django.utils.cache import patch_vary_headers
@ -11,18 +12,21 @@ class GZipMiddleware(object):
on the Accept-Encoding header.
"""
def process_response(self, request, response):
# It's not worth compressing non-OK or really short responses.
if response.status_code != 200 or len(response.content) < 200:
# Not worth compressing really short responses or 304 status
# responses, etc.
return response
patch_vary_headers(response, ('Accept-Encoding',))
# Avoid gzipping if we've already got a content-encoding or if the
# content-type is Javascript and the user's browser is IE.
is_js = ("msie" in request.META.get('HTTP_USER_AGENT', '').lower() and
"javascript" in response.get('Content-Type', '').lower())
if response.has_header('Content-Encoding') or is_js:
# Avoid gzipping if we've already got a content-encoding.
if response.has_header('Content-Encoding'):
return response
# Older versions of IE have issues with gzipped javascript.
# See http://code.djangoproject.com/ticket/2449
is_ie = "msie" in request.META.get('HTTP_USER_AGENT', '').lower()
is_js = "javascript" in response.get('Content-Type', '').lower()
if is_ie and is_js:
return response
ae = request.META.get('HTTP_ACCEPT_ENCODING', '')

View File

@ -6,6 +6,7 @@ import datetime
from django.newforms.widgets import Widget, Select
from django.utils.dates import MONTHS
from django.utils.safestring import mark_safe
__all__ = ('SelectDateWidget',)
@ -51,7 +52,7 @@ class SelectDateWidget(Widget):
select_html = Select(choices=year_choices).render(self.year_field % name, year_val)
output.append(select_html)
return u'\n'.join(output)
return mark_safe(u'\n'.join(output))
def value_from_datadict(self, data, files, name):
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)

View File

@ -17,7 +17,7 @@ except NameError:
from sets import Set as set
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import StrAndUnicode, smart_unicode
from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
from util import ErrorList, ValidationError
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
@ -235,7 +235,7 @@ class DecimalField(Field):
super(DecimalField, self).clean(value)
if not self.required and value in EMPTY_VALUES:
return None
value = str(value).strip()
value = smart_str(value).strip()
try:
value = Decimal(value)
except DecimalException:
@ -536,11 +536,12 @@ class BooleanField(Field):
widget = CheckboxInput
def clean(self, value):
"Returns a Python boolean object."
"""Returns a Python boolean object."""
super(BooleanField, self).clean(value)
# Explicitly check for the string '0', which is what as hidden field
# will submit for False.
if value == '0':
# Explicitly check for the string 'False', which is what a hidden field
# will submit for False (since bool("True") == True we don't need to
# handle that explicitly).
if value == 'False':
return False
return bool(value)

View File

@ -3,13 +3,13 @@ Helper functions for creating Form classes from Django models
and database field objects.
"""
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.utils.datastructures import SortedDict
from util import ValidationError
from forms import BaseForm
from fields import Field, ChoiceField
from fields import Field, ChoiceField, EMPTY_VALUES
from widgets import Select, SelectMultiple, MultipleHiddenInput
__all__ = (
@ -151,15 +151,20 @@ class ModelChoiceField(ChoiceField):
"""A ChoiceField whose choices are a model QuerySet."""
# This class is a subclass of ChoiceField for purity, but it doesn't
# actually use any of ChoiceField's implementation.
default_error_messages = {
'invalid_choice': _(u'Select a valid choice. That choice is not one of'
u' the available choices.'),
}
def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
required=True, widget=Select, label=None, initial=None,
help_text=None):
help_text=None, *args, **kwargs):
self.empty_label = empty_label
self.cache_choices = cache_choices
# Call Field instead of ChoiceField __init__() because we don't need
# ChoiceField.__init__().
Field.__init__(self, required, widget, label, initial, help_text)
Field.__init__(self, required, widget, label, initial, help_text,
*args, **kwargs)
self.queryset = queryset
def _get_queryset(self):
@ -195,41 +200,43 @@ class ModelChoiceField(ChoiceField):
def clean(self, value):
Field.clean(self, value)
if value in ('', None):
if value in EMPTY_VALUES:
return None
try:
value = self.queryset.get(pk=value)
except self.queryset.model.DoesNotExist:
raise ValidationError(ugettext(u'Select a valid choice. That'
u' choice is not one of the'
u' available choices.'))
raise ValidationError(self.error_messages['invalid_choice'])
return value
class ModelMultipleChoiceField(ModelChoiceField):
"""A MultipleChoiceField whose choices are a model QuerySet."""
hidden_widget = MultipleHiddenInput
default_error_messages = {
'list': _(u'Enter a list of values.'),
'invalid_choice': _(u'Select a valid choice. %s is not one of the'
u' available choices.'),
}
def __init__(self, queryset, cache_choices=False, required=True,
widget=SelectMultiple, label=None, initial=None,
help_text=None):
help_text=None, *args, **kwargs):
super(ModelMultipleChoiceField, self).__init__(queryset, None,
cache_choices, required, widget, label, initial, help_text)
cache_choices, required, widget, label, initial, help_text,
*args, **kwargs)
def clean(self, value):
if self.required and not value:
raise ValidationError(ugettext(u'This field is required.'))
raise ValidationError(self.error_messages['required'])
elif not self.required and not value:
return []
if not isinstance(value, (list, tuple)):
raise ValidationError(ugettext(u'Enter a list of values.'))
raise ValidationError(self.error_messages['list'])
final_values = []
for val in value:
try:
obj = self.queryset.get(pk=val)
except self.queryset.model.DoesNotExist:
raise ValidationError(ugettext(u'Select a valid choice. %s is'
u' not one of the available'
u' choices.') % val)
raise ValidationError(self.error_messages['invalid_choice'] % val)
else:
final_values.append(obj)
return final_values

View File

@ -11,7 +11,7 @@ import copy
from itertools import chain
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
from django.utils.html import escape, conditional_escape
from django.utils.translation import ugettext
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe
@ -155,7 +155,7 @@ class Textarea(Widget):
value = force_unicode(value)
final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
escape(value)))
conditional_escape(force_unicode(value))))
class DateTimeInput(Input):
input_type = 'text'
@ -217,7 +217,9 @@ class Select(Widget):
for option_value, option_label in chain(self.choices, choices):
option_value = force_unicode(option_value)
selected_html = (option_value == str_value) and u' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
output.append(u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label))))
output.append(u'</select>')
return mark_safe(u'\n'.join(output))
@ -254,7 +256,9 @@ class SelectMultiple(Widget):
for option_value, option_label in chain(self.choices, choices):
option_value = force_unicode(option_value)
selected_html = (option_value in str_values) and ' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
output.append(u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label))))
output.append(u'</select>')
return mark_safe(u'\n'.join(output))
@ -278,7 +282,7 @@ class RadioInput(StrAndUnicode):
def __unicode__(self):
return mark_safe(u'<label>%s %s</label>' % (self.tag(),
self.choice_label))
conditional_escape(force_unicode(self.choice_label))))
def is_checked(self):
return self.value == self.choice_value
@ -317,11 +321,13 @@ class RadioFieldRenderer(StrAndUnicode):
% force_unicode(w) for w in self]))
class RadioSelect(Select):
renderer = RadioFieldRenderer
def __init__(self, *args, **kwargs):
self.renderer = kwargs.pop('renderer', None)
if not self.renderer:
self.renderer = RadioFieldRenderer
# Override the default renderer if we were passed one.
renderer = kwargs.pop('renderer', None)
if renderer:
self.renderer = renderer
super(RadioSelect, self).__init__(*args, **kwargs)
def get_renderer(self, name, value, attrs=None, choices=()):
@ -361,7 +367,8 @@ class CheckboxSelectMultiple(SelectMultiple):
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(force_unicode(option_label))))
output.append(u'<li><label>%s %s</label></li>' % (rendered_cb,
conditional_escape(force_unicode(option_label))))
output.append(u'</ul>')
return mark_safe(u'\n'.join(output))

View File

@ -547,9 +547,9 @@ class FilterExpression(object):
if var == None:
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
if i18n_constant:
var = '"%s"' % _(i18n_constant)
var = '"%s"' % _(i18n_constant.replace(r'\"', '"'))
elif constant:
var = '"%s"' % constant
var = '"%s"' % constant.replace(r'\"', '"')
upto = match.end()
if var == None:
raise TemplateSyntaxError, "Could not find variable at start of %s" % token
@ -594,7 +594,7 @@ class FilterExpression(object):
arg_vals = []
for lookup, arg in args:
if not lookup:
arg_vals.append(arg)
arg_vals.append(mark_safe(arg))
else:
arg_vals.append(arg.resolve(context))
if getattr(func, 'needs_autoescape', False):
@ -678,6 +678,7 @@ class Variable(object):
self.var = var
self.literal = None
self.lookups = None
self.translate = False
try:
# First try to treat this variable as a number.
@ -698,11 +699,15 @@ class Variable(object):
except ValueError:
# A ValueError means that the variable isn't a number.
if var.startswith('_(') and var.endswith(')'):
# The result of the lookup should be translated at rendering
# time.
self.translate = True
var = var[2:-1]
# If it's wrapped with quotes (single or double), then
# we're also dealing with a literal.
if var[0] in "\"'" and var[0] == var[-1]:
self.literal = var[1:-1]
self.literal = mark_safe(var[1:-1])
else:
# Otherwise we'll set self.lookups so that resolve() knows we're
# dealing with a bonafide variable
@ -712,10 +717,13 @@ class Variable(object):
"""Resolve this variable against a given context."""
if self.lookups is not None:
# We're dealing with a variable that needs to be resolved
return self._resolve_lookup(context)
value = self._resolve_lookup(context)
else:
# We're dealing with a literal, so it's already been "resolved"
return self.literal
value = self.literal
if self.translate:
return _(value)
return value
def __repr__(self):
return "<%s: %r>" % (self.__class__.__name__, self.var)
@ -796,7 +804,7 @@ class NodeList(list):
bits.append(self.render_node(node, context))
else:
bits.append(node)
return ''.join([force_unicode(b) for b in bits])
return mark_safe(''.join([force_unicode(b) for b in bits]))
def get_nodes_by_type(self, nodetype):
"Return a list of all nodes of the given type"

View File

@ -25,6 +25,8 @@ def stringfilter(func):
if args:
args = list(args)
args[0] = force_unicode(args[0])
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
return mark_safe(func(*args, **kwargs))
return func(*args, **kwargs)
# Include a reference to the real function (used to check original
@ -89,7 +91,7 @@ def floatformat(text, arg=-1):
"""
try:
f = float(text)
except ValueError:
except (ValueError, TypeError):
return u''
try:
d = int(arg)
@ -106,6 +108,7 @@ floatformat.is_safe = True
def iriencode(value):
"""Escapes an IRI value for use in a URL."""
return force_unicode(iri_to_uri(value))
iriencode.is_safe = True
iriencode = stringfilter(iriencode)
def linenumbers(value, autoescape=None):

View File

@ -2,6 +2,7 @@ from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
from django.template import Library, Node
from django.template.loader import get_template, get_template_from_string, find_template_source
from django.conf import settings
from django.utils.safestring import mark_safe
register = Library()
@ -26,7 +27,7 @@ class BlockNode(Node):
def super(self):
if self.parent:
return self.parent.render(self.context)
return mark_safe(self.parent.render(self.context))
return ''
def add_parent(self, nodelist):

View File

@ -1,9 +1,10 @@
import re
from django.template import Node, Variable
from django.template import Node, Variable, VariableNode
from django.template import TemplateSyntaxError, TokenParser, Library
from django.template import TOKEN_TEXT, TOKEN_VAR
from django.utils import translation
from django.utils.encoding import force_unicode
register = Library()
@ -45,7 +46,8 @@ class TranslateNode(Node):
return translation.ugettext(value)
class BlockTranslateNode(Node):
def __init__(self, extra_context, singular, plural=None, countervar=None, counter=None):
def __init__(self, extra_context, singular, plural=None, countervar=None,
counter=None):
self.extra_context = extra_context
self.singular = singular
self.plural = plural
@ -54,29 +56,32 @@ class BlockTranslateNode(Node):
def render_token_list(self, tokens):
result = []
vars = []
for token in tokens:
if token.token_type == TOKEN_TEXT:
result.append(token.contents)
elif token.token_type == TOKEN_VAR:
result.append('%%(%s)s' % token.contents)
return ''.join(result)
result.append(u'%%(%s)s' % token.contents)
vars.append(token.contents)
return ''.join(result), vars
def render(self, context):
context.push()
for var,val in self.extra_context.items():
context[var] = val.resolve(context)
singular = self.render_token_list(self.singular)
for var, val in self.extra_context.items():
context[var] = val.render(context)
singular, vars = self.render_token_list(self.singular)
if self.plural and self.countervar and self.counter:
count = self.counter.resolve(context)
context[self.countervar] = count
plural = self.render_token_list(self.plural)
plural, vars = self.render_token_list(self.plural)
result = translation.ungettext(singular, plural, count)
else:
result = translation.ugettext(singular)
# Escape all isolated '%' before substituting in the context.
result = re.sub('%(?!\()', '%%', result) % context
result = re.sub(u'%(?!\()', u'%%', result)
data = dict([(v, force_unicode(context[v])) for v in vars])
context.pop()
return result
return result % data
def do_get_available_languages(parser, token):
"""
@ -198,7 +203,6 @@ def do_block_translate(parser, token):
This is much like ngettext, only in template syntax.
"""
class BlockTranslateParser(TokenParser):
def top(self):
countervar = None
counter = None
@ -209,7 +213,8 @@ def do_block_translate(parser, token):
value = self.value()
if self.tag() != 'as':
raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'"
extra_context[self.tag()] = parser.compile_filter(value)
extra_context[self.tag()] = VariableNode(
parser.compile_filter(value))
elif tag == 'count':
counter = parser.compile_filter(self.value())
if self.tag() != 'as':
@ -241,7 +246,8 @@ def do_block_translate(parser, token):
if token.contents.strip() != 'endblocktrans':
raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents
return BlockTranslateNode(extra_context, singular, plural, countervar, counter)
return BlockTranslateNode(extra_context, singular, plural, countervar,
counter)
register.tag('get_available_languages', do_get_available_languages)
register.tag('get_current_language', do_get_current_language)

View File

@ -51,9 +51,9 @@ class TestCase(unittest.TestCase):
def _pre_setup(self):
"""Performs any pre-test setup. This includes:
* If the Test Case class has a 'fixtures' member, clearing the
database and installing the named fixtures at the start of each
test.
* Flushing the database.
* If the Test Case class has a 'fixtures' member, installing the
named fixtures.
* Clearing the mail test outbox.
"""
call_command('flush', verbosity=0, interactive=False)

View File

@ -20,6 +20,10 @@ An example: i18n middleware would need to distinguish caches by the
import md5
import re
import time
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
from django.conf import settings
from django.core.cache import cache
@ -70,7 +74,20 @@ def patch_cache_control(response, **kwargs):
cc = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc
vary_delim_re = re.compile(r',\s*')
def get_max_age(response):
"""
Returns the max-age from the response Cache-Control header as an integer
(or ``None`` if it wasn't found or wasn't an integer.
"""
if not response.has_header('Cache-Control'):
return
cc = dict([_to_tuple(el) for el in
cc_delim_re.split(response['Cache-Control'])])
if 'max-age' in cc:
try:
return int(cc['max-age'])
except (ValueError, TypeError):
pass
def patch_response_headers(response, cache_timeout=None):
"""
@ -109,14 +126,15 @@ def patch_vary_headers(response, newheaders):
# Note that we need to keep the original order intact, because cache
# implementations may rely on the order of the Vary contents in, say,
# computing an MD5 hash.
vary = []
if response.has_header('Vary'):
vary = vary_delim_re.split(response['Vary'])
oldheaders = dict([(el.lower(), 1) for el in vary])
for newheader in newheaders:
if not newheader.lower() in oldheaders:
vary.append(newheader)
response['Vary'] = ', '.join(vary)
vary_headers = cc_delim_re.split(response['Vary'])
else:
vary_headers = []
# Use .lower() here so we treat headers as case-insensitive.
existing_headers = set([header.lower() for header in vary_headers])
additional_headers = [newheader for newheader in newheaders
if newheader.lower() not in existing_headers]
response['Vary'] = ', '.join(vary_headers + additional_headers)
def _generate_cache_key(request, headerlist, key_prefix):
"""Returns a cache key from the headers given in the header list."""
@ -169,7 +187,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
key_prefix, iri_to_uri(request.path))
if response.has_header('Vary'):
headerlist = ['HTTP_'+header.upper().replace('-', '_')
for header in vary_delim_re.split(response['Vary'])]
for header in cc_delim_re.split(response['Vary'])]
cache.set(cache_key, headerlist, cache_timeout)
return _generate_cache_key(request, headerlist, key_prefix)
else:
@ -177,3 +195,10 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
# for the request.path
cache.set(cache_key, [], cache_timeout)
return _generate_cache_key(request, [], key_prefix)
def _to_tuple(s):
t = s.split('=',1)
if len(t) == 2:
return t[0].lower(), t[1]
return t[0].lower(), True

View File

@ -7,9 +7,9 @@ class MergeDict(object):
self.dicts = dicts
def __getitem__(self, key):
for dict in self.dicts:
for dict_ in self.dicts:
try:
return dict[key]
return dict_[key]
except KeyError:
pass
raise KeyError
@ -24,22 +24,22 @@ class MergeDict(object):
return default
def getlist(self, key):
for dict in self.dicts:
for dict_ in self.dicts:
try:
return dict.getlist(key)
return dict_.getlist(key)
except KeyError:
pass
raise KeyError
def items(self):
item_list = []
for dict in self.dicts:
item_list.extend(dict.items())
for dict_ in self.dicts:
item_list.extend(dict_.items())
return item_list
def has_key(self, key):
for dict in self.dicts:
if key in dict:
for dict_ in self.dicts:
if key in dict_:
return True
return False
@ -56,11 +56,14 @@ class SortedDict(dict):
def __init__(self, data=None):
if data is None:
data = {}
dict.__init__(self, data)
super(SortedDict, self).__init__(data)
if isinstance(data, dict):
self.keyOrder = data.keys()
else:
self.keyOrder = [key for key, value in data]
self.keyOrder = []
for key, value in data:
if key not in self.keyOrder:
self.keyOrder.append(key)
def __deepcopy__(self, memo):
from copy import deepcopy
@ -68,12 +71,12 @@ class SortedDict(dict):
for key, value in self.iteritems()])
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
super(SortedDict, self).__setitem__(key, value)
if key not in self.keyOrder:
self.keyOrder.append(key)
def __delitem__(self, key):
dict.__delitem__(self, key)
super(SortedDict, self).__delitem__(key)
self.keyOrder.remove(key)
def __iter__(self):
@ -81,7 +84,7 @@ class SortedDict(dict):
yield k
def pop(self, k, *args):
result = dict.pop(self, k, *args)
result = super(SortedDict, self).pop(k, *args)
try:
self.keyOrder.remove(k)
except ValueError:
@ -90,7 +93,7 @@ class SortedDict(dict):
return result
def popitem(self):
result = dict.popitem(self)
result = super(SortedDict, self).popitem()
self.keyOrder.remove(result[0])
return result
@ -99,7 +102,7 @@ class SortedDict(dict):
def iteritems(self):
for key in self.keyOrder:
yield key, dict.__getitem__(self, key)
yield key, super(SortedDict, self).__getitem__(key)
def keys(self):
return self.keyOrder[:]
@ -108,20 +111,20 @@ class SortedDict(dict):
return iter(self.keyOrder)
def values(self):
return [dict.__getitem__(self, k) for k in self.keyOrder]
return [super(SortedDict, self).__getitem__(k) for k in self.keyOrder]
def itervalues(self):
for key in self.keyOrder:
yield dict.__getitem__(self, key)
yield super(SortedDict, self).__getitem__(key)
def update(self, dict):
for k, v in dict.items():
def update(self, dict_):
for k, v in dict_.items():
self.__setitem__(k, v)
def setdefault(self, key, default):
if key not in self.keyOrder:
self.keyOrder.append(key)
return dict.setdefault(self, key, default)
return super(SortedDict, self).setdefault(key, default)
def value_for_index(self, index):
"""Returns the value of the item at the given zero-based index."""
@ -135,7 +138,7 @@ class SortedDict(dict):
if n < index:
index -= 1
self.keyOrder.insert(index, key)
dict.__setitem__(self, key, value)
super(SortedDict, self).__setitem__(key, value)
def copy(self):
"""Returns a copy of this object."""
@ -173,10 +176,11 @@ class MultiValueDict(dict):
single name-value pairs.
"""
def __init__(self, key_to_list_mapping=()):
dict.__init__(self, key_to_list_mapping)
super(MultiValueDict, self).__init__(key_to_list_mapping)
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, dict.__repr__(self))
return "<%s: %s>" % (self.__class__.__name__,
super(MultiValueDict, self).__repr__())
def __getitem__(self, key):
"""
@ -184,7 +188,7 @@ class MultiValueDict(dict):
raises KeyError if not found.
"""
try:
list_ = dict.__getitem__(self, key)
list_ = super(MultiValueDict, self).__getitem__(key)
except KeyError:
raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)
try:
@ -193,10 +197,10 @@ class MultiValueDict(dict):
return []
def __setitem__(self, key, value):
dict.__setitem__(self, key, [value])
super(MultiValueDict, self).__setitem__(key, [value])
def __copy__(self):
return self.__class__(dict.items(self))
return self.__class__(super(MultiValueDict, self).items())
def __deepcopy__(self, memo=None):
import copy
@ -210,7 +214,10 @@ class MultiValueDict(dict):
return result
def get(self, key, default=None):
"""Returns the default value if the requested data doesn't exist."""
"""
Returns the last data value for the passed key. If key doesn't exist
or value is an empty list, then default is returned.
"""
try:
val = self[key]
except KeyError:
@ -220,14 +227,17 @@ class MultiValueDict(dict):
return val
def getlist(self, key):
"""Returns an empty list if the requested data doesn't exist."""
"""
Returns the list of values for the passed key. If key doesn't exist,
then an empty list is returned.
"""
try:
return dict.__getitem__(self, key)
return super(MultiValueDict, self).__getitem__(key)
except KeyError:
return []
def setlist(self, key, list_):
dict.__setitem__(self, key, list_)
super(MultiValueDict, self).__setitem__(key, list_)
def setdefault(self, key, default=None):
if key not in self:
@ -242,7 +252,7 @@ class MultiValueDict(dict):
def appendlist(self, key, value):
"""Appends an item to the internal list associated with key."""
self.setlistdefault(key, [])
dict.__setitem__(self, key, self.getlist(key) + [value])
super(MultiValueDict, self).__setitem__(key, self.getlist(key) + [value])
def items(self):
"""
@ -253,7 +263,7 @@ class MultiValueDict(dict):
def lists(self):
"""Returns a list of (key, list) pairs."""
return dict.items(self)
return super(MultiValueDict, self).items()
def values(self):
"""Returns a list of the last value on every key list."""
@ -315,7 +325,7 @@ class DotExpandedDict(dict):
try:
current[bits[-1]] = v
except TypeError: # Special-case if current isn't a dict.
current = {bits[-1] : v}
current = {bits[-1]: v}
class FileDict(dict):
"""

View File

@ -6,6 +6,7 @@ import string
from django.utils.safestring import SafeData, mark_safe
from django.utils.encoding import force_unicode
from django.utils.functional import allow_lazy
from django.utils.http import urlquote
# Configuration for urlize() function
LEADING_PUNCTUATION = ['(', '<', '&lt;']
@ -101,14 +102,24 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \
len(middle) > 0 and middle[0] in string.letters + string.digits and \
(middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
middle = '<a href="http://%s"%s>%s</a>' % (middle, nofollow_attr, trim_url(middle))
middle = '<a href="http://%s"%s>%s</a>' % (
urlquote(middle, safe='/&=:;#?+'), nofollow_attr,
trim_url(middle))
if middle.startswith('http://') or middle.startswith('https://'):
middle = '<a href="%s"%s>%s</a>' % (middle, nofollow_attr, trim_url(middle))
if '@' in middle and not middle.startswith('www.') and not ':' in middle \
and simple_email_re.match(middle):
middle = '<a href="%s"%s>%s</a>' % (
urlquote(middle, safe='/&=:;#?+'), nofollow_attr,
trim_url(middle))
if '@' in middle and not middle.startswith('www.') and \
not ':' in middle and simple_email_re.match(middle):
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
if lead + middle + trail != word:
words[i] = lead + middle + trail
elif autoescape and not safe_input:
words[i] = escape(word)
elif safe_input:
words[i] = mark_safe(word)
elif autoescape:
words[i] = escape(word)
return u''.join(words)
urlize = allow_lazy(urlize, unicode)

View File

@ -57,7 +57,6 @@ class SafeString(str, SafeData):
else:
return SafeUnicode(data)
encode = curry(_proxy_method, method = str.encode)
decode = curry(_proxy_method, method = str.decode)
class SafeUnicode(unicode, SafeData):
@ -89,7 +88,6 @@ class SafeUnicode(unicode, SafeData):
return SafeUnicode(data)
encode = curry(_proxy_method, method = unicode.encode)
decode = curry(_proxy_method, method = unicode.decode)
def mark_safe(s):
"""

View File

@ -4,6 +4,7 @@
from django.conf import settings
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe, SafeData
def ngettext(singular, plural, number):
if number == 1: return singular
@ -31,7 +32,10 @@ TECHNICAL_ID_MAP = {
}
def gettext(message):
return TECHNICAL_ID_MAP.get(message, message)
result = TECHNICAL_ID_MAP.get(message, message)
if isinstance(message, SafeData):
return mark_safe(result)
return result
def ugettext(message):
return force_unicode(gettext(message))

View File

@ -8,6 +8,7 @@ import gettext as gettext_module
from cStringIO import StringIO
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe, SafeData
try:
import threading
@ -167,10 +168,9 @@ def translation(language):
res.merge(t)
return res
if hasattr(settings, 'LOCALE_PATHS'):
for localepath in settings.LOCALE_PATHS:
if os.path.isdir(localepath):
res = _merge(localepath)
for localepath in settings.LOCALE_PATHS:
if os.path.isdir(localepath):
res = _merge(localepath)
if projectpath and os.path.isdir(projectpath):
res = _merge(projectpath)
@ -271,11 +271,15 @@ def do_translate(message, translation_function):
global _default, _active
t = _active.get(currentThread(), None)
if t is not None:
return getattr(t, translation_function)(message)
if _default is None:
from django.conf import settings
_default = translation(settings.LANGUAGE_CODE)
return getattr(_default, translation_function)(message)
result = getattr(t, translation_function)(message)
else:
if _default is None:
from django.conf import settings
_default = translation(settings.LANGUAGE_CODE)
result = getattr(_default, translation_function)(message)
if isinstance(message, SafeData):
return mark_safe(result)
return result
def gettext(message):
return do_translate(message, 'gettext')

View File

@ -54,6 +54,12 @@ class LocalTimezone(tzinfo):
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
stamp = time.mktime(tt)
try:
stamp = time.mktime(tt)
except OverflowError:
# 32 bit systems can't handle dates after Jan 2038, so we fake it
# in that case (since we only care about the DST flag here).
tt = (2037,) + tt[1:]
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0

View File

@ -422,11 +422,11 @@ TECHNICAL_500_TEMPLATE = """
{% if frame.context_line %}
<div class="context" id="c{{ frame.id }}">
{% if frame.pre_context %}
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol>
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
{% endif %}
<ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line }} <span>...</span></li></ol>
<ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line|escape }} <span>...</span></li></ol>
{% if frame.post_context %}
<ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol>
<ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
{% endif %}
</div>
{% endif %}
@ -445,8 +445,8 @@ TECHNICAL_500_TEMPLATE = """
<tbody>
{% for var in frame.vars|dictsort:"0" %}
<tr>
<td>{{ var.0 }}</td>
<td class="code"><div>{{ var.1|pprint }}</div></td>
<td>{{ var.0|escape }}</td>
<td class="code"><div>{{ var.1|pprint|escape }}</div></td>
</tr>
{% endfor %}
</tbody>
@ -466,7 +466,7 @@ Traceback (most recent call last):<br/>
{% for frame in frames %}
File "{{ frame.filename }}" in {{ frame.function }}<br/>
{% if frame.context_line %}
&nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line }}<br/>
&nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line|escape }}<br/>
{% endif %}
{% endfor %}<br/>
&nbsp;&nbsp;{{ exception_type }} at {{ request.path|escape }}<br/>

View File

@ -120,8 +120,12 @@ def javascript_catalog(request, domain='djangojs', packages=None):
p = __import__(package, {}, {}, [''])
path = os.path.join(os.path.dirname(p.__file__), 'locale')
paths.append(path)
catalog = gettext_module.translation(domain, path, ['en'])
t.update(catalog._catalog)
try:
catalog = gettext_module.translation(domain, path, ['en'])
t.update(catalog._catalog)
except IOError:
# 'en' catalog was missing. This is harmless.
pass
# next load the settings.LANGUAGE_CODE translations if it isn't english
if default_locale != 'en':
for path in paths:

View File

@ -1,5 +1,5 @@
"""
Views and functions for serving static files. These are only to be used
Views and functions for serving static files. These are only to be used
during development, and SHOULD NOT be used in a production setting.
"""
@ -33,6 +33,7 @@ def serve(request, path, document_root=None, show_indexes=False):
# Clean up given path to only allow serving files below document_root.
path = posixpath.normpath(urllib.unquote(path))
path = path.lstrip('/')
newpath = ''
for part in path.split('/'):
if not part:

View File

@ -170,7 +170,7 @@ The ``User`` model has a custom manager that has the following helper functions:
If no password is provided, ``set_unusable_password()`` will be called.
See _`Creating users` for example usage.
See `Creating users`_ for example usage.
* ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')``
Returns a random password with the given length and given string of

View File

@ -263,6 +263,18 @@ See the `middleware documentation`_ for more on middleware.
.. _`middleware documentation`: ../middleware/
**New in Django development version**
If a view sets its own cache expiry time (i.e. it has a ``max-age`` section in
its ``Cache-Control`` header) then the page will be cached until the expiry
time, rather than ``CACHE_MIDDLEWARE_SECONDS``. Using the decorators in
``django.views.decorators.cache`` you can easily set a view's expiry time
(using the ``cache_control`` decorator) or disable caching for a view (using
the ``never_cache`` decorator). See the `using other headers`__ section for
more on these decorators.
__ `Controlling cache: Using other headers`_
The per-view cache
==================
@ -291,7 +303,7 @@ minutes.
Template fragment caching
=========================
**New in development version**.
**New in development version**
If you're after even more control, you can also cache template fragments using
the ``cache`` template tag. To give your template access to this tag, put
@ -307,18 +319,18 @@ and the name to give the cache fragment. For example::
{% endcache %}
Sometimes you might want to cache multiple copies of a fragment depending on
some dynamic data that appears inside the fragment. For example you may want a
some dynamic data that appears inside the fragment. For example, you might want a
separate cached copy of the sidebar used in the previous example for every user
of your site. This can be easily achieved by passing additional arguments to
the ``{% cache %}`` template tag to uniquely identify the cache fragment::
of your site. Do this by passing additional arguments to the ``{% cache %}``
template tag to uniquely identify the cache fragment::
{% load cache %}
{% cache 500 sidebar request.user.username %}
.. sidebar for logged in user ..
{% endcache %}
If you need more than one argument to identify the fragment that's fine, simply
pass as many arguments to ``{% cache %}`` as you need!
It's perfectly fine to specify more than one argument to identify the fragment.
Simply pass as many arguments to ``{% cache %}`` as you need.
The low-level cache API
=======================
@ -358,16 +370,16 @@ get() can take a ``default`` argument::
>>> cache.get('my_key', 'has expired')
'has expired'
To add a key only if it doesn't already exist, there is an add() method. It
takes the same parameters as set(), but will not attempt to update the cache
if the key specified is already present::
**New in Django development version:** To add a key only if it doesn't already
exist, use the ``add()`` method. It takes the same parameters as ``set()``, but
it will not attempt to update the cache if the key specified is already present::
>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'
There's also a get_many() interface that only hits the cache once. get_many()
There's also a ``get_many()`` interface that only hits the cache once. ``get_many()``
returns a dictionary with all the keys you asked for that actually exist in the
cache (and haven't expired)::
@ -566,7 +578,7 @@ the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
precedence, and the header values will be merged correctly.)
If you want to use headers to disable caching altogether,
``django.views.decorators.never_cache`` is a view decorator that adds
``django.views.decorators.cache.never_cache`` is a view decorator that adds
headers to ensure the response won't be cached by browsers or other caches. Example::
from django.views.decorators.cache import never_cache

View File

@ -56,7 +56,7 @@ would like to be able to things like this in our models (we assume the
We assign to and retrieve from the ``hand`` attribute in our model just like
any other Python class. The trick is to tell Django how to handle saving and
loading such an object
loading such an object.
In order to use the ``Hand`` class in our models, we **do not** have to change
this class at all. This is ideal, because it means you can easily write
@ -98,7 +98,7 @@ For our ``Hand`` example, we could convert the card data to a string of 104
characters by concatenating all the cards together in a pre-determined order.
Say, all the *north* cards first, then the *east*, *south* and *west* cards, in
that order. So ``Hand`` objects can be saved to text or character columns in
the database
the database.
What does a field class do?
---------------------------
@ -233,9 +233,9 @@ sure your field subclass uses ``django.db.models.SubfieldBase`` as its
metaclass. This ensures that the ``to_python()`` method, documented below_,
will always be called when the attribute is initialised.
Our ``HandleField`` class now looks like this::
Our ``HandField`` class now looks like this::
class HandleField(models.Field):
class HandField(models.Field):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
@ -549,7 +549,7 @@ we can reuse some existing conversion code::
Some general advice
--------------------
Writing a custom field can be a tricky process sometime, particularly if you
Writing a custom field can be a tricky process sometimes, particularly if you
are doing complex conversions between your Python types and your database and
serialization formats. A couple of tips to make things go more smoothly:

View File

@ -172,22 +172,32 @@ storage engine, you have a couple of options.
.. _AlterModelOnSyncDB: http://code.djangoproject.com/wiki/AlterModelOnSyncDB
Oracle Notes
Oracle notes
============
Django supports `Oracle Database Server`_ versions 9i and higher. Oracle
Django supports `Oracle Database Server`_ versions 9i and higher. Oracle
version 10g or later is required to use Django's ``regex`` and ``iregex`` query
operators. You will also need the `cx_Oracle`_ driver, version 4.3.1 or newer.
operators. You will also need the `cx_Oracle`_ driver, version 4.3.1 or newer.
.. _`Oracle Database Server`: http://www.oracle.com/
.. _`cx_Oracle`: http://cx-oracle.sourceforge.net/
To run ``python manage.py syncdb``, you'll need to create an Oracle database
user with CREATE TABLE, CREATE SEQUENCE, CREATE PROCEDURE, and CREATE TRIGGER
privileges. To run Django's test suite, the user also needs
CREATE and DROP DATABASE and CREATE and DROP TABLESPACE privileges.
In order for the ``python manage.py syncdb`` command to work, your Oracle
database user must have privileges to run the following commands:
Connecting to the Database
* CREATE TABLE
* CREATE SEQUENCE
* CREATE PROCEDURE
* CREATE TRIGGER
To run Django's test suite, the user needs these *additional* privileges:
* CREATE DATABASE
* DROP DATABASE
* CREATE TABLESPACE
* DROP TABLESPACE
Connecting to the database
--------------------------
Your Django settings.py file should look something like this for Oracle::
@ -213,29 +223,29 @@ and ``DATABASE_PORT`` like so::
You should supply both ``DATABASE_HOST`` and ``DATABASE_PORT``, or leave both
as empty strings.
Tablespace Options
Tablespace options
------------------
A common paradigm for optimizing performance in Oracle-based systems is the
use of `tablespaces`_ to organize disk layout. The Oracle backend supports
this use case by adding ``db_tablespace`` options to the ``Meta`` and
``Field`` classes. (When using a backend that lacks support for tablespaces,
these options are ignored.)
``Field`` classes. (When you use a backend that lacks support for tablespaces,
Django ignores these options.)
.. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
A tablespace can be specified for the table(s) generated by a model by
supplying the ``db_tablespace`` option inside the model's ``Meta`` class.
Additionally, the ``db_tablespace`` option can be passed to a ``Field``
supplying the ``db_tablespace`` option inside the model's ``class Meta``.
Additionally, you can pass the ``db_tablespace`` option to a ``Field``
constructor to specify an alternate tablespace for the ``Field``'s column
index. If no index would be created for the column, the ``db_tablespace``
index. If no index would be created for the column, the ``db_tablespace``
option is ignored.
::
class TablespaceExample(models.Model):
name = models.CharField(maxlength=30, db_index=True, db_tablespace="indexes")
data = models.CharField(maxlength=255, db_index=True)
name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
data = models.CharField(max_length=255, db_index=True)
edges = models.ManyToManyField(to="self", db_tablespace="indexes")
class Meta:
@ -243,46 +253,46 @@ option is ignored.
In this example, the tables generated by the ``TablespaceExample`` model
(i.e., the model table and the many-to-many table) would be stored in the
``tables`` tablespace. The index for the name field and the indexes on the
many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
``tables`` tablespace. The index for the name field and the indexes on the
many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
field would also generate an index, but no tablespace for it is specified, so
it would be stored in the model tablespace ``tables`` by default.
Django does not create the tablespaces for you. Please refer to `Oracle's
Django does not create the tablespaces for you. Please refer to `Oracle's
documentation`_ for details on creating and managing tablespaces.
.. _`Oracle's documentation`: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7003.htm#SQLRF01403
Naming Issues
Naming issues
-------------
Oracle imposes a name length limit of 30 characters. To accommodate this, the
Oracle imposes a name length limit of 30 characters. To accommodate this, the
backend truncates database identifiers to fit, replacing the final four
characters of the truncated name with a repeatable MD5 hash value.
NULL and Empty Strings
NULL and empty strings
----------------------
Django generally prefers to use the empty string ('') rather than NULL, but
Oracle treats both identically. To get around this, the Oracle backend
Oracle treats both identically. To get around this, the Oracle backend
coerces the ``null=True`` option on fields that permit the empty string as a
value. When fetching from the database, it is assumed that a NULL value in
value. When fetching from the database, it is assumed that a NULL value in
one of these fields really means the empty string, and the data is silently
converted to reflect this assumption.
TextField Limitations
---------------------
``TextField`` limitations
-------------------------
The Oracle backend stores ``TextFields`` as ``NCLOB`` columns. Oracle imposes
The Oracle backend stores ``TextFields`` as ``NCLOB`` columns. Oracle imposes
some limitations on the usage of such LOB columns in general:
* LOB columns may not be used as primary keys.
* LOB columns may not be used in indexes.
* LOB columns may not be used in a ``SELECT DISTINCT`` list. This means that
* LOB columns may not be used in a ``SELECT DISTINCT`` list. This means that
attempting to use the ``QuerySet.distinct`` method on a model that
includes ``TextField`` columns will result in an error when run against
Oracle. A workaround to this is to keep ``TextField`` columns out of any
models that you foresee performing ``.distinct`` queries on, and to
Oracle. A workaround to this is to keep ``TextField`` columns out of any
models that you foresee performing ``distinct()`` queries on, and to
include the ``TextField`` in a related model instead.

View File

@ -184,9 +184,9 @@ is being executed as an unattended, automated script.
Use ``--verbosity`` to specify the amount of notification and debug information
that ``django-admin.py`` should print to the console.
* ``0`` means no input.
* ``1`` means normal input (default).
* ``2`` means verbose input.
* ``0`` means no output.
* ``1`` means normal output (default).
* ``2`` means verbose output.
Example usage::
@ -651,7 +651,7 @@ To run the test server on port 7000 with ``fixture1`` and ``fixture2``::
that it doesn't matter whether the options come before or after the fixture
arguments.)
To run on 1.2.3.4:7000 with a `test` fixture::
To run on 1.2.3.4:7000 with a ``test`` fixture::
django-admin.py testserver --addrport 1.2.3.4:7000 test

View File

@ -113,3 +113,10 @@ Here's a sample ``flatpages/default.html`` template::
{{ flatpage.content }}
</body>
</html>
Since you're already entering raw HTML into the admin page for a flatpage,
both ``flatpage.title`` and ``flatpage.content`` are marked as **not**
requiring `automatic HTML escaping`_ in the template.
.. _automatic HTML escaping: ../templates/#automatic-html-escaping

View File

@ -461,8 +461,8 @@ otherwise, they'll be tacked together without whitespace!
you'll be using to edit the content. Due to the way the ``gettext`` tools
work internally and because we want to allow non-ASCII source strings in
Django's core and your applications, you **must** use UTF-8 as the encoding
for your PO file (this means that everybody will be using the same
encoding, which is important when Django processes the PO files).
for your PO file. This means that everybody will be using the same
encoding, which is important when Django processes the PO files.
To reexamine all source code and templates for new translation strings and
update all message files for **all** languages, run this::
@ -658,7 +658,7 @@ message file. The choice is yours.
of the settings file to determine this, and a settings file doesn't exist
if you're manually configuring your settings.)
.. _settings documentation: ../settings/#using-settings-without-the-django-settings-module-environment-variable
.. _settings documentation: ../settings/#using-settings-without-setting-django-settings-module
All message file repositories are structured the same way. They are:

View File

@ -187,10 +187,10 @@ latest bug fixes and improvements, follow these instructions:
"Where are my ``site-packages`` stored?" section above.)
Alternatively, you can define your ``PYTHONPATH`` environment variable
so that it includes the ``django`` subdirectory of ``django-trunk``.
This is perhaps the most convenient solution on Windows systems, which
don't support symbolic links. (Environment variables can be defined on
Windows systems `from the Control Panel`_.)
so that it includes the ``django-trunk`` directory. This is perhaps the
most convenient solution on Windows systems, which don't support symbolic
links. (Environment variables can be defined on Windows systems `from the
Control Panel`_.)
.. admonition:: What about Apache and mod_python?
@ -204,11 +204,18 @@ latest bug fixes and improvements, follow these instructions:
.. _How to use Django with mod_python: ../modpython/
4. Copy the file ``django-trunk/django/bin/django-admin.py`` to somewhere on
your system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
(Windows). This step simply lets you type ``django-admin.py`` from within
any directory, rather than having to qualify the command with the full path
to the file.
4. On Unix-like systems, create a symbolic link to the file
``django-trunk/django/bin/django-admin.py`` in a directory on your system
path, such as ``/usr/local/bin``. For example::
ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin
This simply lets you type ``django-admin.py`` from within any directory,
rather than having to qualify the command with the full path to the file.
On Windows systems, the same result can be achieved by copying the file
``django-trunk/django/bin/django-admin.py`` to somewhere on your system
path, for example ``C:\Python24\Scripts``.
You *don't* have to run ``python setup.py install``, because you've already
carried out the equivalent actions in steps 3 and 4.

View File

@ -104,8 +104,7 @@ Handles conditional GET operations. If the response has a ``ETag`` or
``Last-Modified`` header, and the request has ``If-None-Match`` or
``If-Modified-Since``, the response is replaced by an HttpNotModified.
Also removes the content from any response to a HEAD request and sets the
``Date`` and ``Content-Length`` response-headers.
Also sets the ``Date`` and ``Content-Length`` response-headers.
django.middleware.http.SetRemoteAddrFromForwardedFor
----------------------------------------------------

View File

@ -50,7 +50,7 @@ The above ``Person`` model would create a database table like this::
Some technical notes:
* The name of the table, ``myapp_person``, is automatically derived from
some model metadata but can be overridden. See _`Table names` below.
some model metadata but can be overridden. See `Table names`_ below.
* An ``id`` field is added automatically, but this behavior can be
overriden. See `Automatic primary key fields`_ below.
* The ``CREATE TABLE`` SQL in this example is formatted using PostgreSQL
@ -1664,7 +1664,7 @@ Adding extra Manager methods
Adding extra ``Manager`` methods is the preferred way to add "table-level"
functionality to your models. (For "row-level" functionality -- i.e., functions
that act on a single instance of a model object -- use _`Model methods`, not
that act on a single instance of a model object -- use `Model methods`_, not
custom ``Manager`` methods.)
A custom ``Manager`` method can return anything you want. It doesn't have to

View File

@ -89,18 +89,17 @@ path.
.. note::
If you're using Windows, it is still recommended that you use forward
slashes in the pathnames, even though Windows normally uses backslashes
for its native separator. Apache knows how to convert from the forward
slash format to the native format, so this approach is portable and easier
to read (it avoids tricky problems with having to double-escape
backslashes).
If you're using Windows, we still recommended that you use forward
slashes in the pathnames, even though Windows normally uses the backslash
character as its native separator. Apache knows how to convert from the
forward slash format to the native format, so this approach is portable and
easier to read. (It avoids tricky problems with having to double-escape
backslashes.)
This is valid even on a Windows system::
PythonPath "['c:/path/to/project'] + sys.path"
You can also add directives such as ``PythonAutoReload Off`` for performance.
See the `mod_python documentation`_ for a full list of options.

View File

@ -753,6 +753,30 @@ For example::
</ul>
</form>
Highlighting required fields in templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You may wish to show a visitor which fields are required. Here is the above
example modified to insert an asterix after the label of each required field::
<form method="post" action="">
<dl>
{% for field in form %}
<dt>{{ field.label_tag }}{{ field.label }}{% if field.field.required %}*{% endif %}</dt>
<dd>{{ field }}</dd>
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
{% endfor %}
</dl>
<input type="submit" />
</form>
The ``{% if field.field.required %}*{% endif %}`` fragment is the relevant
addition here. It adds the asterix only if the field is required. Note that we
check ``field.field.required`` and not ``field.required``. In the template,
``field`` is a ``newforms.forms.BoundField`` instance, which holds the actual
``Field`` instance in its ``field`` attribute.
Binding uploaded files to a form
--------------------------------
@ -860,12 +884,11 @@ classes::
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>
Prefixes for forms
------------------
You can put several Django forms inside one ``<form>`` tag. To give each
``Form`` its own namespace you need to use the ``prefix`` keyword argument::
``Form`` its own namespace, use the ``prefix`` keyword argument::
>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
@ -876,7 +899,6 @@ You can put several Django forms inside one ``<form>`` tag. To give each
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
Fields
======
@ -1849,7 +1871,11 @@ In addition, each generated form field has attributes set as follows:
* If the model field has ``choices`` set, then the form field's ``widget``
will be set to ``Select``, with choices coming from the model field's
``choices``.
``choices``. The choices will normally include the blank choice which is
selected by default. If the field is required, this forces the user to
make a selection. The blank choice will not be included if the model
field has ``blank=False`` and an explicit ``default`` value (the
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
field. See "Overriding the default field types" below.
@ -2095,10 +2121,14 @@ instance instead of a model class::
# Instantiate the form.
>>> f = AuthorForm()
When a form created by ``form_for_instance()`` is created, the initial
data values for the form fields are drawn from the instance. However,
this data is not bound to the form. You will need to bind data to the
form before the form can be saved.
When a form created by ``form_for_instance()`` is created, the initial data
values for the form fields are drawn from the instance. However, this data is
not bound to the form. You will need to bind data to the form before the form
can be saved.
Unlike ``form_for_model()``, a choice field in form created by
``form_for_instance()`` will not include the blank choice if the respective
model field has ``blank=False``. The initial choice is drawn from the instance.
When you call ``save()`` on a form created by ``form_for_instance()``,
the database instance will be updated. As in ``form_for_model()``, ``save()``

View File

@ -44,7 +44,7 @@ to this::
DATABASE_ENGINE = "mysql_old"
However, we strongly encourage MySQL users to upgrade to a more recent
version of `MySQLdb` as soon as possible, The "mysql_old" backend is
version of ``MySQLdb`` as soon as possible, The "mysql_old" backend is
provided only to ease this transition, and is considered deprecated;
aside from any necessary security fixes, it will not be actively
maintained, and it will be removed in a future release of Django.

View File

@ -583,7 +583,7 @@ LOCALE_PATHS
Default: ``()`` (Empty tuple)
A list of directories where Django looks for translation files.
A tuple of directories where Django looks for translation files.
See the `internationalization docs section`_ explaining the variable and the
default behavior.
@ -791,10 +791,12 @@ SESSION_COOKIE_PATH
Default: ``'/'``
The path set on the session cookie. Should match the URL path of your Django
installation (or be parent of that path). This is useful if you have multiple
Django instances running under the same hostname; they can use different
cookie paths and each instance will only see its own session cookie.
The path set on the session cookie. This should either match the URL path of your
Django installation or be parent of that path.
This is useful if you have multiple Django instances running under the same
hostname. They can use different cookie paths, and each instance will only see
its own session cookie.
SESSION_COOKIE_SECURE
---------------------

View File

@ -201,6 +201,8 @@ the feed.
An example makes this clear. Here's the code for these beat-specific feeds::
from django.contrib.syndication import FeedDoesNotExist
class BeatFeed(Feed):
def get_object(self, bits):
# In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter,
@ -213,6 +215,8 @@ An example makes this clear. Here's the code for these beat-specific feeds::
return "Chicagocrime.org: Crimes for beat %s" % obj.beat
def link(self, obj):
if not obj:
raise FeedDoesNotExist
return obj.get_absolute_url()
def description(self, obj):
@ -246,11 +250,18 @@ request to the URL ``/rss/beats/0613/``:
each of ``title``, ``link`` and ``description``, Django follows this
algorithm:
* First, it tries to call a method, passing the ``obj`` argument, where
``obj`` is the object returned by ``get_object()``.
* First, it tries to call a method, passing the ``obj`` argument,
where ``obj`` is the object returned by ``get_object()``.
* Failing that, it tries to call a method with no arguments.
* Failing that, it uses the class attribute.
Inside the ``link()`` method, we handle the possibility that ``obj``
might be ``None``, which can occur when the URL isn't fully specified. In
some cases, you might want to do something else in this case, which would
mean you'd need to check for ``obj`` existing in other methods as well
(the ``link()`` method is called very early in the feed generation
process, so is a good place to bail out early).
* Finally, note that ``items()`` in this example also takes the ``obj``
argument. The algorithm for ``items`` is the same as described in the
previous step -- first, it tries ``items(obj)``, then ``items()``, then
@ -553,15 +564,15 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
def ttl(self, obj):
"""
Takes the object returned by get_object() and returns the feed's
TTL (Time to live) as a normal Python string.
TTL (Time To Live) as a normal Python string.
"""
def ttl(self):
"""
Returns the feed's ttl as a normal Python string.
Returns the feed's TTL as a normal Python string.
"""
ttl = 600 # Hard-coded Time to live.
ttl = 600 # Hard-coded Time To Live.
# ITEMS -- One of the following three is required. The framework looks
# for them in this order.

View File

@ -2,9 +2,11 @@
The Django template language: For template authors
==================================================
This document explains the language syntax of the Django template system. If
you're looking for a more technical perspective on how it works and how to
extend it, see `The Django template language: For Python programmers`_.
.. admonition:: About this document
This document explains the language syntax of the Django template system. If
you're looking for a more technical perspective on how it works and how to
extend it, see `The Django template language: For Python programmers`_.
Django's template language is designed to strike a balance between power and
ease. It's designed to feel comfortable to those used to working with HTML. If
@ -280,7 +282,9 @@ Here are some tips for working with inheritance:
* If you need to get the content of the block from the parent template,
the ``{{ block.super }}`` variable will do the trick. This is useful
if you want to add to the contents of a parent block instead of
completely overriding it.
completely overriding it. Data inserted using ``{{ block.super }}`` will
not be automatically escaped (see the `next section`_), since it was
already escaped, if necessary, in the parent template.
* For extra readability, you can optionally give a *name* to your
``{% endblock %}`` tag. For example::
@ -299,6 +303,8 @@ it also defines the content that fills the hole in the *parent*. If there were
two similarly-named ``{% block %}`` tags in a template, that template's parent
wouldn't know which one of the blocks' content to use.
.. _next section: #automatic-html-escaping
Automatic HTML escaping
=======================
@ -397,6 +403,32 @@ auto-escaping is on, these extra filters won't change the output -- any
variables that use the ``escape`` filter do not have further automatic
escaping applied to them.
String literals and automatic escaping
--------------------------------------
Sometimes you will pass a string literal as an argument to a filter. For
example::
{{ data|default:"This is a string literal." }}
All string literals are inserted **without** any automatic escaping into the
template, if they are used (it's as if they were all passed through the
``safe`` filter). The reasoning behind this is that the template author is in
control of what goes into the string literal, so they can make sure the text
is correctly escaped when the template is written.
This means you would write ::
{{ data|default:"3 &gt; 2" }}
...rather than ::
{{ data|default:"3 > 2" }} <-- Bad! Don't do this.
This doesn't affect what happens to data coming from the variable itself.
The variable's contents are still automatically escaped, if necessary, since
they're beyond the control of the template author.
Using the built-in reference
============================

View File

@ -755,61 +755,106 @@ inside the template code:
``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry
about these; they exist for the implementation of the ``escape`` filter.
Inside your filter, you will need to think about three areas in order to be
auto-escaping compliant:
When you are writing a filter, your code will typically fall into one of two
situations:
1. If your filter returns a string that is ready for direct output (it should
be considered a "safe" string), you should call
``django.utils.safestring.mark_safe()`` on the result prior to returning.
This will turn the result into the appropriate ``SafeData`` type. This is
often the case when you are returning raw HTML, for example.
1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``,
``'``, ``"`` or ``&``) into the result that were not already present. In
this case, you can let Django take care of all the auto-escaping handling
for you. All you need to do is put the ``is_safe`` attribute on your
filter function and set it to ``True``. This attribute tells Django that
is a "safe" string is passed into your filter, the result will still be
"safe" and if a non-safe string is passed in, Django will automatically
escape it, if necessary. The reason ``is_safe`` is necessary is because
there are plenty of normal string operations that will turn a ``SafeData``
object back into a normal ``str`` or ``unicode`` object and, rather than
try to catch them all, which would be very difficult, Django repairs the
damage after the filter has completed.
2. If your filter is given a "safe" string, is it guaranteed to return a
"safe" string? If so, set the ``is_safe`` attribute on the function to be
``True``. For example, a filter that replaced a word consisting only of
digits with the number spelt out in words is going to be
safe-string-preserving, since it cannot introduce any of the five dangerous
characters: <, >, ", ' or &. We can write::
For example, suppose you have a filter that adds the string ``xx`` to the
end of any input. Since this introduces no dangerous HTML characters into
the result (aside from any that were already present), you should mark
your filter with ``is_safe``::
@register.filter
def convert_to_words(value):
# ... implementation here ...
return result
def add_xx(value):
return '%sxx' % value
add_xx.is_safe = True
convert_to_words.is_safe = True
When this filter is used in a template where auto-escaping is enabled,
Django will escape the output whenever the input is not already marked as
"safe".
Note that this filter does not return a universally safe result (it does
not return ``mark_safe(result)``) because if it is handed a raw string such
as '<a>', this will need further escaping in an auto-escape environment.
The ``is_safe`` attribute only talks about the the result when a safe
string is passed into the filter.
By default, ``is_safe`` defaults to ``False`` and you can omit it from
any filters where it isn't required.
3. Will your filter behave differently depending upon whether auto-escaping
is currently in effect or not? This is normally a concern when you are
returning mixed content (HTML elements mixed with user-supplied content).
For example, the ``ordered_list`` filter that ships with Django needs to
know whether to escape its content or not. It will always return a safe
string. Since it returns raw HTML, we cannot apply escaping to the
result -- it needs to be done in-situ.
Be careful when deciding if your filter really does leave safe strings
as safe. Sometimes if you are *removing* characters, you can
inadvertently leave unbalanced HTML tags or entities in the result.
For example, removing a ``>`` from the input might turn ``<a>`` into
``<a``, which would need to be escaped on output to avoid causing
problems. Similarly, removing a semicolon (``;``) can turn ``&amp;``
into ``&amp``, which is no longer a valid entity and thus needs
further escaping. Most cases won't be nearly this tricky, but keep an
eye out for any problems like that when reviewing your code.
For these cases, the filter function needs to be told what the current
auto-escaping setting is. Set the ``needs_autoescape`` attribute on the
filter to ``True`` and have your function take an extra argument called
``autoescape`` with a default value of ``None``. When the filter is called,
the ``autoescape`` keyword argument will be ``True`` if auto-escaping is in
effect. For example, the ``unordered_list`` filter is written as::
2. Alternatively, your filter code can manually take care of any necessary
escaping. This is usually necessary when you are introducing new HTML
markup into the result. You want to mark the output as safe from further
escaping so that your HTML markup isn't escaped further, so you'll need to
handle the input yourself.
def unordered_list(value, autoescape=None):
# ... lots of code here ...
To mark the output as a safe string, use
``django.utils.safestring.mark_safe()``.
return mark_safe(...)
Be careful, though. You need to do more than just mark the output as
safe. You need to ensure it really *is* safe and what you do will often
depend upon whether or not auto-escaping is in effect. The idea is to
write filters than can operate in templates where auto-escaping is either
on or off in order to make things easier for your template authors.
unordered_list.is_safe = True
unordered_list.needs_autoescape = True
In order for you filter to know the current auto-escaping state, set the
``needs_autoescape`` attribute to ``True`` on your function (if you don't
specify this attribute, it defaults to ``False``). This attribute tells
Django that your filter function wants to be passed an extra keyword
argument, called ``autoescape`` that is ``True`` is auto-escaping is in
effect and ``False`` otherwise.
By default, both the ``is_safe`` and ``needs_autoescape`` attributes are
``False``. You do not need to specify them if ``False`` is an acceptable
value.
An example might make this clearer. Let's write a filter that emphasizes
the first character of a string::
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
def initial_letter_filter(text, autoescape=None):
first, other = text[0] ,text[1:]
if autoescape:
esc = conditional_escape
else:
esc = lambda x: x
result = '<strong>%s</strong>%s' % (esc(first), esc(other))
return mark_safe(result)
initial_letter_filter.needs_autoescape = True
The ``needs_autoescape`` attribute on the filter function and the
``autoescape`` keyword argument mean that our function will know whether
or not automatic escaping is in effect when the filter is called. We use
``autoescape`` to decide whether the input data needs to be passed through
``django.utils.html.conditional_escape`` or not (in the latter case, we
just use the identity function as the "escape" function). The
``conditional_escape()`` function is like ``escape()`` except it only
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
instance is passed to ``conditional_escape()``, the data is returned
unchanged.
Finally, in the above example, we remember to mark the result as safe
so that our HTML is inserted directly into the template without further
escaping.
There is no need to worry about the ``is_safe`` attribute in this case
(although including it wouldn't hurt anything). Whenever you are manually
handling the auto-escaping issues and returning a safe string, the
``is_safe`` attribute won't change anything either way.
Writing custom template tags
----------------------------
@ -932,7 +977,9 @@ without having to be parsed multiple times.
Auto-escaping considerations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The output from template tags is not automatically run through the
**New in Django development version**
The output from template tags is **not** automatically run through the
auto-escaping filters. However, there are still a couple of things you should
keep in mind when writing a template tag:
@ -1136,7 +1183,7 @@ on the object being edited -- so they're a perfect case for using a small
template that is filled with details from the current object. (In the admin's
case, this is the ``submit_row`` tag.)
These sorts of tags are called `inclusion tags`.
These sorts of tags are called "inclusion tags".
Writing inclusion tags is probably best demonstrated by example. Let's write a
tag that outputs a list of choices for a given ``Poll`` object, such as was

View File

@ -47,7 +47,7 @@ will create a ``mysite`` directory in your current directory.
denied" when you try to run ``django-admin.py startproject``. This
is because, on Unix-based systems like OS X, a file must be marked
as "executable" before it can be run as a program. To do this, open
Terminal.app and navigate (using the `cd` command) to the directory
Terminal.app and navigate (using the ``cd`` command) to the directory
where ``django-admin.py`` is installed, then run the command
``chmod +x django-admin.py``.

View File

@ -136,7 +136,7 @@ for converting back and forth between Unicode and bytestrings.
* ``smart_str(s, encoding='utf-8', strings_only=False, errors='strict')``
is essentially the opposite of ``smart_unicode()``. It forces the first
argument to a bytestring. The ``strings_only`` parameter has the same
behaviour as for ``smart_unicode()`` and ``force_unicode()``. This is
behavior as for ``smart_unicode()`` and ``force_unicode()``. This is
slightly different semantics from Python's builtin ``str()`` function,
but the difference is needed in a few places within Django's internals.

View File

@ -237,7 +237,7 @@ include
-------
A function that takes a full Python import path to another URLconf that should
be "included" in this place. See _`Including other URLconfs` below.
be "included" in this place. See `Including other URLconfs`_ below.
Notes on capturing text in URLs
===============================

View File

@ -103,4 +103,14 @@ TypeError: Invalid lookup type: 'lt'
>>> obj = list(serializers.deserialize("json", stream))[0]
>>> obj.object == m
True
# Test retrieving custom field data
>>> m.delete()
>>> m1 = MyModel(name="1", data=Small(1, 2))
>>> m1.save()
>>> m2 = MyModel(name="2", data=Small(2, 3))
>>> m2.save()
>>> for m in MyModel.objects.all(): print unicode(m.data)
12
23
"""}

View File

@ -30,6 +30,23 @@ ARTICLE_STATUS = (
(3, 'Live'),
)
STEERING_TYPE = (
('left', 'Left steering wheel'),
('right', 'Right steering wheel'),
)
FUEL_TYPE = (
('gas', 'Gasoline'),
('diesel', 'Diesel'),
('other', 'Other'),
)
TRANSMISSION_TYPE = (
('at', 'Automatic'),
('mt', 'Manual'),
('cvt', 'CVT'),
)
class Category(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=20)
@ -70,6 +87,12 @@ class PhoneNumber(models.Model):
def __unicode__(self):
return self.phone
class Car(models.Model):
name = models.CharField(max_length=50)
steering = models.CharField(max_length=5, choices=STEERING_TYPE, default='left')
fuel = models.CharField(max_length=10, choices=FUEL_TYPE)
transmission = models.CharField(max_length=3, choices=TRANSMISSION_TYPE, blank=True, help_text='Leave empty if not applicable.')
__test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
>>> import datetime
@ -592,4 +615,54 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
True
>>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'}
# form_for_* blank choices ####################################################
Show the form for a new Car. Note that steering field doesn't include the blank choice,
because the field is obligatory and has an explicit default.
>>> CarForm = form_for_model(Car)
>>> f = CarForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left" selected="selected">Left steering wheel</option>
<option value="right">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="" selected="selected">---------</option>
<option value="gas">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="" selected="selected">---------</option>
<option value="at">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
Create a Car, and display the form for modifying it. Note that now the fuel
selector doesn't include the blank choice as well, since the field is
obligatory and can not be changed to be blank.
>>> honda = Car(name='Honda Accord Wagon', steering='right', fuel='gas', transmission='at')
>>> honda.save()
>>> HondaForm = form_for_instance(honda)
>>> f = HondaForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Honda Accord Wagon" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left">Left steering wheel</option>
<option value="right" selected="selected">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="gas" selected="selected">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="">---------</option>
<option value="at" selected="selected">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
"""}

View File

@ -78,7 +78,8 @@ True
>>> paginator.pages
2
# The paginator can provide a list of all available pages
# The paginator can provide a list of all available pages.
>>> paginator = ObjectPaginator(Article.objects.all(), 10)
>>> paginator.page_range
[1, 2]
"""}

View File

@ -3,9 +3,12 @@
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
from django.core.cache import cache
import time, unittest
from django.core.cache import cache
from django.utils.cache import patch_vary_headers
from django.http import HttpResponse
# functions/classes for complex data type tests
def f():
return 42
@ -87,5 +90,30 @@ class Cache(unittest.TestCase):
cache.set(key, value)
self.assertEqual(cache.get(key), value)
class CacheUtils(unittest.TestCase):
"""TestCase for django.utils.cache functions."""
def test_patch_vary_headers(self):
headers = (
# Initial vary, new headers, resulting vary.
(None, ('Accept-Encoding',), 'Accept-Encoding'),
('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
(None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
)
for initial_vary, newheaders, resulting_vary in headers:
response = HttpResponse()
if initial_vary is not None:
response['Vary'] = initial_vary
patch_vary_headers(response, newheaders)
self.assertEqual(response['Vary'], resulting_vary)
if __name__ == '__main__':
unittest.main()

View File

@ -25,11 +25,23 @@
>>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
>>> d['name']
'Simon'
>>> d.get('name')
'Simon'
>>> d.getlist('name')
['Adrian', 'Simon']
>>> d['lastname']
Traceback (most recent call last):
...
MultiValueDictKeyError: "Key 'lastname' not found in <MultiValueDict: {'position': ['Developer'], 'name': ['Adrian', 'Simon']}>"
>>> d.get('lastname')
>>> d.get('lastname', 'nonexistent')
'nonexistent'
>>> d.getlist('lastname')
[]
>>> d.setlist('lastname', ['Holovaty', 'Willison'])
>>> d.getlist('lastname')
['Holovaty', 'Willison']
### SortedDict #################################################################

View File

@ -66,6 +66,9 @@ u'1979 189 CET'
>>> format(my_birthday, r'jS o\f F')
u'8th of July'
>>> format(the_future, r'Y')
u'2100'
"""
from django.utils import dateformat, translation
@ -84,3 +87,4 @@ except AttributeError:
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
summertime = datetime.datetime(2005, 10, 30, 1, 00)
wintertime = datetime.datetime(2005, 10, 30, 4, 00)
the_future = datetime.datetime(2100, 10, 25, 0, 00)

View File

@ -37,6 +37,8 @@ u''
u'13.1031'
>>> floatformat(u'foo', u'bar')
u''
>>> floatformat(None)
u''
>>> addslashes(u'"double quotes" and \'single quotes\'')
u'\\"double quotes\\" and \\\'single quotes\\\''

View File

@ -312,4 +312,49 @@ ValidationError: [u'REQUIRED']
Traceback (most recent call last):
...
ValidationError: [u'INVALID IP ADDRESS']
###############################################################################
# Create choices for the model choice field tests below.
>>> from regressiontests.forms.models import ChoiceModel
>>> ChoiceModel.objects.create(pk=1, name='a')
<ChoiceModel: ChoiceModel object>
>>> ChoiceModel.objects.create(pk=2, name='b')
<ChoiceModel: ChoiceModel object>
>>> ChoiceModel.objects.create(pk=3, name='c')
<ChoiceModel: ChoiceModel object>
# ModelChoiceField ############################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = 'INVALID CHOICE'
>>> f = ModelChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('4')
Traceback (most recent call last):
...
ValidationError: [u'INVALID CHOICE']
# ModelMultipleChoiceField ####################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = '%s IS INVALID CHOICE'
>>> e['list'] = 'NOT A LIST OF VALUES'
>>> f = ModelMultipleChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('3')
Traceback (most recent call last):
...
ValidationError: [u'NOT A LIST OF VALUES']
>>> f.clean(['4'])
Traceback (most recent call last):
...
ValidationError: [u'4 IS INVALID CHOICE']
"""

View File

@ -323,6 +323,10 @@ Decimal("3.14")
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean(u'łąść')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean('1.0 ')
Decimal("1.0")
>>> f.clean(' 1.0')
@ -914,6 +918,11 @@ False
>>> f.clean('Django rocks')
True
>>> f.clean('True')
True
>>> f.clean('False')
False
>>> f = BooleanField(required=False)
>>> f.clean('')
False
@ -930,6 +939,11 @@ False
>>> f.clean('Django rocks')
True
A form's BooleanField with a hidden widget will output the string 'False', so
that should clean to the boolean value False:
>>> f.clean('False')
False
# ChoiceField #################################################################
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])

View File

@ -147,6 +147,10 @@ u'BC'
u'NS'
>>> f.clean(' manitoba ')
u'MB'
>>> f.clean(' new brunswick ')
u'NB'
>>> f.clean('NB')
u'NB'
>>> f.clean('T2S 2H7')
Traceback (most recent call last):
...

View File

@ -10,6 +10,10 @@ class Defaults(models.Model):
def_date = models.DateField(default = datetime.date(1980, 1, 1))
value = models.IntegerField(default=42)
class ChoiceModel(models.Model):
"""For ModelChoiceField and ModelMultipleChoiceField tests."""
name = models.CharField(max_length=10)
__test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance

View File

@ -2,6 +2,7 @@
tests = r"""
>>> from django.newforms import *
>>> from django.newforms.widgets import RadioFieldRenderer
>>> from django.utils.safestring import mark_safe
>>> import datetime
>>> import time
>>> import re
@ -128,6 +129,13 @@ u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u
>>> w.render('email', '', attrs={'class': 'special'})
u'<input type="hidden" class="special" name="email" />'
Boolean values are rendered to their string forms ("True" and "False").
>>> w = HiddenInput()
>>> w.render('get_spam', False)
u'<input type="hidden" name="get_spam" value="False" />'
>>> w.render('get_spam', True)
u'<input type="hidden" name="get_spam" value="True" />'
# MultipleHiddenInput Widget ##################################################
>>> w = MultipleHiddenInput()
@ -205,6 +213,8 @@ u'<textarea rows="10" cols="40" name="msg"></textarea>'
u'<textarea rows="10" cols="40" name="msg">value</textarea>'
>>> w.render('msg', 'some "quoted" & ampersanded value')
u'<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>'
>>> w.render('msg', mark_safe('pre &quot;quoted&quot; value'))
u'<textarea rows="10" cols="40" name="msg">pre &quot;quoted&quot; value</textarea>'
>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>'
@ -375,6 +385,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<option value="5">5</option>
</select>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<select name="escape">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="bad">you &amp; me</option>
<option value="good">you &gt; me</option>
</select>
# Unicode choices are correctly rendered as HTML
>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
@ -538,6 +559,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<option value="5">5</option>
</select>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<select multiple="multiple" name="escape">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="bad">you &amp; me</option>
<option value="good">you &gt; me</option>
</select>
# Unicode choices are correctly rendered as HTML
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
@ -663,6 +695,16 @@ You can create your own custom renderers for RadioSelect to use.
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
Or you can use custom RadioSelect fields that use your custom renderer.
>>> class CustomRadioSelect(RadioSelect):
... renderer = MyRenderer
>>> w = CustomRadioSelect()
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
<label><input type="radio" name="beatle" value="J" /> John</label><br />
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
A RadioFieldRenderer object also allows index access to individual RadioInput
objects.
>>> w = RadioSelect()
@ -682,6 +724,14 @@ Traceback (most recent call last):
...
IndexError: list index out of range
# Choices are escaped correctly
>>> w = RadioSelect()
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<ul>
<li><label><input type="radio" name="escape" value="bad" /> you &amp; me</label></li>
<li><label><input type="radio" name="escape" value="good" /> you &gt; me</label></li>
</ul>
# Unicode choices are correctly rendered as HTML
>>> w = RadioSelect()
>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
@ -811,6 +861,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
</ul>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<ul>
<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
<li><label><input type="checkbox" name="escape" value="bad" /> you &amp; me</label></li>
<li><label><input type="checkbox" name="escape" value="good" /> you &gt; me</label></li>
</ul>
# Unicode choices are correctly rendered as HTML
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'

View File

@ -4,7 +4,7 @@ import misc
regressions = ur"""
Format string interpolation should work with *_lazy objects.
>>> from django.utils.translation import ugettext_lazy, activate, deactivate, gettext_lazy
>>> from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy
>>> s = ugettext_lazy('Add %(name)s')
>>> d = {'name': 'Ringo'}
>>> s % d
@ -39,6 +39,18 @@ unicode(string_concat(...)) should not raise a TypeError - #4796
<module 'django.utils.translation' from ...>
>>> unicode(django.utils.translation.string_concat("dja", "ngo"))
u'django'
Translating a string requiring no auto-escaping shouldn't change the "safe"
status.
>>> from django.utils.safestring import mark_safe
>>> s = mark_safe('Password')
>>> type(s)
<class 'django.utils.safestring.SafeString'>
>>> activate('de')
>>> type(ugettext(s))
<class 'django.utils.safestring.SafeUnicode'>
>>> deactivate()
"""
__test__ = {

View File

@ -12,6 +12,15 @@ from datetime import datetime, timedelta
from django.utils.tzinfo import LocalTimezone
from django.utils.safestring import mark_safe
# These two classes are used to test auto-escaping of __unicode__ output.
class UnsafeClass:
def __unicode__(self):
return u'you & me'
class SafeClass:
def __unicode__(self):
return mark_safe(u'you &gt; me')
# RESULT SYNTAX --
# 'template_name': ('template contents', 'context dict',
# 'expected string output' or Exception class)
@ -94,6 +103,11 @@ def get_filter_tests():
'filter-urlize03': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
'filter-urlize04': ('{{ a|urlize }}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
# This will lead to a nonsense result, but at least it won't be
# exploitable for XSS purposes when auto-escaping is on.
'filter-urlize05': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": "<script>alert('foo')</script>"}, "<script>alert('foo')</script>"),
'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;'),
'filter-urlizetrunc01': ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}', {"a": "http://example.com/x=&y=", "b": mark_safe("http://example.com?x=&y=")}, u'<a href="http://example.com/x=&y=" rel="nofollow">http:...</a> <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
'filter-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": "http://example.com/x=&y=", "b": mark_safe("http://example.com?x=&y=")}, u'<a href="http://example.com/x=&y=" rel="nofollow">http:...</a> <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
@ -177,23 +191,28 @@ def get_filter_tests():
'filter-unordered_list04': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
'filter-unordered_list05': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
# If the input to "default" filter is marked as safe, then so is the
# output. However, if the default arg is used, auto-escaping kicks in
# (if enabled), because we cannot mark the default as safe.
# Literal string arguments to the default filter are always treated as
# safe strings, regardless of the auto-escaping state.
#
# Note: we have to use {"a": ""} here, otherwise the invalid template
# variable string interferes with the test result.
'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x&lt;"),
'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
'filter-default02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
'filter-default03': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
'filter-default04': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": mark_safe("x>")}, "x>"),
'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x&lt;"),
'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x<"),
'filter-default_if_none02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),
'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "<1-800-2255-63> <1-800-2255-63>"),
# Ensure iriencode keeps safe strings:
'filter-iriencode01': ('{{ url|iriencode }}', {'url': '?test=1&me=2'}, '?test=1&amp;me=2'),
'filter-iriencode02': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': '?test=1&me=2'}, '?test=1&me=2'),
'filter-iriencode03': ('{{ url|iriencode }}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
'filter-iriencode04': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
# Chaining a bunch of safeness-preserving filters should not alter
# the safe status either way.
'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),
@ -209,12 +228,19 @@ def get_filter_tests():
# Force to safe, then back (also showing why using force_escape too
# early in a chain can lead to unexpected results).
'chaining07': ('{{ a|force_escape|cut:"b" }}', {"a": "a < b"}, "a &lt; "),
'chaining08': ('{% autoescape off %}{{ a|force_escape|cut:"b" }}{% endautoescape %}', {"a": "a < b"}, "a &lt; "),
'chaining09': ('{{ a|cut:"b"|force_escape }}', {"a": "a < b"}, "a &lt; "),
'chaining10': ('{% autoescape off %}{{ a|cut:"b"|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; "),
'chaining07': ('{{ a|force_escape|cut:";" }}', {"a": "a < b"}, "a &amp;lt b"),
'chaining08': ('{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}', {"a": "a < b"}, "a &lt b"),
'chaining09': ('{{ a|cut:";"|force_escape }}', {"a": "a < b"}, "a &lt; b"),
'chaining10': ('{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
'chaining11': ('{{ a|cut:"b"|safe }}', {"a": "a < b"}, "a < "),
'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a &lt; b"),
'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
# Filters decorated with stringfilter still respect is_safe.
'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You &amp; me'),
'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You &gt; me'),
'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You &gt; me'),
}

View File

@ -268,6 +268,12 @@ class Templates(unittest.TestCase):
# Embedded newlines make it not-a-tag.
'basic-syntax24': ("{{ moo\n }}", {}, "{{ moo\n }}"),
# Literal strings are permitted inside variables, mostly for i18n
# purposes.
'basic-syntax25': ('{{ "fred" }}', {}, "fred"),
'basic-syntax26': (r'{{ "\"fred\"" }}', {}, "\"fred\""),
'basic-syntax27': (r'{{ _("\"fred\"") }}', {}, "\"fred\""),
# List-index syntax allows a template to access a certain item of a subscriptable object.
'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),
@ -318,9 +324,9 @@ class Templates(unittest.TestCase):
# Chained filters, with an argument to the first one
'filter-syntax09': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"),
# Escaped string as argument
# Literal string as argument is always "safe" from auto-escaping..
'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}',
{"var": None}, ' endquote&quot; hah'),
{"var": None}, ' endquote" hah'),
# Variable as argument
'filter-syntax11': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'),
@ -617,7 +623,7 @@ class Templates(unittest.TestCase):
### INHERITANCE ###########################################################
# Standard template with no inheritance
'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),
'inheritance01': ("1{% block first %}&{% endblock %}3{% block second %}_{% endblock %}", {}, '1&3_'),
# Standard two-level inheritance
'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
@ -626,7 +632,7 @@ class Templates(unittest.TestCase):
'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'),
# Two-level with no redefinitions on second level
'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'),
'inheritance04': ("{% extends 'inheritance01' %}", {}, '1&3_'),
# Two-level with double quotes instead of single quotes
'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'),
@ -635,16 +641,16 @@ class Templates(unittest.TestCase):
'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'),
# Two-level with one block defined, one block not defined
'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'),
'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1&35'),
# Three-level with one block defined on this level, two blocks defined next level
'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'),
# Three-level with second and third levels blank
'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'),
'inheritance09': ("{% extends 'inheritance04' %}", {}, '1&3_'),
# Three-level with space NOT in a block -- should be ignored
'inheritance10': ("{% extends 'inheritance04' %} ", {}, '1_3_'),
'inheritance10': ("{% extends 'inheritance04' %} ", {}, '1&3_'),
# Three-level with both blocks defined on this level, but none on second level
'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),
@ -656,7 +662,7 @@ class Templates(unittest.TestCase):
'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),
# A block defined only in a child template shouldn't be displayed
'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),
'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1&3_'),
# A block within another block
'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),
@ -674,16 +680,16 @@ class Templates(unittest.TestCase):
'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),
# Two-level inheritance with {{ block.super }}
'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1&a3_'),
# Three-level inheritance with {{ block.super }} from parent
'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'),
# Three-level inheritance with {{ block.super }} from grandparent
'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),
'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1&a3_'),
# Three-level inheritance with {{ block.super }} from parent and grandparent
'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'),
'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1&ab3_'),
# Inheritance from local context without use of template loader
'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'),
@ -705,10 +711,10 @@ class Templates(unittest.TestCase):
'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),
# simple translation of a variable
'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"),
'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': '\xc3\x85'}, u"Å"),
# simple translation of a variable and filter
'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"),
'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': '\xc3\x85'}, u'å'),
# simple translation of a string with interpolation
'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),
@ -717,10 +723,10 @@ class Templates(unittest.TestCase):
'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"),
# translation of singular form
'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"),
'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}{{ counter }} plural{% endblocktrans %}', {'number': 1}, "singular"),
# translation of plural form
'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"),
'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}{{ counter }} plural{% endblocktrans %}', {'number': 2}, "2 plural"),
# simple non-translation (only marking) of a string to german
'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"),
@ -734,8 +740,16 @@ class Templates(unittest.TestCase):
# usage of the get_available_languages tag
'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'),
# translation of a constant string
'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
# translation of constant strings
'i18n13': ('{{ _("Password") }}', {'LANGUAGE_CODE': 'de'}, 'Passwort'),
'i18n14': ('{% cycle "foo" _("Password") _(\'Password\') as c %} {% cycle c %} {% cycle c %}', {'LANGUAGE_CODE': 'de'}, 'foo Passwort Passwort'),
'i18n15': ('{{ absent|default:_("Password") }}', {'LANGUAGE_CODE': 'de', 'absent': ""}, 'Passwort'),
'i18n16': ('{{ _("<") }}', {'LANGUAGE_CODE': 'de'}, '<'),
# Escaping inside blocktrans works as if it was directly in the
# template.
'i18n17': ('{% load i18n %}{% blocktrans with anton|escape as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'α & β'}, u'α &amp; β'),
'i18n18': ('{% load i18n %}{% blocktrans with anton|force_escape as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'α & β'}, u'α &amp; β'),
### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
@ -883,9 +897,14 @@ class Templates(unittest.TestCase):
'autoescape-tag06': ("{{ first }}", {"first": mark_safe("<b>first</b>")}, "<b>first</b>"),
'autoescape-tag07': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": mark_safe(u"<b>Apple</b>")}, u"<b>Apple</b>"),
# String arguments to filters, if used in the result, are escaped,
# too.
'basic-syntax08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote&quot; hah'),
# Literal string arguments to filters, if used in the result, are
# safe.
'autoescape-tag08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote" hah'),
# Objects which return safe strings as their __unicode__ method
# won't get double-escaped.
'autoescape-tag09': (r'{{ unsafe }}', {'unsafe': filters.UnsafeClass()}, 'you &amp; me'),
'autoescape-tag10': (r'{{ safe }}', {'safe': filters.SafeClass()}, 'you &gt; me'),
# The "safe" and "escape" filters cannot work due to internal
# implementation details (fortunately, the (no)autoescape block

View File

@ -3,6 +3,7 @@
unicode_tests = ur"""
Templates can be created from unicode strings.
>>> from django.template import *
>>> from django.utils.safestring import SafeData
>>> t1 = Template(u'ŠĐĆŽćžšđ {{ var }}')
Templates can also be created from bytestrings. These are assumed by encoded
@ -24,10 +25,13 @@ Contexts can be constructed from unicode or UTF-8 bytestrings.
>>> c4 = Context({u'var': '\xc4\x90\xc4\x91'})
Since both templates and all four contexts represent the same thing, they all
render the same (and are returned as unicode objects).
render the same (and are returned as unicode objects and "safe" objects as
well, for auto-escaping purposes).
>>> t1.render(c3) == t2.render(c3)
True
>>> type(t1.render(c3))
<type 'unicode'>
>>> isinstance(t1.render(c3), unicode)
True
>>> isinstance(t1.render(c3), SafeData)
True
"""

View File

@ -0,0 +1,51 @@
"""
>>> from django.utils.datastructures import SortedDict
>>> d = SortedDict()
>>> d[7] = 'seven'
>>> d[1] = 'one'
>>> d[9] = 'nine'
>>> d.keys()
[7, 1, 9]
>>> d.values()
['seven', 'one', 'nine']
>>> d.items()
[(7, 'seven'), (1, 'one'), (9, 'nine')]
# Overwriting an item keeps it's place.
>>> d[1] = 'ONE'
>>> d.values()
['seven', 'ONE', 'nine']
# New items go to the end.
>>> d[0] = 'nil'
>>> d.keys()
[7, 1, 9, 0]
# Deleting an item, then inserting the same key again will place it at the end.
>>> del d[7]
>>> d.keys()
[1, 9, 0]
>>> d[7] = 'lucky number 7'
>>> d.keys()
[1, 9, 0, 7]
# Changing the keys won't do anything, it's only a copy of the keys dict.
>>> k = d.keys()
>>> k.remove(9)
>>> d.keys()
[1, 9, 0, 7]
# Initialising a SortedDict with two keys will just take the first one. A real
# dict will actually take the second value so we will too, but we'll keep the
# ordering from the first key found.
>>> tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
>>> d = SortedDict(tuples)
>>> d.keys()
[2, 1]
>>> real_dict = dict(tuples)
>>> real_dict.values()
['one', 'second-two']
>>> d.values()
['second-two', 'one']
"""

View File

@ -6,7 +6,14 @@ from unittest import TestCase
from django.utils import html, checksums
from timesince import timesince_tests
import timesince
import datastructures
# Extra tests
__test__ = {
'timesince': timesince,
'datastructures': datastructures,
}
class TestUtilsHtml(TestCase):
@ -142,10 +149,6 @@ class TestUtilsChecksums(TestCase):
for value, output in items:
self.check_output(f, value, output)
__test__ = {
'timesince_tests': timesince_tests,
}
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@ -1,4 +1,4 @@
timesince_tests = """
"""
>>> from datetime import datetime, timedelta
>>> from django.utils.timesince import timesince

View File

@ -12,4 +12,12 @@ class StaticTests(TestCase):
for filename in media_files:
response = self.client.get('/views/site_media/%s' % filename)
file = open(path.join(media_dir, filename))
self.assertEquals(file.read(), response.content)
self.assertEquals(file.read(), response.content)
def test_copes_with_empty_path_component(self):
file_name = 'file.txt'
response = self.client.get('/views/site_media//%s' % file_name)
file = open(path.join(media_dir, file_name))
self.assertEquals(file.read(), response.content)