1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

gis: Merged revisions 7044-7102 via svnmerge from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7103 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2008-02-08 20:57:56 +00:00
parent 40e0a964ea
commit d06e33a54d
61 changed files with 18978 additions and 10943 deletions

View File

@ -45,6 +45,8 @@ answer newbie questions, and generally made Django that much better:
Marty Alchin <gulopine@gamemusic.org>
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
AgarFu <heaven@croasanaso.sytes.net>
Dagur Páll Ammendrup <dagurp@gmail.com>
Collin Anderson <cmawebsite@gmail.com>
Andreas
andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com>
@ -52,7 +54,7 @@ answer newbie questions, and generally made Django that much better:
Florian Apolloner
arien <regexbot@gmail.com>
David Ascher <http://ascher.ca/>
david@kazserve.org
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
Arthur <avandorp@gmail.com>
axiak@mit.edu
Jiri Barton
@ -99,6 +101,7 @@ answer newbie questions, and generally made Django that much better:
Dirk Datzert <dummy@habmalnefrage.de>
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
dave@thebarproject.com
david@kazserve.org
Jason Davies (Esaj) <http://www.jasondavies.com/>
Alex Dedul
deric@monowerks.com
@ -228,7 +231,7 @@ answer newbie questions, and generally made Django that much better:
mccutchen@gmail.com
michael.mcewan@gmail.com
michal@plovarna.cz
mikko@sorl.net
Mikko Hellsing <mikko@sorl.net>
Slawek Mikula <slawek dot mikula at gmail dot com>
mitakummaa@gmail.com
mmarshall
@ -301,6 +304,7 @@ answer newbie questions, and generally made Django that much better:
Don Spaulding <donspauldingii@gmail.com>
Bjørn Stabell <bjorn@exoweb.net>
Georgi Stanojevski <glisha@gmail.com>
starrynight <cmorgh@gmail.com>
Vasiliy Stavenko <stavenko@gmail.com>
Thomas Steinacher <http://www.eggdrop.ch/>
Johan C. Stöver <johan@nilling.nl>

View File

@ -47,7 +47,7 @@ LANGUAGES = (
('el', gettext_noop('Greek')),
('en', gettext_noop('English')),
('es', gettext_noop('Spanish')),
('es_AR', gettext_noop('Argentinean Spanish')),
('es-ar', gettext_noop('Argentinean Spanish')),
('fa', gettext_noop('Persian')),
('fi', gettext_noop('Finnish')),
('fr', gettext_noop('French')),

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,14 @@ msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-05-20 18:25+0200\n"
"PO-Revision-Date: 2007-12-01 12:06+0100\n"
"Last-Translator: Antoni Aloy <antoni.aloy@trespams.com>\n"
"PO-Revision-Date: 2008-01-22 19:39+0100\n"
"Last-Translator: Marc Garcia <marc.garcia@accopensys.com>\n"
"Language-Team: español <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
@ -50,9 +50,7 @@ msgstr "Deseleccionar tots"
#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgid "January February March April May June July August September October November December"
msgstr "Gener Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
#: contrib/admin/media/js/dateparse.js:33
@ -61,7 +59,7 @@ msgstr "Diumenge Dilluns Dimarts Dimecres Dijous Divendres Dissabte"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "D L M X J V S"
msgstr "Dg Dl Dt Dc Dj Dv Ds"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81

View File

@ -153,6 +153,7 @@ msgstr "Sgorau Carma"
#: contrib/comments/models.py:242
#, python-format
#, fuzzy
msgid "%(score)d rating by %(user)s"
msgstr "%(score)d"

View File

@ -2614,6 +2614,34 @@ msgstr "Samstag"
msgid "Sunday"
msgstr "Sonntag"
#: utils/dates.py:10
msgid "Mon"
msgstr "Mo"
#: utils/dates.py:10
msgid "Tue"
msgstr "Di"
#: utils/dates.py:10
msgid "Wed"
msgstr "Mi"
#: utils/dates.py:10
msgid "Thu"
msgstr "Do"
#: utils/dates.py:10
msgid "Fri"
msgstr "Fr"
#: utils/dates.py:11
msgid "Sat"
msgstr "Sa"
#: utils/dates.py:11
msgid "Sun"
msgstr "So"
#: utils/dates.py:14
msgid "January"
msgstr "Januar"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: django 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-14 12:33+0100\n"
"PO-Revision-Date: 2007-09-14 14:19+0100\n"
"Last-Translator: Michael Thornhill <michael.thornhill@gmail.com>\n"
"PO-Revision-Date: 2008-01-23 11:04+0100\n"
"Last-Translator: Michael Thornhill <michael@maithu.com>\n"
"Language-Team: Gaeilge <ga@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -18,99 +18,99 @@ msgstr ""
#: 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 ""
msgstr "Eanair Feabhra Márta Aibreán Bealtaine Meitheamh Iúil Lúnasa Mean Fómhair Deireadh Fómhair Nollaig"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr ""
msgstr "D L M C D A S"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
msgstr "Domhnaigh Luain Máirt Céadaoin Déardaoin Aoine Sathairn"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr ""
msgstr "%s ar fáil"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr ""
msgstr "Roghnaigh iomlán"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr ""
msgstr "Cuir le"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr ""
msgstr "Bain amach"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr ""
msgstr "Roghnófar %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr ""
msgstr "Roghnaigh do rogha agus cniog"
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr ""
msgstr "Glan iomlán"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr ""
msgstr "Anois"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr ""
msgstr "Clog"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr ""
msgstr "Roghnaigh am"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr ""
msgstr "Meán oíche"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr ""
msgstr "6 a.m."
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr ""
msgstr "Nóin"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr ""
msgstr "Cealaigh"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr ""
msgstr "Inniu"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr ""
msgstr "Féilire"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr ""
msgstr "Inné"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr ""
msgstr "Amárach"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
msgstr "Taispeán"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""
msgstr "Folaigh"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -971,6 +971,7 @@ msgstr ""
#: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format
#,fuzzy
msgid ""
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
"All of the following related items will be deleted:"
@ -2181,6 +2182,7 @@ msgstr ""
#: core/validators.py:256
#, python-format
#,fuzzy
msgid "Watch your mouth! The word %s is not allowed here."
msgstr ""
"ನಾಲಿಗೆ ಬಿಗಿ ಹಿಡಿಯಿರಿ! %s "
@ -2486,6 +2488,7 @@ msgstr ""
#: forms/__init__.py:381
#, python-format
#,fuzzy
msgid "Ensure your text is less than %s character."
msgstr ""
"ನಿಮ್ಮ ಗದ್ಯ %s ಅಕ್ಷರಕ್ಕಿಂತ "

File diff suppressed because it is too large Load Diff

View File

@ -851,6 +851,7 @@ msgstr "Remover"
#: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format
#, fuzzy
msgid ""
"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
"related objects, but your account doesn't have permission to delete the "
@ -1933,6 +1934,7 @@ msgstr[1] "Por favor introduza um número décimal com um máximo de %s digitos.
#: core/validators.py:381
#, python-format
#, fuzzy
msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit."
msgid_plural ""
@ -1973,6 +1975,7 @@ msgstr "Não foi possível extrair nada de %s."
#: core/validators.py:466
#, python-format
#, fuzzy
msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "O URL %(url)s devolveu um tipo de conteúdo inválido no header: '%s(contenttype)s'."

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-03-06 02:29+0100\n"
"PO-Revision-Date: 2007-03-06 10:30+0100\n"
"POT-Creation-Date: 2008-02-01 15:31+0100\n"
"PO-Revision-Date: 2008-02-01 15:32+0100\n"
"Last-Translator: Mikko Hellsing <mikko@sorl.net>\n"
"Language-Team: Django I18N <Django-I18N@googlegroups.com>\n"
"MIME-Version: 1.0\n"
@ -20,7 +20,7 @@ msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "Tillgänglig %s"
msgstr "Tillgängliga %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
@ -37,7 +37,7 @@ msgstr "Ta bort"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "Vald %s"
msgstr "Valda %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
@ -47,8 +47,8 @@ msgstr "Gör dina val och klicka på "
msgid "Clear all"
msgstr "Ta bort alla"
#: contrib/admin/media/js/dateparse.js:32
#: 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"
@ -56,14 +56,14 @@ msgstr ""
"Januari Februari Mars April Maj Juni Juli Augusti September Oktober November "
"December"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Söndag Måndag Tisdag Onsdag Torsdag Fredag Lördag"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "S M T O T F L"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Söndag Måndag Tisdag Onsdag Torsdag Fredag Lördag"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
@ -118,5 +118,4 @@ msgstr "Igår"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "I morgon"
msgstr "Imorgon"

View File

@ -34,7 +34,7 @@
{% for bound_field_set in bound_field_sets %}
<fieldset class="module aligned {{ bound_field_set.classes }}">
{% if bound_field_set.name %}<h2>{{ bound_field_set.name }}</h2>{% endif %}
{% if bound_field_set.description %}<div class="description">{{ bound_field_set.description }}</div>{% endif %}
{% if bound_field_set.description %}<div class="description">{{ bound_field_set.description|safe }}</div>{% endif %}
{% for bound_field_line in bound_field_set %}
{% admin_field_line bound_field_line %}
{% for bound_field in bound_field_line %}

View File

@ -105,7 +105,7 @@ class EasyInstance(object):
return self.instance._get_pk_val()
def url(self):
return '%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk()))
return mark_safe('%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk())))
def fields(self):
"""

View File

@ -20,7 +20,7 @@ class ARProvinceSelect(Select):
class ARPostalCodeField(RegexField):
"""
A field that accepts a `classic´ NNNN Postal Code or a CPA.
A field that accepts a 'classic' NNNN Postal Code or a CPA.
See http://www.correoargentino.com.ar/consulta_cpa/home.php
"""
@ -44,7 +44,7 @@ class ARPostalCodeField(RegexField):
class ARDNIField(CharField):
"""
A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
A field that validates 'Documento Nacional de Identidad' (DNI) numbers.
"""
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
@ -73,7 +73,7 @@ class ARDNIField(CharField):
class ARCUITField(RegexField):
"""
This field validates a CUIT (Código Único de Identificación Tributaria). A
This field validates a CUIT (Código Único de Identificación Tributaria). A
CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
"""
default_error_messages = {

View File

@ -55,7 +55,7 @@ NORTHERN_IRELAND_REGION_CHOICES = (
("County Antrim", _("County Antrim")),
("County Armagh", _("County Armagh")),
("County Down", _("County Down")),
("County Fermanagh", _("County Down")),
("County Fermanagh", _("County Fermanagh")),
("County Londonderry", _("County Londonderry")),
("County Tyrone", _("County Tyrone")),
)

View File

@ -6,7 +6,7 @@ from django.utils.encoding import smart_unicode, iri_to_uri
from django.conf import settings
def add_domain(domain, url):
if not url.startswith('http://'):
if not (url.startswith('http://') or url.startswith('https://')):
# 'url' must already be ASCII and URL-quoted, so no need for encoding
# conversions here.
url = iri_to_uri(u'http://%s%s' % (domain, url))
@ -82,7 +82,8 @@ class Feed(object):
link = link,
description = self.__get_dynamic_attr('description', obj),
language = settings.LANGUAGE_CODE.decode(),
feed_url = add_domain(current_site, self.__get_dynamic_attr('feed_url', obj)),
feed_url = add_domain(current_site.domain,
self.__get_dynamic_attr('feed_url', obj)),
author_name = self.__get_dynamic_attr('author_name', obj),
author_link = self.__get_dynamic_attr('author_link', obj),
author_email = self.__get_dynamic_attr('author_email', obj),

View File

@ -111,13 +111,13 @@ class BaseHandler(object):
except SystemExit:
pass # See http://code.djangoproject.com/ticket/1023
except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later.
exc_info = sys.exc_info()
receivers = dispatcher.send(signal=signals.got_request_exception, request=request)
if settings.DEBUG:
from django.views import debug
return debug.technical_500_response(request, *sys.exc_info())
return debug.technical_500_response(request, *exc_info)
else:
# Get the exception info now, in case another exception is thrown later.
exc_info = sys.exc_info()
receivers = dispatcher.send(signal=signals.got_request_exception, request=request)
# When DEBUG is False, send an error message to the admins.
subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
try:

View File

@ -24,7 +24,8 @@ class ModelBase(type):
def __new__(cls, name, bases, attrs):
# If this isn't a subclass of Model, don't do anything special.
try:
if not filter(lambda b: issubclass(b, Model), bases):
parents = [b for b in bases if issubclass(b, Model)]
if not parents:
return super(ModelBase, cls).__new__(cls, name, bases, attrs)
except NameError:
# 'Model' isn't defined yet, meaning we're looking at Django's own
@ -39,9 +40,8 @@ class ModelBase(type):
types.ClassType('MultipleObjectsReturned', (MultipleObjectsReturned, ), {}))
# Build complete list of parents
for base in bases:
# TODO: Checking for the presence of '_meta' is hackish.
if '_meta' in dir(base):
for base in parents:
if base is not Model:
new_class._meta.parents.append(base)
new_class._meta.parents.extend(base._meta.parents)
@ -79,6 +79,35 @@ class ModelBase(type):
# registered version.
return get_model(new_class._meta.app_label, name, False)
def add_to_class(cls, name, value):
if name == 'Admin':
assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value))
value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')]))
if hasattr(value, 'contribute_to_class'):
value.contribute_to_class(cls, name)
else:
setattr(cls, name, value)
def _prepare(cls):
# Creates some methods once self._meta has been populated.
opts = cls._meta
opts._prepare(cls)
if opts.order_with_respect_to:
cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True)
cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)
setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls))
setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls))
# Give the class a docstring -- its definition.
if cls.__doc__ is None:
cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields]))
if hasattr(cls, 'get_absolute_url'):
cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
dispatcher.send(signal=signals.class_prepared, sender=cls)
class Model(object):
__metaclass__ = ModelBase
@ -176,40 +205,9 @@ class Model(object):
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
def add_to_class(cls, name, value):
if name == 'Admin':
assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value))
value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')]))
if hasattr(value, 'contribute_to_class'):
value.contribute_to_class(cls, name)
else:
setattr(cls, name, value)
add_to_class = classmethod(add_to_class)
def _prepare(cls):
# Creates some methods once self._meta has been populated.
opts = cls._meta
opts._prepare(cls)
if opts.order_with_respect_to:
cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True)
cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)
setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls))
setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls))
# Give the class a docstring -- its definition.
if cls.__doc__ is None:
cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields]))
if hasattr(cls, 'get_absolute_url'):
cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
dispatcher.send(signal=signals.class_prepared, sender=cls)
_prepare = classmethod(_prepare)
def save(self, raw=False):
dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
dispatcher.send(signal=signals.pre_save, sender=self.__class__,
instance=self, raw=raw)
non_pks = [f for f in self._meta.fields if not f.primary_key]
cursor = connection.cursor()
@ -272,7 +270,7 @@ class Model(object):
# Run any post-save hooks.
dispatcher.send(signal=signals.post_save, sender=self.__class__,
instance=self, created=(not record_exists))
instance=self, created=(not record_exists), raw=raw)
save.alters_data = True

View File

@ -22,12 +22,12 @@ class GZipMiddleware(object):
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
# Older versions of IE have issues with gzipped pages containing either
# Javascript and PDF.
if "msie" in request.META.get('HTTP_USER_AGENT', '').lower():
ctype = response.get('Content-Type', '').lower()
if "javascript" in ctype or ctype == "application/pdf":
return response
ae = request.META.get('HTTP_ACCEPT_ENCODING', '')
if not re_accepts_gzip.search(ae):

View File

@ -228,7 +228,7 @@ class ModelFormMetaclass(type):
opts = ModelFormOptions(attrs.get('Meta', None))
attrs['_meta'] = opts
# Don't allow more than one Meta model defenition in bases. The fields
# Don't allow more than one Meta model definition in bases. The fields
# would be generated correctly, but the save method won't deal with
# more than one object.
base_models = []

View File

@ -426,7 +426,7 @@ class MultiWidget(Widget):
if id_:
final_attrs = dict(final_attrs, id='%s_%s' % (id_, i))
output.append(widget.render(name + '_%s' % i, widget_value, final_attrs))
return self.format_output(output)
return mark_safe(self.format_output(output))
def id_for_label(self, id_):
# See the comment for RadioSelect.id_for_label()

View File

@ -289,6 +289,14 @@ class Parser(object):
return NodeList()
def extend_nodelist(self, nodelist, node, token):
if node.must_be_first and nodelist:
try:
if nodelist.contains_nontext:
raise AttributeError
except AttributeError:
raise TemplateSyntaxError("%r must be the first tag in the template." % node)
if isinstance(nodelist, NodeList) and not isinstance(node, TextNode):
nodelist.contains_nontext = True
nodelist.append(node)
def enter_command(self, command, token):
@ -708,6 +716,10 @@ class Variable(object):
return current
class Node(object):
# Set this to True for nodes that must be first in the template (although
# they can be preceded by text nodes.
must_be_first = False
def render(self, context):
"Return the node rendered as a string"
pass
@ -725,6 +737,10 @@ class Node(object):
return nodes
class NodeList(list):
# Set to True the first time a non-TextNode is inserted by
# extend_nodelist().
contains_nontext = False
def render(self, context):
bits = []
for node in self:

View File

@ -1,5 +1,5 @@
from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
from django.template import Library, Node
from django.template import Library, Node, TextNode
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
@ -37,11 +37,18 @@ class BlockNode(Node):
self.parent = BlockNode(self.name, nodelist)
class ExtendsNode(Node):
must_be_first = True
def __init__(self, nodelist, parent_name, parent_name_expr, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
self.template_dirs = template_dirs
def __repr__(self):
if self.parent_name_expr:
return "<ExtendsNode: extends %s>" % self.parent_name_expr.token
return '<ExtendsNode: extends "%s">' % self.parent_name
def get_parent(self, context):
if self.parent_name_expr:
self.parent_name = self.parent_name_expr.resolve(context)
@ -49,7 +56,7 @@ class ExtendsNode(Node):
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_expr:
error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr.
error_msg += " Got this from the '%s' variable." % self.parent_name_expr.token
raise TemplateSyntaxError, error_msg
if hasattr(parent, 'render'):
return parent # parent is a Template object
@ -62,7 +69,10 @@ class ExtendsNode(Node):
def render(self, context):
compiled_parent = self.get_parent(context)
parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
pos = 0
while isinstance(compiled_parent.nodelist[pos], TextNode):
pos += 1
parent_is_child = isinstance(compiled_parent.nodelist[pos], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
# Check for a BlockNode with this node's name, and replace it if found.
@ -74,7 +84,7 @@ class ExtendsNode(Node):
# add this BlockNode to the parent's ExtendsNode nodelist, so
# it'll be checked when the parent node's render() is called.
if parent_is_child:
compiled_parent.nodelist[0].nodelist.append(block_node)
compiled_parent.nodelist[pos].nodelist.append(block_node)
else:
# Keep any existing parents and add a new one. Used by BlockNode.
parent_block.parent = block_node.parent

View File

@ -262,7 +262,7 @@ class Client:
self.cookies[settings.SESSION_COOKIE_NAME]['expires'] = None
# Save the session values
request.session.save()
request.session.save()
return True
else:
@ -274,5 +274,5 @@ class Client:
Causes the authenticated user to be logged out.
"""
session = __import__(settings.SESSION_ENGINE, {}, {}, ['']).SessionStore()
session.delete(session_key=self.cookies['sessionid'].value)
session.delete(session_key=self.cookies[settings.SESSION_COOKIE_NAME].value)
self.cookies = SimpleCookie()

View File

@ -72,6 +72,8 @@ class TestCase(unittest.TestCase):
self.client = Client()
try:
self._pre_setup()
except (KeyboardInterrupt, SystemExit):
raise
except Exception:
import sys
result.addError(self, sys.exc_info())

View File

@ -2,6 +2,9 @@ class MergeDict(object):
"""
A simple class for creating new "virtual" dictionaries that actually look
up values in more than one dictionary, passed in the constructor.
If a key appears in more than one of the passed in dictionaries, only the
first occurrence will be used.
"""
def __init__(self, *dicts):
self.dicts = dicts
@ -25,11 +28,9 @@ class MergeDict(object):
def getlist(self, key):
for dict_ in self.dicts:
try:
if key in dict_.keys():
return dict_.getlist(key)
except KeyError:
pass
raise KeyError
return []
def items(self):
item_list = []

View File

@ -98,5 +98,5 @@ def iri_to_uri(iri):
# section 3.1 of RFC 3987.
if iri is None:
return iri
return urllib.quote(smart_str(iri), safe='/#%[]=:;$&()+,!?')
return urllib.quote(smart_str(iri), safe='/#%[]=:;$&()+,!?*')

View File

@ -53,7 +53,7 @@ class SyndicationFeed(object):
'title': to_unicode(title),
'link': iri_to_uri(link),
'description': to_unicode(description),
'language': force_unicode(language),
'language': to_unicode(language),
'author_email': to_unicode(author_email),
'author_name': to_unicode(author_name),
'author_link': iri_to_uri(author_link),

View File

@ -102,18 +102,23 @@ 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.ascii_letters + string.digits and \
(middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
middle = '<a href="http://%s"%s>%s</a>' % (
urlquote(middle, safe='/&=:;#?+'), nofollow_attr,
trim_url(middle))
middle = 'http://%s' % middle
if middle.startswith('http://') or middle.startswith('https://'):
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):
url = urlquote(middle, safe='/&=:;#?+*')
if autoescape and not safe_input:
url = escape(url)
trimmed_url = trim_url(middle)
middle = '<a href="%s"%s>%s</a>' % (url, nofollow_attr,
trimmed_url)
elif '@' in middle and not middle.startswith('www.') and \
not ':' in middle and simple_email_re.match(middle):
if autoescape:
middle = conditional_escape(middle)
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
if lead + middle + trail != word:
words[i] = lead + middle + trail
if autoescape and not safe_input:
lead, trail = escape(lead), escape(trail)
words[i] = mark_safe('%s%s%s' % (lead, middle, trail))
elif autoescape and not safe_input:
words[i] = escape(word)
elif safe_input:

View File

@ -42,7 +42,10 @@ accept_language_re = re.compile(r'''
''', re.VERBOSE)
def to_locale(language, to_lower=False):
"Turns a language name (en-us) into a locale name (en_US)."
"""
Turns a language name (en-us) into a locale name (en_US). If 'to_lower' is
True, the last component is lower-cased (en_us).
"""
p = language.find('-')
if p >= 0:
if to_lower:
@ -357,19 +360,20 @@ def get_language_from_request(request):
return lang_code
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
for lang, unused in parse_accept_lang_header(accept):
if lang == '*':
for accept_lang, unused in parse_accept_lang_header(accept):
if accept_lang == '*':
break
# We have a very restricted form for our language files (no encoding
# specifier, since they all must be UTF-8 and only one possible
# language each time. So we avoid the overhead of gettext.find() and
# look up the MO file manually.
# work out the MO file manually.
normalized = locale.locale_alias.get(to_locale(lang, True))
# 'normalized' is the root name of the locale in POSIX format (which is
# the format used for the directories holding the MO files).
normalized = locale.locale_alias.get(to_locale(accept_lang, True))
if not normalized:
continue
# Remove the default encoding from locale_alias
normalized = normalized.split('.')[0]
@ -378,10 +382,11 @@ def get_language_from_request(request):
# need to check again.
return _accepted[normalized]
for lang in (normalized, normalized.split('_')[0]):
for lang, dirname in ((accept_lang, normalized),
(accept_lang.split('-')[0], normalized.split('_')[0])):
if lang not in supported:
continue
langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
langfile = os.path.join(globalpath, dirname, 'LC_MESSAGES',
'django.mo')
if os.path.exists(langfile):
_accepted[normalized] = lang

View File

@ -73,6 +73,12 @@ def technical_500_response(request, exc_type, exc_value, tb):
template_info = None
template_does_not_exist = False
loader_debug_info = None
# Handle deprecated string exceptions
if isinstance(exc_type, basestring):
exc_value = Exception('Deprecated String Exception: %r' % exc_type)
exc_type = type(exc_value)
if issubclass(exc_type, TemplateDoesNotExist):
from django.template.loader import template_source_loaders
template_does_not_exist = True
@ -192,9 +198,11 @@ def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_na
Returns (pre_context_lineno, pre_context, context_line, post_context).
"""
source = None
if loader is not None:
source = loader.get_source(module_name).splitlines()
else:
if loader is not None and hasattr(loader, "get_source"):
source = loader.get_source(module_name)
if source is not None:
source = source.splitlines()
if source is None:
try:
f = open(filename)
try:
@ -431,11 +439,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|escape }}</li>{% endfor %}</ol>
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}{% if line %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endif %}{% endfor %}</ol>
{% endif %}
<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|escape }}</li>{% endfor %}</ol>
<ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}{% if line %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endif %}{% endfor %}</ol>
{% endif %}
</div>
{% endif %}

View File

@ -292,6 +292,14 @@ translation string. Example::
In this case, both the tag and the filter will see the already-translated
string, so they don't need to be aware of translations.
.. note::
In this example, the translation infrastructure will be passed the string
``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The
translated string will need to contain the comma so that the filter
parsing code knows how to split up the arguments. For example, a German
translator might translate the string ``"yes,no"`` as ``"ja,nein"``
(keeping the comma intact).
.. _Django templates: ../templates_python/
Working with lazy translation objects

View File

@ -113,10 +113,23 @@ postal code or a CPA_.
.. _CPA: http://www.correoargentino.com.ar/consulta_cpa/home.php
ARDNIField
----------
A form field that validates input as a Documento Nacional de Identidad (DNI)
number.
ARCUITField
-----------
A form field that validates input as a Código Único de Identificación
Tributaria (CUIT) number.
ARProvinceSelect
----------------
A ``Select`` widget that uses a list of Argentina's provinces as its choices.
A ``Select`` widget that uses a list of Argentina's provinces and autonomous
cities as its choices.
Australia (``django.contrib.localflavor.au``)
=============================================
@ -610,7 +623,7 @@ UKNationSelect
A ``Select`` widget that uses a list of UK nations as its choices.
United States of America (``django.contrib.localflavor.us``)
United States of America (``django.contrib.localflavor.us``)
============================================================
USPhoneNumberField
@ -635,7 +648,7 @@ A valid SSN must obey the following rules:
USStateField
------------
A form field that validates input as a U.S. state name or abbreviation. It
A form field that validates input as a U.S. state name or abbreviation. It
normalizes the input to the standard two-letter postal service abbreviation
for the given state.

View File

@ -575,6 +575,10 @@ Three things to note about 404 views:
to the template: ``request_path``, which is the URL that resulted
in the 404.
* The 404 view is passed a ``RequestContext`` and will have access to
variables supplied by your ``TEMPLATE_CONTEXT_PROCESSORS`` (e.g.
``MEDIA_URL``).
* If ``DEBUG`` is set to ``True`` (in your settings module), then your 404
view will never be used, and the traceback will be displayed instead.
@ -587,8 +591,9 @@ the view ``django.views.defaults.server_error``, which loads and renders the
template ``500.html``.
This means you need to define a ``500.html`` template in your root template
directory. This template will be used for all server errors. The
default 500 view passes no variables to this template.
directory. This template will be used for all server errors. The default 500
view passes no variables to this template and is rendered with an empty
``Context`` to lessen the chance of additional errors.
This ``server_error`` view should suffice for 99% of Web applications, but if
you want to override the view, you can specify ``handler500`` in your

View File

@ -22,16 +22,29 @@ Required arguments
Optional arguments
------------------
``context``
``dictionary``
A dictionary of values to add to the template context. By default, this
is an empty dictionary. If a value in the dictionary is callable, the
view will call it just before rendering the template.
``context_instance``
The context instance to render the template with. By default, the template
will be rendered with a ``Context`` instance (filled with values from
``dictionary``). If you need to use `context processors`_, you will want to
render the template with a ``RequestContext`` instance instead. Your code
might look something like this::
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
``mimetype``
**New in Django development version:** The MIME type to use for the
resulting document. Defaults to the value of the ``DEFAULT_CONTENT_TYPE``
setting.
.. _`context processors`: ../templates_python/#subclassing-context-requestcontext
Example
-------
@ -57,8 +70,6 @@ This example is equivalent to::
r = HttpResponse(t.render(c),
mimetype="application/xhtml+xml")
.. _an HttpResponse object: ../request_response/#httpresponse-objects
``get_object_or_404``
=====================

View File

@ -13,8 +13,16 @@ class Person(models.Model):
return u"%s %s" % (self.first_name, self.last_name)
def pre_save_nokwargs_test(sender, instance):
print 'pre_save_nokwargs signal'
def post_save_nokwargs_test(sender, instance):
print 'post_save_nokwargs signal'
def pre_save_test(sender, instance, **kwargs):
print 'pre_save signal,', instance
if kwargs.get('raw'):
print 'Is raw'
def post_save_test(sender, instance, **kwargs):
print 'post_save signal,', instance
@ -23,16 +31,20 @@ def post_save_test(sender, instance, **kwargs):
print 'Is created'
else:
print 'Is updated'
if kwargs.get('raw'):
print 'Is raw'
def pre_delete_test(sender, instance, **kwargs):
print 'pre_delete signal,', instance
print 'instance.id is not None: %s' % (instance.id != None)
print 'instance.id is not None: %s' % (instance.id != None)
def post_delete_test(sender, instance, **kwargs):
print 'post_delete signal,', instance
print 'instance.id is None: %s' % (instance.id == None)
print 'instance.id is None: %s' % (instance.id == None)
__test__ = {'API_TESTS':"""
>>> dispatcher.connect(pre_save_nokwargs_test, signal=models.signals.pre_save)
>>> dispatcher.connect(post_save_nokwargs_test, signal=models.signals.post_save)
>>> dispatcher.connect(pre_save_test, signal=models.signals.pre_save)
>>> dispatcher.connect(post_save_test, signal=models.signals.post_save)
>>> dispatcher.connect(pre_delete_test, signal=models.signals.pre_delete)
@ -40,16 +52,29 @@ __test__ = {'API_TESTS':"""
>>> p1 = Person(first_name='John', last_name='Smith')
>>> p1.save()
pre_save_nokwargs signal
pre_save signal, John Smith
post_save_nokwargs signal
post_save signal, John Smith
Is created
>>> p1.first_name = 'Tom'
>>> p1.save()
pre_save_nokwargs signal
pre_save signal, Tom Smith
post_save_nokwargs signal
post_save signal, Tom Smith
Is updated
>>> p1.save(raw=True)
pre_save_nokwargs signal
pre_save signal, Tom Smith
Is raw
post_save_nokwargs signal
post_save signal, Tom Smith
Is updated
Is raw
>>> p1.delete()
pre_delete signal, Tom Smith
instance.id is not None: True
@ -59,13 +84,17 @@ instance.id is None: False
>>> p2 = Person(first_name='James', last_name='Jones')
>>> p2.id = 99999
>>> p2.save()
pre_save_nokwargs signal
pre_save signal, James Jones
post_save_nokwargs signal
post_save signal, James Jones
Is created
>>> p2.id = 99998
>>> p2.save()
pre_save_nokwargs signal
pre_save signal, James Jones
post_save_nokwargs signal
post_save signal, James Jones
Is created
@ -78,6 +107,8 @@ instance.id is None: False
>>> Person.objects.all()
[<Person: James Jones>]
>>> dispatcher.disconnect(pre_save_nokwargs_test, signal=models.signals.pre_save)
>>> dispatcher.disconnect(post_save_nokwargs_test, signal=models.signals.post_save)
>>> dispatcher.disconnect(post_delete_test, signal=models.signals.post_delete)
>>> dispatcher.disconnect(pre_delete_test, signal=models.signals.pre_delete)
>>> dispatcher.disconnect(post_save_test, signal=models.signals.post_save)

View File

@ -20,6 +20,19 @@
>>> md2['chris']
'cool'
MergeDict can merge MultiValueDicts
>>> multi1 = MultiValueDict({'key1': ['value1'], 'key2': ['value2', 'value3']})
>>> multi2 = MultiValueDict({'key2': ['value4'], 'key4': ['value5', 'value6']})
>>> mm = MergeDict(multi1, multi2)
# Although 'key2' appears in both dictionaries, only the first value is used.
>>> mm.getlist('key2')
['value2', 'value3']
>>> mm.getlist('key4')
['value5', 'value6']
>>> mm.getlist('undefined')
[]
### MultiValueDict ##########################################################
>>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})

View File

@ -2,6 +2,11 @@ tests = """
>>> from django.utils.translation.trans_real import parse_accept_lang_header
>>> p = parse_accept_lang_header
#
# Testing HTTP header parsing. First, we test that we can parse the values
# according to the spec (and that we extract all the pieces in the right order).
#
Good headers.
>>> p('de')
[('de', 1.0)]
@ -54,4 +59,44 @@ Bad headers; should always return [].
>>> p('')
[]
#
# Now test that we parse a literal HTTP header correctly.
#
>>> from django.utils.translation.trans_real import get_language_from_request
>>> g = get_language_from_request
>>> from django.http import HttpRequest
>>> r = HttpRequest
>>> r.COOKIES = {}
These tests assumes the es, es_AR, pt and pt_BR translations exit in the Django
source tree.
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-br'}
>>> g(r)
'pt-br'
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt'}
>>> g(r)
'pt'
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es,de'}
>>> g(r)
'es'
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'}
>>> g(r)
'es-ar'
This test assumes there won't be a Django translation to a US variation
of the Spanish language, a safe assumption. When the user sets it
as the preferred language, the main 'es' translation should be selected
instead.
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'}
>>> g(r)
'es'
This tests the following scenario: there isn't a main language (zh)
translation of Django but there is a translation to variation (zh_CN)
the user sets zh-cn as the preferred language, it should be selected by
Django without falling back nor ignoring it.
>>> r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-cn,de'}
>>> g(r)
'zh-cn'
"""

View File

@ -98,8 +98,8 @@ def get_filter_tests():
'filter-upper01': ('{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, u"A & B A &AMP; B"),
'filter-upper02': ('{{ a|upper }} {{ b|upper }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, u"A &amp; B A &amp;AMP; B"),
'filter-urlize01': ('{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% 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://example.com/x=&y=</a> <a href="http://example.com?x=&y=" rel="nofollow">http://example.com?x=&y=</a>'),
'filter-urlize02': ('{{ a|urlize }} {{ b|urlize }}', {"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://example.com/x=&amp;y=</a> <a href="http://example.com?x=&y=" rel="nofollow">http://example.com?x=&y=</a>'),
'filter-urlize01': ('{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, u'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
'filter-urlize02': ('{{ a|urlize }} {{ b|urlize }}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, u'<a href="http://example.com/?x=&amp;y=" rel="nofollow">http://example.com/?x=&amp;y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
'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'),
@ -108,8 +108,12 @@ def get_filter_tests():
'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": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&y=')}, u'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
'filter-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&y=')}, u'&quot;Unsafe&quot; <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
# mailto: testing for urlize
'filter-urlize07': ('{{ a|urlize }}', {"a": "Email me at me@example.com"}, 'Email me at <a href="mailto:me@example.com">me@example.com</a>'),
'filter-urlize08': ('{{ a|urlize }}', {"a": "Email me at <me@example.com>"}, 'Email me at &lt;<a href="mailto:me@example.com">me@example.com</a>&gt;'),
'filter-urlizetrunc01': ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, u'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),
'filter-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, u'&quot;Unsafe&quot; <a href="http://example.com/x=&amp;y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),
'filter-wordcount01': ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
@ -240,7 +244,7 @@ def get_filter_tests():
'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.
# 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'),

View File

@ -736,7 +736,7 @@ class Templates(unittest.TestCase):
'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"),
# translation of a variable with a translated filter
'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'),
'i18n10': ('{{ bool|yesno:_("yes,no,maybe") }}', {'bool': True, 'LANGUAGE_CODE': 'de'}, 'Ja'),
# translation of a variable with a non-translated filter
'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),