1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

gis: Merged revisions 6920-6989 via svnmerge from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6990 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2008-01-02 16:57:53 +00:00
parent ef0f46f1d0
commit 7e322b5908
75 changed files with 1074 additions and 689 deletions

View File

@ -130,6 +130,7 @@ answer newbie questions, and generally made Django that much better:
Matthew Flanagan <http://wadofstuff.blogspot.com>
Eric Floehr <eric@intellovations.com>
Vincent Foley <vfoleybourgon@yahoo.ca>
Rudolph Froger <rfroger@estrate.nl>
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info
Marc Garcia <marc.garcia@accopensys.com>
@ -300,6 +301,7 @@ answer newbie questions, and generally made Django that much better:
Georgi Stanojevski <glisha@gmail.com>
Vasiliy Stavenko <stavenko@gmail.com>
Thomas Steinacher <http://www.eggdrop.ch/>
Johan C. Stöver <johan@nilling.nl>
nowell strite
Thomas Stromberg <tstromberg@google.com>
Sundance
@ -327,6 +329,7 @@ answer newbie questions, and generally made Django that much better:
tt@gurgle.no
Amit Upadhyay
Geert Vanderkelen
I.S. van Oostveen <v.oostveen@idca.nl>
viestards.lists@gmail.com
George Vilches <gav@thataddress.com>
Vlado <vlado@labath.org>

View File

@ -52,7 +52,9 @@ class LazySettings(object):
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
raise ImportError, "Environment variable %s is undefined so settings cannot be imported." % ENVIRONMENT_VARIABLE # NOTE: This is arguably an EnvironmentError, but that causes problems with Python's interactive help
# NOTE: This is arguably an EnvironmentError, but that causes
# problems with Python's interactive help.
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
self._target = Settings(settings_module)

View File

@ -1,17 +1,12 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the django package.
# Johan C. Stöver <johan@nilling.nl>, 2005.
# Rudolph Froger <rfroger@estrate.nl>, 2006.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-12-09 15:51+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Johan C. Stöver <johan@nilling.nl>\n"
"PO-Revision-Date: 2007-12-17 21:14+0100\n"
"Last-Translator: I.S. van Oostveen\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
@ -69,7 +64,7 @@ msgstr "De waarde moet een geheel getal zijn."
#: db/models/fields/__init__.py:381
msgid "This value must be either True or False."
msgstr "De waarde moet of True (waar) of False (onwaar) zijn."
msgstr "De waarde moet of True (Waar) of False (Onwaar) zijn."
#: db/models/fields/__init__.py:397
msgid "This field cannot be null."
@ -279,7 +274,7 @@ msgstr "Alleen alfabetische karakters zijn toegestaan"
#: core/validators.py:139
msgid "Year must be 1900 or later."
msgstr "Het jaartal moet 1900 of nieuwer zijn."
msgstr "Het jaartal moet 1900 of later zijn."
#: core/validators.py:143
#, python-format
@ -296,20 +291,20 @@ msgstr "Geef een geldig e-mailadres op."
#: core/validators.py:173 core/validators.py:442 forms/__init__.py:667
msgid "No file was submitted. Check the encoding type on the form."
msgstr "Er was geen bestand verstuurd. Controleer de encoding van het formulier."
msgstr "Er was geen bestand verstuurd. Controleer het coderings type van het formulier."
#: core/validators.py:177
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
"Bestand ongeldig. Het bestand dat is gegeven is geen afbeelding of was "
"Bestand ongeldig. Het bestand dat is gegeven is geen afbeelding of is "
"beschadigd."
#: core/validators.py:184
#, python-format
msgid "The URL %s does not point to a valid image."
msgstr "De URL %s wijst niet naar een afbeelding."
msgstr "De URL %s wijst niet naar een geldige afbeelding."
#: core/validators.py:188
#, python-format
@ -321,7 +316,7 @@ msgstr ""
#: core/validators.py:196
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
msgstr "De URL %s wijst niet naar een QuickTime video."
msgstr "De URL %s wijst niet naar een geldige QuickTime video."
#: core/validators.py:200
msgid "A valid URL is required."
@ -349,18 +344,18 @@ msgstr "Ongeldige URL: %s"
#: core/validators.py:243 core/validators.py:245
#, python-format
msgid "The URL %s is a broken link."
msgstr "De URL %s is een niet werkende link."
msgstr "De URL %s is niet een werkende link."
#: core/validators.py:251
msgid "Enter a valid U.S. state abbreviation."
msgstr "Geef een geldige afkorting van een VS staat."
msgstr "Geef een geldige afkorting van een staat in de VS."
#: core/validators.py:265
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Pas op uw taalgebruik! Gebruik van %s niet toegestaan."
msgstr[1] "Pas op uw taalgebruik! Gebruik van de woorden %s niet toegestaan."
msgstr[1] "Pas op uw taalgebruik! Gebruik van de woorden %s is niet toegestaan."
#: core/validators.py:272
#, python-format
@ -373,7 +368,7 @@ msgstr "Voer tenminste één veld in."
#: core/validators.py:300 core/validators.py:311
msgid "Please enter both fields or leave them both empty."
msgstr "Voer waarden in in beide velden of laat beide leeg."
msgstr "Voer waarden in beide velden in of laat beide leeg."
#: core/validators.py:318
#, python-format
@ -450,7 +445,7 @@ msgstr "Zorg ervoor dat het bestand hoogstens %s bytes groot is."
#: core/validators.py:453
msgid "The format for this field is wrong."
msgstr "Het formaat van dit veld is fout."
msgstr "Het formaat van dit veld is foutief."
#: core/validators.py:468
msgid "This field is invalid."
@ -536,7 +531,7 @@ msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgstr ""
"Het lijkt erop dat uw browser geen cookies accepteerd. Om aan te melden "
"Het lijkt erop dat uw browser geen cookies accepteert. Om aan te melden "
"moeten cookies worden geaccepteerd."
#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10
@ -645,7 +640,7 @@ msgstr "supergebruiker status"
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
msgstr "Bepaald dat deze gebruiker alle rechten heeft, zonder deze expliciet toe te wijzen."
msgstr "Bepaalt dat deze gebruiker alle rechten heeft, zonder deze expliciet toe te wijzen."
#: contrib/auth/models.py:98
msgid "last login"
@ -685,7 +680,7 @@ msgstr "Rechten"
#: contrib/auth/models.py:113
msgid "Important dates"
msgstr "Belangrijke data"
msgstr "Belangrijke datums"
#: contrib/auth/models.py:114
msgid "Groups"
@ -783,7 +778,7 @@ msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
msgstr ""
"Uw sessie is verlopen, meldt u opnieuw aan. Maakt u geen zorgen: Uw bijdrage "
"Uw sessie is verlopen, meld u opnieuw aan. Maakt u zich geen zorgen: Uw bijdrage "
"is opgeslagen."
#: contrib/admin/views/decorators.py:69
@ -791,7 +786,7 @@ msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
msgstr ""
"Het lijkt erop dat uw browser geen cookies accepteerd. Zet het gebruik van "
"Het lijkt erop dat uw browser geen cookies accepteert. Zet het gebruik van "
"cookies aan in uw browser, laad deze pagina nogmaals en probeer het opnieuw."
#: contrib/admin/views/decorators.py:83
@ -928,7 +923,7 @@ msgstr "Model %r niet gevonden in app %r"
#: contrib/admin/views/doc.py:183
#, python-format
msgid "the related `%s.%s` object"
msgstr "the related `%s.%s` object"
msgstr "het gerelateerde `%s.%s` object"
#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
@ -938,7 +933,7 @@ msgstr "model:"
#: contrib/admin/views/doc.py:214
#, python-format
msgid "related `%s.%s` objects"
msgstr "related `%s.%s` objects"
msgstr "de gerelateerde `%s.%s` objecten"
#: contrib/admin/views/doc.py:219
#, python-format
@ -948,12 +943,12 @@ msgstr "alle %s"
#: contrib/admin/views/doc.py:224
#, python-format
msgid "number of %s"
msgstr "nummer van %s"
msgstr "aantal %s"
#: contrib/admin/views/doc.py:229
#, python-format
msgid "Fields on %s objects"
msgstr "Velden van %s objects"
msgstr "Velden van %s objecten"
#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301
#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309
@ -1139,11 +1134,11 @@ msgid ""
"All of the following related items will be deleted:"
msgstr ""
"Weet u zeker dat u %(object_name)s \"%(escaped_object)s\" wilt verwijderen? Alle "
"volgende opjecten worden verwijderd:"
"volgende objecten worden verwijderd:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
msgstr "Ja, Ik weet het zeker"
msgstr "Ja, ik weet het zeker"
#: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8
@ -1197,7 +1192,7 @@ msgstr "Opslaan en nieuw item"
#: contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing"
msgstr "Opslaan en bewerk opnieuw"
msgstr "Opslaan en opnieuw bewerken"
#: contrib/admin/templates/admin/submit_line.html:7
msgid "Save"
@ -1224,7 +1219,7 @@ msgstr "Wijzigen"
#: contrib/admin/templates/admin/index.html:44
msgid "You don't have permission to edit anything."
msgstr "U heeft geen rechten om iets te wijzigen"
msgstr "U heeft geen rechten om iets te wijzigen."
#: contrib/admin/templates/admin/index.html:52
msgid "Recent Actions"
@ -1380,7 +1375,7 @@ msgstr ""
"de bookmarklet vanuit elke pagina op de site worden gekozen. Let erop dat "
"het soms\n"
"noodzakelijk is dat de computer van waaruit de pagina wordt bekeken intern "
"is\n"
"is.\n"
"(Raadpleeg uw systeembeheerder of uw computer zich op het interne netwerk "
"bevind).<p>\n"
@ -1393,7 +1388,7 @@ msgid ""
"Jumps you from any page to the documentation for the view that generates "
"that page."
msgstr ""
"Spring vanuit elke pagina naar de documentatie voor de view die gegenereerd "
"Springt vanuit elke pagina naar de documentatie voor de view die gegenereerd "
"wordt door die pagina"
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
@ -1406,7 +1401,7 @@ msgid ""
"object."
msgstr ""
"Toont de content-type en unieke ID voor pagina's die een enkel object "
"voorsteld."
"voorstellen."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)"
@ -1414,7 +1409,7 @@ msgstr "Bewerk dit object (huidig venster)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object."
msgstr "Ga naar de beheerpagina voor pagina's die een enkel object weergeven."
msgstr "Gaat naar de beheerpagina voor pagina's die een enkel object weergeven."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)"
@ -1527,7 +1522,7 @@ msgid ""
"password twice so we can verify you typed it in correctly."
msgstr ""
"Vanwege de beveiliging moet u uw oude en twee keer een nieuw "
"wachtwoordinvoeren, zodat we kunnen controleren of er geen typefouten zijn "
"wachtwoord invoeren, zodat we kunnen controleren of er geen typefouten zijn "
"gemaakt."
#: contrib/admin/templates/registration/password_change_form.html:17
@ -1597,7 +1592,7 @@ msgid ""
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
"will use 'flatpages/default.html'."
msgstr ""
"Voorbeeld: 'flatpages/contact_page'. Als deze niet is opgegeven, dan wordt "
"Voorbeeld: 'flatpages/contact_page.html'. Als deze niet is opgegeven, dan wordt "
"'flatpages/default.html' gebruikt."
#: contrib/flatpages/models.py:14
@ -1894,7 +1889,7 @@ msgstr "Een of meerdere verplichte velden zijn niet ingevuld"
#: contrib/comments/views/comments.py:196
#: contrib/comments/views/comments.py:286
msgid "Somebody tampered with the comment form (security violation)"
msgstr "Iemand heeft het opmerkingenformulier gewijzigd (Beveilingsinbreuk)"
msgstr "Iemand heeft het opmerkingenformulier gewijzigd (beveilingsinbreuk)"
#: contrib/comments/views/comments.py:206
#: contrib/comments/views/comments.py:292

View File

@ -55,6 +55,12 @@ var POLISH_MAP = {
'Ź':'Z', 'Ż':'Z'
}
var LATVIAN_MAP = {
'ā':'a', 'č':'c', 'ē':'e', 'ģ':'g', 'ī':'i', 'ķ':'k', 'ļ':'l', 'ņ':'n',
'š':'s', 'ū':'u', 'ž':'z', 'Ā':'A', 'Č':'C', 'Ē':'E', 'Ģ':'G', 'Ī':'i',
'Ķ':'k', 'Ļ':'L', 'Ņ':'N', 'Š':'S', 'Ū':'u', 'Ž':'Z'
}
var ALL_DOWNCODE_MAPS=new Array()
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
@ -64,6 +70,7 @@ ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
ALL_DOWNCODE_MAPS[8]=LATVIAN_MAP
var Downcoder = new Object();
Downcoder.Initialize = function()

View File

@ -12,6 +12,7 @@ from django.utils.safestring import mark_safe
from django.db.models.query import QuerySet
EMPTY_VALUE = '(None)'
DISPLAY_SIZE = 100
class EasyModel(object):
def __init__(self, site, model):
@ -93,8 +94,8 @@ class EasyInstance(object):
def __unicode__(self):
val = smart_unicode(self.instance)
if len(val) > 30:
return val[:30] + u'...'
if len(val) > DISPLAY_SIZE:
return val[:DISPLAY_SIZE] + u'...'
return val
def __str__(self):

View File

@ -24,18 +24,20 @@ class ARPostalCodeField(RegexField):
See http://www.correoargentino.com.ar/consulta_cpa/home.php
"""
default_error_messages = {
'invalid': ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
}
def __init__(self, *args, **kwargs):
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
min_length=4, max_length=8,
error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
*args, **kwargs)
min_length=4, max_length=8, *args, **kwargs)
def clean(self, value):
value = super(ARPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
return u''
if len(value) not in (4, 8):
raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA."))
raise ValidationError(self.error_messages['invalid'])
if len(value) == 8:
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
return value
@ -44,6 +46,11 @@ class ARDNIField(CharField):
"""
A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
"""
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 7 or 8 digits."),
}
def __init__(self, *args, **kwargs):
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
**kwargs)
@ -58,10 +65,9 @@ class ARDNIField(CharField):
if not value.isdigit():
value = value.replace('.', '')
if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers."))
raise ValidationError(self.error_messages['invalid'])
if len(value) not in (7, 8):
raise ValidationError(
ugettext("This field requires 7 or 8 digits."))
raise ValidationError(self.error_messages['max_digits'])
return value
@ -70,9 +76,13 @@ class ARCUITField(RegexField):
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 = {
'invalid': ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
'checksum': ugettext("Invalid CUIT."),
}
def __init__(self, *args, **kwargs):
super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
*args, **kwargs)
def clean(self, value):
@ -85,7 +95,7 @@ class ARCUITField(RegexField):
return u''
value, cd = self._canon(value)
if self._calc_cd(value) != cd:
raise ValidationError(ugettext("Invalid CUIT."))
raise ValidationError(self.error_messages['checksum'])
return self._format(value, cd)
def _canon(self, cuit):

View File

@ -12,14 +12,20 @@ PHONE_DIGITS_RE = re.compile(r'^(\d{10})$')
class AUPostCodeField(RegexField):
"""Australian post code field."""
default_error_messages = {
'invalid': ugettext('Enter a 4 digit post code.'),
}
def __init__(self, *args, **kwargs):
super(AUPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a 4 digit post code.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class AUPhoneNumberField(Field):
"""Australian phone number field."""
default_error_messages = {
'invalid': u'Phone numbers must contain 10 digits.',
}
def clean(self, value):
"""
Validate a phone number. Strips parentheses, whitespace and hyphens.
@ -31,7 +37,7 @@ class AUPhoneNumberField(Field):
phone_match = PHONE_DIGITS_RE.search(value)
if phone_match:
return u'%s' % phone_match.group(1)
raise ValidationError(u'Phone numbers must contain 10 digits.')
raise ValidationError(self.error_messages['invalid'])
class AUStateSelect(Select):
"""

View File

@ -17,13 +17,19 @@ except NameError:
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
class BRZipCodeField(RegexField):
default_error_messages = {
'invalid': _('Enter a zip code in the format XXXXX-XXX.'),
}
def __init__(self, *args, **kwargs):
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
max_length=None, min_length=None,
error_message=_('Enter a zip code in the format XXXXX-XXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class BRPhoneNumberField(Field):
default_error_messages = {
'invalid': _('Phone numbers must be in XX-XXXX-XXXX format.'),
}
def clean(self, value):
super(BRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@ -32,7 +38,7 @@ class BRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(_('Phone numbers must be in XX-XXXX-XXXX format.'))
raise ValidationError(self.error_messages['invalid'])
class BRStateSelect(Select):
"""
@ -48,6 +54,9 @@ class BRStateChoiceField(Field):
A choice field that uses a list of Brazilian states as its choices.
"""
widget = Select
default_error_messages = {
'invalid': _(u'Select a valid brazilian state. That state is not one of the available states.'),
}
def __init__(self, required=True, widget=None, label=None,
initial=None, help_text=None):
@ -65,9 +74,7 @@ class BRStateChoiceField(Field):
return value
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
if value not in valid_values:
raise ValidationError(_(u'Select a valid brazilian state.'
u' That state is not one'
u' of the available states.'))
raise ValidationError(self.error_messages['invalid'])
return value
def DV_maker(v):
@ -83,6 +90,12 @@ class BRCPFField(CharField):
More information:
http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
"""
default_error_messages = {
'invalid': _("Invalid CPF number."),
'max_digits': _("This field requires at most 11 digits or 14 characters."),
'digits_only': _("This field requires only numbers."),
}
def __init__(self, *args, **kwargs):
super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
@ -100,9 +113,9 @@ class BRCPFField(CharField):
try:
int(value)
except ValueError:
raise ValidationError(_("This field requires only numbers."))
raise ValidationError(self.error_messages['digits_only'])
if len(value) != 11:
raise ValidationError(_("This field requires at most 11 digits or 14 characters."))
raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
@ -112,11 +125,17 @@ class BRCPFField(CharField):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
raise ValidationError(_("Invalid CPF number."))
raise ValidationError(self.error_messages['invalid'])
return orig_value
class BRCNPJField(Field):
default_error_messages = {
'invalid': _("Invalid CNPJ number."),
'digits_only': _("This field requires only numbers."),
'max_digits': _("This field requires at least 14 digits"),
}
def clean(self, value):
"""
Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
@ -131,10 +150,9 @@ class BRCNPJField(Field):
try:
int(value)
except ValueError:
raise ValidationError("This field requires only numbers.")
raise ValidationError(self.error_messages['digits_only'])
if len(value) != 14:
raise ValidationError(
_("This field requires at least 14 digits"))
raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
@ -144,7 +162,6 @@ class BRCNPJField(Field):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
raise ValidationError(_("Invalid CNPJ number."))
raise ValidationError(self.error_messages['invalid'])
return orig_value

View File

@ -13,14 +13,20 @@ sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
class CAPostalCodeField(RegexField):
"""Canadian postal code field."""
default_error_messages = {
'invalid': gettext(u'Enter a postal code in the format XXX XXX.'),
}
def __init__(self, *args, **kwargs):
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
max_length=None, min_length=None,
error_message=gettext(u'Enter a postal code in the format XXX XXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class CAPhoneNumberField(Field):
"""Canadian phone number field."""
default_error_messages = {
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
}
def clean(self, value):
"""Validate a phone number.
"""
@ -31,7 +37,7 @@ class CAPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
raise ValidationError(self.error_messages['invalid'])
class CAProvinceField(Field):
"""
@ -39,6 +45,10 @@ class CAProvinceField(Field):
It normalizes the input to the standard two-leter postal service
abbreviation for the given province.
"""
default_error_messages = {
'invalid': u'Enter a Canadian province or territory.',
}
def clean(self, value):
from ca_provinces import PROVINCES_NORMALIZED
super(CAProvinceField, self).clean(value)
@ -53,7 +63,7 @@ class CAProvinceField(Field):
return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError:
pass
raise ValidationError(u'Enter a Canadian province or territory.')
raise ValidationError(self.error_messages['invalid'])
class CAProvinceSelect(Select):
"""
@ -70,23 +80,27 @@ class CASocialInsuranceNumberField(Field):
Checks the following rules to determine whether the number is valid:
* Conforms to the XXX-XXX-XXXX format.
* Conforms to the XXX-XXX-XXX format.
* Passes the check digit process "Luhn Algorithm"
See: http://en.wikipedia.org/wiki/Social_Insurance_Number
"""
default_error_messages = {
'invalid': ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXX format.'),
}
def clean(self, value):
super(CASocialInsuranceNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.')
match = re.match(sin_re, value)
if not match:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
if not self.luhn_checksum_is_valid(check_number):
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
return number
def luhn_checksum_is_valid(self, number):

View File

@ -12,11 +12,13 @@ id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$
phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
class CHZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXX.'),
}
def __init__(self, *args, **kwargs):
super(CHZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class CHPhoneNumberField(Field):
"""
@ -25,6 +27,10 @@ class CHPhoneNumberField(Field):
'0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0XX XXX XX XX'.
"""
default_error_messages = {
'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
}
def clean(self, value):
super(CHPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@ -33,7 +39,7 @@ class CHPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.')
raise ValidationError(self.error_messages['invalid'])
class CHStateSelect(Select):
"""
@ -54,6 +60,10 @@ class CHIdentityCardNumberField(Field):
Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
"""
default_error_messages = {
'invalid': ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.'),
}
def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1]
new_number = given_number
@ -87,23 +97,22 @@ class CHIdentityCardNumberField(Field):
def clean(self, value):
super(CHIdentityCardNumberField, self).clean(value)
error_msg = ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
if not match:
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
if idnumber == '00000000' or \
idnumber == 'A0000000':
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
all_digits = "%s%s%s" % (idnumber, pos9, checksum)
if not self.has_valid_checksum(all_digits):
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
return u'%s%s%s' % (idnumber, pos9, checksum)

View File

@ -25,16 +25,21 @@ class CLRutField(RegexField):
Samples for testing are available from
https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
"""
default_error_messages = {
'invalid': ugettext('Enter a valid Chilean RUT.'),
'strict': ugettext('Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'),
'checksum': ugettext('The Chilean RUT is not valid.'),
}
def __init__(self, *args, **kwargs):
if 'strict' in kwargs:
del kwargs['strict']
super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
error_message=ugettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
*args, **kwargs)
error_message=self.default_error_messages['strict'], *args, **kwargs)
else:
# In non-strict mode, accept RUTs that validate but do not exist in
# the real world.
super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=ugettext('Enter valid a Chilean RUT'), *args, **kwargs)
super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', *args, **kwargs)
def clean(self, value):
"""
@ -47,7 +52,7 @@ class CLRutField(RegexField):
if self._algorithm(rut) == verificador:
return self._format(rut, verificador)
else:
raise ValidationError(u'The Chilean RUT is not valid.')
raise ValidationError(self.error_messages['checksum'])
def _algorithm(self, rut):
"""

View File

@ -10,11 +10,12 @@ import re
id_re = re.compile(r"^(?P<residence>\d{10})(?P<origin>\w{1,3})[-\ ]?(?P<birthday>\d{7})[-\ ]?(?P<validity>\d{7})[-\ ]?(?P<checksum>\d{1})$")
class DEZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs):
super(DEZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class DEStateSelect(Select):
"""
@ -36,6 +37,10 @@ class DEIdentityCardNumberField(Field):
Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis
"""
default_error_messages = {
'invalid': ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'),
}
def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1]
calculated_checksum = 0
@ -57,23 +62,22 @@ class DEIdentityCardNumberField(Field):
def clean(self, value):
super(DEIdentityCardNumberField, self).clean(value)
error_msg = ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.')
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
if not match:
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
gd = match.groupdict()
residence, origin = gd['residence'], gd['origin']
birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
raise ValidationError(error_msg)
raise ValidationError(self.error_messages['invalid'])
return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)

View File

@ -15,12 +15,14 @@ class ESPostalCodeField(RegexField):
Spanish postal code is a five digits string, with two first digits
between 01 and 52, assigned to provinces code.
"""
default_error_messages = {
'invalid': _('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
}
def __init__(self, *args, **kwargs):
super(ESPostalCodeField, self).__init__(
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
max_length=None, min_length=None,
error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class ESPhoneNumberField(RegexField):
"""
@ -33,11 +35,13 @@ class ESPhoneNumberField(RegexField):
TODO: accept and strip characters like dot, hyphen... in phone number
"""
default_error_messages = {
'invalid': _('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
}
def __init__(self, *args, **kwargs):
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
max_length=None, min_length=None,
error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class ESIdentityCardNumberField(RegexField):
"""
@ -58,19 +62,23 @@ class ESIdentityCardNumberField(RegexField):
public, and different authors have different opinions on which ones allows
letters, so both validations are assumed true for all types.
"""
default_error_messages = {
'invalid': _('Please enter a valid NIF, NIE, or CIF.'),
'invalid_only_nif': _('Please enter a valid NIF or NIE.'),
'invalid_nif': _('Invalid checksum for NIF.'),
'invalid_nie': _('Invalid checksum for NIE.'),
'invalid_cif': _('Invalid checksum for CIF.'),
}
def __init__(self, only_nif=False, *args, **kwargs):
self.only_nif = only_nif
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
self.cif_control = 'JABCDEFGHI'
self.cif_types = 'ABCDEFGHKLMNPQS'
self.nie_types = 'XT'
if self.only_nif:
self.id_types = 'NIF or NIE'
else:
self.id_types = 'NIF, NIE, or CIF'
super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()),
max_length=None, min_length=None,
error_message=_('Please enter a valid %s.' % self.id_types),
error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')],
*args, **kwargs)
def clean(self, value):
@ -88,13 +96,13 @@ class ESIdentityCardNumberField(RegexField):
if letter2 == nif_get_checksum(number):
return value
else:
raise ValidationError, _('Invalid checksum for NIF.')
raise ValidationError, self.error_messages['invalid_nif']
elif letter1 in self.nie_types and letter2:
# NIE
if letter2 == nif_get_checksum(number):
return value
else:
raise ValidationError, _('Invalid checksum for NIE.')
raise ValidationError, self.error_messages['invalid_nie']
elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]:
# CIF
if not letter2:
@ -103,9 +111,9 @@ class ESIdentityCardNumberField(RegexField):
if letter2 in [checksum, self.cif_control[checksum]]:
return value
else:
raise ValidationError, _('Invalid checksum for CIF.')
raise ValidationError, self.error_messages['invalid_cif']
else:
raise ValidationError, _('Please enter a valid %s.' % self.id_types)
raise ValidationError, self.error_messages['invalid']
class ESCCCField(RegexField):
"""
@ -130,11 +138,14 @@ class ESCCCField(RegexField):
TODO: allow IBAN validation too
"""
default_error_messages = {
'invalid': _('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
'checksum': _('Invalid checksum for bank account number.'),
}
def __init__(self, *args, **kwargs):
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
max_length=None, min_length=None,
error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
super(ESCCCField, self).clean(value)
@ -147,7 +158,7 @@ class ESCCCField(RegexField):
if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
return value
else:
raise ValidationError, _('Invalid checksum for bank account number.')
raise ValidationError, self.error_messages['checksum']
class ESRegionSelect(Select):
"""

View File

@ -8,11 +8,12 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext
class FIZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs):
super(FIZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class FIMunicipalitySelect(Select):
"""
@ -23,6 +24,10 @@ class FIMunicipalitySelect(Select):
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
class FISocialSecurityNumber(Field):
default_error_messages = {
'invalid': ugettext('Enter a valid Finnish social security number.'),
}
def clean(self, value):
super(FISocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
@ -37,9 +42,9 @@ class FISocialSecurityNumber(Field):
(?P<serial>(\d{3}))
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
if not result:
raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
raise ValidationError(self.error_messages['invalid'])
gd = result.groupdict()
checksum = int(gd['date'] + gd['serial'])
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
return u'%s' % value.upper()
raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
raise ValidationError(self.error_messages['invalid'])

View File

@ -11,11 +11,13 @@ import re
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
class FRZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs):
super(FRZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class FRPhoneNumberField(Field):
"""
@ -24,6 +26,10 @@ class FRPhoneNumberField(Field):
'0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0X XX XX XX XX'.
"""
default_error_messages = {
'invalid': u'Phone numbers must be in 0X XX XX XX XX format.',
}
def clean(self, value):
super(FRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@ -32,7 +38,7 @@ class FRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
raise ValidationError(u'Phone numbers must be in 0X XX XX XX XX format.')
raise ValidationError(self.error_messages['invalid'])
class FRDepartmentSelect(Select):
"""

View File

@ -10,11 +10,13 @@ import re
class INZipCodeField(RegexField):
default_error_messages = {
'invalid': gettext(u'Enter a zip code in the format XXXXXXX.'),
}
def __init__(self, *args, **kwargs):
super(INZipCodeField, self).__init__(r'^\d{6}$',
max_length=None, min_length=None,
error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class INStateField(Field):
"""
@ -22,6 +24,10 @@ class INStateField(Field):
abbreviation. It normalizes the input to the standard two-letter vehicle
registration abbreviation for the given state or union territory
"""
default_error_messages = {
'invalid': u'Enter a Indian state or territory.',
}
def clean(self, value):
from in_states import STATES_NORMALIZED
super(INStateField, self).clean(value)
@ -36,7 +42,7 @@ class INStateField(Field):
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
except KeyError:
pass
raise ValidationError(u'Enter a Indian state or territory.')
raise ValidationError(self.error_messages['invalid'])
class INStateSelect(Select):
"""

View File

@ -13,10 +13,14 @@ class ISIdNumberField(RegexField):
Icelandic identification number (kennitala). This is a number every citizen
of Iceland has.
"""
default_error_messages = {
'invalid': ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.'),
'checksum': ugettext(u'The Icelandic identification number is not valid.'),
}
def __init__(self, *args, **kwargs):
error_msg = ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.')
kwargs['min_length'],kwargs['max_length'] = 10,11
super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs)
super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', *args, **kwargs)
def clean(self, value):
value = super(ISIdNumberField, self).clean(value)
@ -28,7 +32,7 @@ class ISIdNumberField(RegexField):
if self._validate(value):
return self._format(value)
else:
raise ValidationError(ugettext(u'The Icelandic identification number is not valid.'))
raise ValidationError(self.error_messages['checksum'])
def _canonify(self, value):
"""

View File

@ -10,11 +10,12 @@ from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check
import re
class ITZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a valid zip code.'),
}
def __init__(self, *args, **kwargs):
super(ITZipCodeField, self).__init__(r'^\d{5}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a valid zip code.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class ITRegionSelect(Select):
"""
@ -38,11 +39,13 @@ class ITSocialSecurityNumberField(RegexField):
For reference see http://www.agenziaentrate.it/ and search for
'Informazioni sulla codificazione delle persone fisiche'.
"""
err_msg = ugettext(u'Enter a valid Social Security number.')
default_error_messages = {
'invalid': ugettext(u'Enter a valid Social Security number.'),
}
def __init__(self, *args, **kwargs):
super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
max_length=None, min_length=None, error_message=self.err_msg,
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
value = super(ITSocialSecurityNumberField, self).clean(value)
@ -52,26 +55,29 @@ class ITSocialSecurityNumberField(RegexField):
try:
check_digit = ssn_check_digit(value)
except ValueError:
raise ValidationError(self.err_msg)
raise ValidationError(self.error_messages['invalid'])
if not value[15] == check_digit:
raise ValidationError(self.err_msg)
raise ValidationError(self.error_messages['invalid'])
return value
class ITVatNumberField(Field):
"""
A form field that validates Italian VAT numbers (partita IVA).
"""
default_error_messages = {
'invalid': ugettext(u'Enter a valid VAT number.'),
}
def clean(self, value):
value = super(ITVatNumberField, self).clean(value)
if value == u'':
return value
err_msg = ugettext(u'Enter a valid VAT number.')
try:
vat_number = int(value)
except ValueError:
raise ValidationError(err_msg)
raise ValidationError(self.error_messages['invalid'])
vat_number = str(vat_number).zfill(11)
check_digit = vat_number_check_digit(vat_number[0:10])
if not vat_number[10] == check_digit:
raise ValidationError(err_msg)
raise ValidationError(self.error_messages['invalid'])
return smart_unicode(vat_number)

View File

@ -15,11 +15,13 @@ class JPPostalCodeField(RegexField):
Accepts 7 digits, with or without a hyphen.
"""
default_error_messages = {
'invalid': ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
}
def __init__(self, *args, **kwargs):
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
"""

View File

@ -17,18 +17,21 @@ class NLZipCodeField(Field):
"""
A Dutch postal code field.
"""
default_error_messages = {
'invalid': _('Enter a valid postal code'),
}
def clean(self, value):
super(NLZipCodeField, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = _('Enter a valid postal code')
value = value.strip().upper().replace(' ', '')
if not pc_re.search(value):
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
if int(value[:4]) < 1000:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
return u'%s %s' % (value[:4], value[4:])
@ -45,12 +48,15 @@ class NLPhoneNumberField(Field):
"""
A Dutch telephone number field.
"""
default_error_messages = {
'invalid': _('Enter a valid phone number'),
}
def clean(self, value):
super(NLPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = _('Enter a valid phone number')
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
@ -60,7 +66,7 @@ class NLPhoneNumberField(Field):
numeric_re.search(phone_nr[3:]):
return value
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
class NLSoFiNumberField(Field):
"""
@ -68,18 +74,20 @@ class NLSoFiNumberField(Field):
http://nl.wikipedia.org/wiki/Sofinummer
"""
default_error_messages = {
'invalid': _('Enter a valid SoFi number'),
}
def clean(self, value):
super(NLSoFiNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = _('Enter a valid SoFi number')
if not sofi_re.search(value):
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
if int(value) == 0:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
checksum = 0
for i in range(9, 1, -1):
@ -87,6 +95,6 @@ class NLSoFiNumberField(Field):
checksum -= int(value[-1])
if checksum % 11 != 0:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
return value

View File

@ -8,11 +8,13 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext
class NOZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXX.'),
}
def __init__(self, *args, **kwargs):
super(NOZipCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class NOMunicipalitySelect(Select):
"""
@ -27,14 +29,17 @@ class NOSocialSecurityNumber(Field):
"""
Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer
"""
default_error_messages = {
'invalid': ugettext(u'Enter a valid Norwegian social security number.'),
}
def clean(self, value):
super(NOSocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = ugettext(u'Enter a valid Norwegian social security number.')
if not re.match(r'^\d{11}$', value):
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
day = int(value[:2])
month = int(value[2:4])
@ -52,7 +57,7 @@ class NOSocialSecurityNumber(Field):
if 900 <= inum < 1000 and year2 > 39:
self.birthday = datetime.date(1900+year2, month, day)
except ValueError:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
sexnum = int(value[8])
if sexnum % 2 == 0:
@ -68,9 +73,9 @@ class NOSocialSecurityNumber(Field):
return sum([(a * b) for (a, b) in zip(aval, bval)])
if multiply_reduce(digits, weight_1) % 11 != 0:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
if multiply_reduce(digits, weight_2) % 11 != 0:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
return value

View File

@ -19,6 +19,11 @@ class PEDNIField(CharField):
"""
A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers.
"""
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 8 digits."),
}
def __init__(self, *args, **kwargs):
super(PEDNIField, self).__init__(max_length=8, min_length=8, *args,
**kwargs)
@ -31,9 +36,9 @@ class PEDNIField(CharField):
if value in EMPTY_VALUES:
return u''
if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers."))
raise ValidationError(self.error_messages['invalid'])
if len(value) != 8:
raise ValidationError(ugettext("This field requires 8 digits."))
raise ValidationError(self.error_messages['max_digits'])
return value
@ -42,6 +47,11 @@ class PERUCField(RegexField):
This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of
the form XXXXXXXXXXX.
"""
default_error_messages = {
'invalid': ugettext("This field requires only numbers."),
'max_digits': ugettext("This field requires 11 digits."),
}
def __init__(self, *args, **kwargs):
super(PERUCField, self).__init__(max_length=11, min_length=11, *args,
**kwargs)
@ -54,8 +64,8 @@ class PERUCField(RegexField):
if value in EMPTY_VALUES:
return u''
if not value.isdigit():
raise ValidationError(ugettext("This field requires only numbers."))
raise ValidationError(self.error_messages['invalid'])
if len(value) != 11:
raise ValidationError(ugettext("This field requires 11 digits."))
raise ValidationError(self.error_messages['max_digits'])
return value

View File

@ -35,16 +35,19 @@ class PLNationalIdentificationNumberField(RegexField):
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
"""
default_error_messages = {
'invalid': _(u'National Identification Number consists of 11 digits.'),
'checksum': _(u'Wrong checksum for the National Identification Number.'),
}
def __init__(self, *args, **kwargs):
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLNationalIdentificationNumberField, self).clean(value)
if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@ -65,17 +68,20 @@ class PLTaxNumberField(RegexField):
Checksum algorithm based on documentation at
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
"""
default_error_messages = {
'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'),
'checksum': _(u'Wrong checksum for the Tax Number (NIP).'),
}
def __init__(self, *args, **kwargs):
super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
max_length=None, min_length=None,
error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLTaxNumberField, self).clean(value)
value = re.sub("[-]", "", value)
if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the Tax Number (NIP).'))
raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@ -102,15 +108,19 @@ class PLNationalBusinessRegisterField(RegexField):
The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
"""
default_error_messages = {
'invalid': _(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'),
}
def __init__(self, *args, **kwargs):
super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',
max_length=None, min_length=None, error_message=_(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLNationalBusinessRegisterField, self).clean(value)
if not self.has_valid_checksum(value):
raise ValidationError(_(u'Wrong checksum for the National Business Register Number (REGON).'))
raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@ -142,9 +152,10 @@ class PLPostalCodeField(RegexField):
A form field that validates as Polish postal code.
Valid code is XX-XXX where X is digit.
"""
default_error_messages = {
'invalid': _(u'Enter a postal code in the format XX-XXX.'),
}
def __init__(self, *args, **kwargs):
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
max_length=None, min_length=None,
error_message=_(u'Enter a postal code in the format XX-XXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)

View File

@ -26,11 +26,13 @@ class SKPostalCodeField(RegexField):
A form field that validates its input as Slovak postal code.
Valid form is XXXXX or XXX XX, where X represents integer.
"""
default_error_messages = {
'invalid': ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
}
def __init__(self, *args, **kwargs):
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
max_length=None, min_length=None,
error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
"""

View File

@ -2,21 +2,39 @@
UK-specific Form helpers
"""
from django.newforms.fields import RegexField, Select
import re
from django.newforms.fields import CharField, Select
from django.newforms import ValidationError
from django.utils.translation import ugettext
class UKPostcodeField(RegexField):
class UKPostcodeField(CharField):
"""
A form field that validates its input is a UK postcode.
The regular expression used is sourced from the schema for British Standard
BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
The value is uppercased and a space added in the correct place, if required.
"""
def __init__(self, *args, **kwargs):
super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$',
max_length=None, min_length=None,
error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
*args, **kwargs)
default_error_messages = {
'invalid': ugettext(u'Enter a valid postcode.'),
}
outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
incode_pattern = '[0-9][ABD-HJLNP-UW-Z]{2}'
postcode_regex = re.compile(r'^(GIR 0AA|%s %s)$' % (outcode_pattern, incode_pattern))
space_regex = re.compile(r' *(%s)$' % incode_pattern)
def clean(self, value):
value = super(UKPostcodeField, self).clean(value)
if value == u'':
return value
postcode = value.upper().strip()
# Put a single space before the incode (second part).
postcode = self.space_regex.sub(r' \1', postcode)
if not self.postcode_regex.search(postcode):
raise ValidationError(self.default_error_messages['invalid'])
return postcode
class UKCountySelect(Select):
"""

View File

@ -12,13 +12,19 @@ phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$")
class USZipCodeField(RegexField):
default_error_messages = {
'invalid': ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
}
def __init__(self, *args, **kwargs):
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
max_length=None, min_length=None,
error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
*args, **kwargs)
max_length=None, min_length=None, *args, **kwargs)
class USPhoneNumberField(Field):
default_error_messages = {
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
}
def clean(self, value):
super(USPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@ -27,7 +33,7 @@ class USPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
raise ValidationError(self.error_messages['invalid'])
class USSocialSecurityNumberField(Field):
"""
@ -44,28 +50,31 @@ class USSocialSecurityNumberField(Field):
promotional use or distribution (e.g., the Woolworth's number or the
1962 promotional number).
"""
default_error_messages = {
'invalid': ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.'),
}
def clean(self, value):
super(USSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
match = re.match(ssn_re, value)
if not match:
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
# First pass: no blocks of all zeroes.
if area == '000' or \
group == '00' or \
serial == '0000':
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
# Second pass: promotional and otherwise permanently invalid numbers.
if area == '666' or \
(area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \
value == '078-05-1120' or \
value == '219-09-9999':
raise ValidationError(msg)
raise ValidationError(self.error_messages['invalid'])
return u'%s-%s-%s' % (area, group, serial)
class USStateField(Field):
@ -74,6 +83,10 @@ class USStateField(Field):
It normalizes the input to the standard two-leter postal service
abbreviation for the given state.
"""
default_error_messages = {
'invalid': u'Enter a U.S. state or territory.',
}
def clean(self, value):
from us_states import STATES_NORMALIZED
super(USStateField, self).clean(value)
@ -88,7 +101,7 @@ class USStateField(Field):
return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError:
pass
raise ValidationError(u'Enter a U.S. state or territory.')
raise ValidationError(self.error_messages['invalid'])
class USStateSelect(Select):
"""

View File

@ -16,10 +16,9 @@ class ZAIDField(Field):
using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
check for the birthdate
"""
def __init__(self, *args, **kwargs):
super(ZAIDField, self).__init__()
self.error_message = _(u'Enter a valid South African ID number')
default_error_messages = {
'invalid': _(u'Enter a valid South African ID number'),
}
def clean(self, value):
# strip spaces and dashes
@ -33,7 +32,7 @@ class ZAIDField(Field):
match = re.match(id_re, value)
if not match:
raise ValidationError(self.error_message)
raise ValidationError(self.error_messages['invalid'])
g = match.groupdict()
@ -43,15 +42,18 @@ class ZAIDField(Field):
# There is no way to guess the century of a ZA ID number
d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
except ValueError:
raise ValidationError(self.error_message)
raise ValidationError(self.error_messages['invalid'])
if not luhn(value):
raise ValidationError(self.error_message)
raise ValidationError(self.error_messages['invalid'])
return value
class ZAPostCodeField(RegexField):
default_error_messages = {
'invalid': _(u'Enter a valid South African postal code'),
}
def __init__(self, *args, **kwargs):
super(ZAPostCodeField, self).__init__(r'^\d{4}$',
max_length=None, min_length=None,
error_message=_(u'Enter a valid South African postal code'))
max_length=None, min_length=None)

View File

@ -67,11 +67,10 @@ def make_msgid(idstring=None):
class BadHeaderError(ValueError):
pass
class SafeMIMEText(MIMEText):
def __setitem__(self, name, val):
def forbid_multi_line_headers(name, val):
"Forbids multi-line headers, to prevent header injection."
if '\n' in val or '\r' in val:
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
try:
val = force_unicode(val).encode('ascii')
except UnicodeEncodeError:
@ -84,25 +83,16 @@ class SafeMIMEText(MIMEText):
val = ', '.join(result)
else:
val = Header(force_unicode(val), settings.DEFAULT_CHARSET)
return name, val
class SafeMIMEText(MIMEText):
def __setitem__(self, name, val):
name, val = forbid_multi_line_headers(name, val)
MIMEText.__setitem__(self, name, val)
class SafeMIMEMultipart(MIMEMultipart):
def __setitem__(self, name, val):
"Forbids multi-line headers, to prevent header injection."
if '\n' in val or '\r' in val:
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
try:
val = force_unicode(val).encode('ascii')
except UnicodeEncodeError:
if name.lower() in ('to', 'from', 'cc'):
result = []
for item in val.split(', '):
nm, addr = parseaddr(item)
nm = str(Header(nm, settings.DEFAULT_CHARSET))
result.append(formataddr((nm, str(addr))))
val = ', '.join(result)
else:
val = Header(force_unicode(val), settings.DEFAULT_CHARSET)
name, val = forbid_multi_line_headers(name, val)
MIMEMultipart.__setitem__(self, name, val)
class SMTPConnection(object):
@ -209,8 +199,14 @@ class EmailMessage(object):
bytestrings). The SafeMIMEText class will handle any necessary encoding
conversions.
"""
self.to = to or []
self.bcc = bcc or []
if to:
self.to = list(to)
else:
self.to = []
if bcc:
self.bcc = list(bcc)
else:
self.bcc = []
self.from_email = from_email or settings.DEFAULT_FROM_EMAIL
self.subject = subject
self.body = body

View File

@ -27,6 +27,8 @@ class BaseCommand(object):
help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.'),
make_option('--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
make_option('--traceback', action='store_true',
help='Print traceback on exception'),
)
help = ''
args = ''

View File

@ -1,11 +1,12 @@
from django.core.management.base import BaseCommand, CommandError
from django.core import serializers
from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--format', default='json', dest='format',
help='Specifies the output serialization format for fixtures'),
help='Specifies the output serialization format for fixtures.'),
make_option('--indent', default=None, dest='indent', type='int',
help='Specifies the indent level to use when pretty-printing output'),
)
@ -14,10 +15,10 @@ class Command(BaseCommand):
def handle(self, *app_labels, **options):
from django.db.models import get_app, get_apps, get_models
from django.core import serializers
format = options.get('format', 'json')
indent = options.get('indent', None)
show_traceback = options.get('traceback', False)
if len(app_labels) == 0:
app_list = get_apps()
@ -26,6 +27,9 @@ class Command(BaseCommand):
# Check that the serialization format exists; this is a shortcut to
# avoid collating all the objects and _then_ failing.
if format not in serializers.get_public_serializer_formats():
raise CommandError("Unknown serialization format: %s" % format)
try:
serializers.get_serializer(format)
except KeyError:
@ -34,8 +38,10 @@ class Command(BaseCommand):
objects = []
for app in app_list:
for model in get_models(app):
objects.extend(model.objects.all())
objects.extend(model._default_manager.all())
try:
return serializers.serialize(format, objects, indent=indent)
except Exception, e:
if show_traceback:
raise
raise CommandError("Unable to serialize database: %s" % e)

View File

@ -27,6 +27,7 @@ class Command(BaseCommand):
self.style = no_style()
verbosity = int(options.get('verbosity', 1))
show_traceback = options.get('traceback', False)
# Keep a count of the installed objects and fixtures
count = [0, 0]
@ -50,10 +51,10 @@ class Command(BaseCommand):
parts = fixture_label.split('.')
if len(parts) == 1:
fixture_name = fixture_label
formats = serializers.get_serializer_formats()
formats = serializers.get_public_serializer_formats()
else:
fixture_name, format = '.'.join(parts[:-1]), parts[-1]
if format in serializers.get_serializer_formats():
if format in serializers.get_public_serializer_formats():
formats = [format]
else:
formats = []
@ -98,11 +99,13 @@ class Command(BaseCommand):
label_found = True
except Exception, e:
fixture.close()
transaction.rollback()
transaction.leave_transaction_management()
if show_traceback:
raise
sys.stderr.write(
self.style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, str(e))))
transaction.rollback()
transaction.leave_transaction_management()
return
fixture.close()
except:

View File

@ -116,6 +116,7 @@ def sql_delete(app, style):
"Returns a list of the DROP TABLE SQL statements for the given app."
from django.db import connection, models, get_introspection_module
from django.db.backends.util import truncate_name
from django.contrib.contenttypes import generic
introspection = get_introspection_module()
# This should work even if a connection isn't available
@ -179,6 +180,8 @@ def sql_delete(app, style):
for model in app_models:
opts = model._meta
for f in opts.many_to_many:
if isinstance(f.rel, generic.GenericRel):
continue
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(qn(f.m2m_db_table()))))

View File

@ -53,6 +53,11 @@ def get_serializer_formats():
_load_serializers()
return _serializers.keys()
def get_public_serializer_formats():
if not _serializers:
_load_serializers()
return [k for k, v in _serializers.iteritems() if not v.Serializer.internal_use_only]
def get_deserializer(format):
if not _serializers:
_load_serializers()

View File

@ -22,6 +22,10 @@ class Serializer(object):
Abstract serializer base class.
"""
# Indicates if the implemented serializer is only available for
# internal Django use.
internal_use_only = False
def serialize(self, queryset, **options):
"""
Serialize a queryset.

View File

@ -20,6 +20,8 @@ class Serializer(PythonSerializer):
"""
Convert a queryset to JSON.
"""
internal_use_only = False
def end_serialization(self):
self.options.pop('stream', None)
self.options.pop('fields', None)

View File

@ -14,6 +14,8 @@ class Serializer(base.Serializer):
Serializes a QuerySet to basic Python objects.
"""
internal_use_only = True
def start_serialization(self):
self._current = None
self.objects = []

View File

@ -19,6 +19,8 @@ class Serializer(PythonSerializer):
Convert a queryset to YAML.
"""
internal_use_only = False
def handle_field(self, obj, field):
# A nasty special case: base YAML doesn't support serialization of time
# types (as opposed to dates or datetimes, which it does support). Since

View File

@ -398,6 +398,18 @@ class ServerHandler(object):
self.bytes_sent += len(data)
# XXX check Content-Length and truncate if too many bytes written?
# If data is too large, socket will choke, so write chunks no larger
# than 32MB at a time.
length = len(data)
if length > 33554432:
offset = 0
while offset < length:
chunk_size = min(33554432, length)
self._write(data[offset:offset+chunk_size])
self._flush()
offset += chunk_size
else:
self._write(data)
self._flush()

View File

@ -413,6 +413,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
return self.connection is not None
def _cursor(self, settings):
cursor = None
if not self._valid_connection():
if len(settings.DATABASE_HOST.strip()) == 0:
settings.DATABASE_HOST = 'localhost'
@ -422,16 +423,25 @@ class DatabaseWrapper(BaseDatabaseWrapper):
else:
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
self.connection = Database.connect(conn_string, **self.options)
cursor = FormatStylePlaceholderCursor(self.connection)
# Set oracle date to ansi date format. This only needs to execute
# once when we create a new connection.
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD' "
"NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
try:
self.oracle_version = int(self.connection.version.split('.')[0])
except ValueError:
pass
try:
self.connection.stmtcachesize = 20
except:
# Django docs specify cx_Oracle version 4.3.1 or higher, but
# stmtcachesize is available only in 4.3.2 and up.
pass
if not cursor:
cursor = FormatStylePlaceholderCursor(self.connection)
# Default arraysize of 1 is highly sub-optimal.
cursor.arraysize = 100
# Set oracle date to ansi date format.
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'")
cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
return cursor
class FormatStylePlaceholderCursor(Database.Cursor):

View File

@ -910,6 +910,11 @@ class NullBooleanField(Field):
def get_manipulator_field_objs(self):
return [oldforms.NullBooleanField]
def formfield(self, **kwargs):
defaults = {'form_class': forms.NullBooleanField}
defaults.update(kwargs)
return super(NullBooleanField, self).formfield(**defaults)
class PhoneNumberField(IntegerField):
def get_manipulator_field_objs(self):
return [oldforms.PhoneNumberField]

View File

@ -277,7 +277,20 @@ class HttpResponse(object):
for key, value in self._headers.values()]) \
+ '\n\n' + self.content
def _convert_to_ascii(self, *values):
"Convert all values to ascii strings"
for value in values:
if isinstance(value, unicode):
try:
yield value.encode('us-ascii')
except UnicodeError, e:
e.reason += ', HTTP response headers must be in US-ASCII format'
raise
else:
yield str(value)
def __setitem__(self, header, value):
header, value = self._convert_to_ascii(header, value)
self._headers[header.lower()] = (header, value)
def __delitem__(self, header):

View File

@ -84,9 +84,8 @@ def form_for_model(model, form=BaseForm, fields=None,
determining the formfield for a given database field. It's a callable that
takes a database Field instance and returns a form Field instance.
"""
warn("form_for_model is deprecated, use ModelForm instead.",
PendingDeprecationWarning,
stacklevel=3)
warn("form_for_model is deprecated. Use ModelForm instead.",
PendingDeprecationWarning, stacklevel=3)
opts = model._meta
field_list = []
for f in opts.fields + opts.many_to_many:
@ -114,9 +113,8 @@ def form_for_instance(instance, form=BaseForm, fields=None,
takes a database Field instance, plus **kwargs, and returns a form Field
instance with the given kwargs (i.e. 'initial').
"""
warn("form_for_instance is deprecated, use ModelForm instead.",
PendingDeprecationWarning,
stacklevel=3)
warn("form_for_instance is deprecated. Use ModelForm instead.",
PendingDeprecationWarning, stacklevel=3)
model = instance.__class__
opts = model._meta
field_list = []
@ -214,9 +212,8 @@ class ModelFormOptions(object):
self.exclude = getattr(options, 'exclude', None)
class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs):
# TODO: no way to specify formfield_callback yet, do we need one, or
# should it be a special case for the admin?
def __new__(cls, name, bases, attrs,
formfield_callback=lambda f: f.formfield()):
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
@ -253,7 +250,8 @@ class ModelFormMetaclass(type):
base_model = getattr(base_opts, 'model', None)
if base_model and base_model is not opts.model:
raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
model_fields = fields_for_model(opts.model, opts.fields, opts.exclude)
model_fields = fields_for_model(opts.model, opts.fields,
opts.exclude, formfield_callback)
# fields declared in base classes override fields from the model
model_fields.update(declared_fields)
attrs['base_fields'] = model_fields

View File

@ -154,15 +154,12 @@ class StringOrigin(Origin):
class Template(object):
def __init__(self, template_string, origin=None, name='<Unknown Template>'):
"Compilation stage"
try:
template_string = smart_unicode(template_string)
except UnicodeDecodeError:
raise TemplateEncodingError("Templates can only be constructed from unicode or UTF-8 strings.")
if settings.TEMPLATE_DEBUG and origin == None:
if settings.TEMPLATE_DEBUG and origin is None:
origin = StringOrigin(template_string)
# Could do some crazy stack-frame stuff to record where this string
# came from...
self.nodelist = compile_string(template_string, origin)
self.name = name
@ -177,13 +174,18 @@ class Template(object):
def compile_string(template_string, origin):
"Compiles template_string into NodeList ready for rendering"
lexer = lexer_factory(template_string, origin)
parser = parser_factory(lexer.tokenize())
if settings.TEMPLATE_DEBUG:
from debug import DebugLexer, DebugParser
lexer_class, parser_class = DebugLexer, DebugParser
else:
lexer_class, parser_class = Lexer, Parser
lexer = lexer_class(template_string, origin)
parser = parser_class(lexer.tokenize())
return parser.parse()
class Token(object):
def __init__(self, token_type, contents):
"The token_type must be TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK or TOKEN_COMMENT"
# token_type must be TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK or TOKEN_COMMENT.
self.token_type, self.contents = token_type, contents
def __str__(self):
@ -200,7 +202,7 @@ class Lexer(object):
self.origin = origin
def tokenize(self):
"Return a list of tokens from a given template_string"
"Return a list of tokens from a given template_string."
in_tag = False
result = []
for bit in tag_re.split(self.template_string):
@ -226,30 +228,6 @@ class Lexer(object):
token = Token(TOKEN_TEXT, token_string)
return token
class DebugLexer(Lexer):
def __init__(self, template_string, origin):
super(DebugLexer, self).__init__(template_string, origin)
def tokenize(self):
"Return a list of tokens from a given template_string"
result, upto = [], 0
for match in tag_re.finditer(self.template_string):
start, end = match.span()
if start > upto:
result.append(self.create_token(self.template_string[upto:start], (upto, start), False))
upto = start
result.append(self.create_token(self.template_string[start:end], (start, end), True))
upto = end
last_bit = self.template_string[upto:]
if last_bit:
result.append(self.create_token(last_bit, (upto, upto + len(last_bit)), False))
return result
def create_token(self, token_string, source, in_tag):
token = super(DebugLexer, self).create_token(token_string, in_tag)
token.source = self.origin, source
return token
class Parser(object):
def __init__(self, tokens):
self.tokens = tokens
@ -319,17 +297,17 @@ class Parser(object):
def exit_command(self):
pass
def error(self, token, msg ):
def error(self, token, msg):
return TemplateSyntaxError(msg)
def empty_variable(self, token):
raise self.error( token, "Empty variable tag")
raise self.error(token, "Empty variable tag")
def empty_block_tag(self, token):
raise self.error( token, "Empty block tag")
raise self.error(token, "Empty block tag")
def invalid_block_tag(self, token, command):
raise self.error( token, "Invalid block tag: '%s'" % command)
raise self.error(token, "Invalid block tag: '%s'" % command)
def unclosed_block_tag(self, parse_until):
raise self.error(None, "Unclosed tags: %s " % ', '.join(parse_until))
@ -358,57 +336,7 @@ class Parser(object):
if filter_name in self.filters:
return self.filters[filter_name]
else:
raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name
class DebugParser(Parser):
def __init__(self, lexer):
super(DebugParser, self).__init__(lexer)
self.command_stack = []
def enter_command(self, command, token):
self.command_stack.append( (command, token.source) )
def exit_command(self):
self.command_stack.pop()
def error(self, token, msg):
return self.source_error(token.source, msg)
def source_error(self, source,msg):
e = TemplateSyntaxError(msg)
e.source = source
return e
def create_nodelist(self):
return DebugNodeList()
def create_variable_node(self, contents):
return DebugVariableNode(contents)
def extend_nodelist(self, nodelist, node, token):
node.source = token.source
super(DebugParser, self).extend_nodelist(nodelist, node, token)
def unclosed_block_tag(self, parse_until):
command, source = self.command_stack.pop()
msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until))
raise self.source_error( source, msg)
def compile_function_error(self, token, e):
if not hasattr(e, 'source'):
e.source = token.source
def lexer_factory(*args, **kwargs):
if settings.TEMPLATE_DEBUG:
return DebugLexer(*args, **kwargs)
else:
return Lexer(*args, **kwargs)
def parser_factory(*args, **kwargs):
if settings.TEMPLATE_DEBUG:
return DebugParser(*args, **kwargs)
else:
return Parser(*args, **kwargs)
raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name)
class TokenParser(object):
"""
@ -426,7 +354,7 @@ class TokenParser(object):
def top(self):
"Overload this method to do the actual parsing and return the result."
raise NotImplemented
raise NotImplementedError()
def more(self):
"Returns True if there is more stuff in the tag."
@ -435,7 +363,7 @@ class TokenParser(object):
def back(self):
"Undoes the last microparser. Use this for lookahead and backtracking."
if not len(self.backout):
raise TemplateSyntaxError, "back called without some previous parsing"
raise TemplateSyntaxError("back called without some previous parsing")
self.pointer = self.backout.pop()
def tag(self):
@ -443,7 +371,7 @@ class TokenParser(object):
subject = self.subject
i = self.pointer
if i >= len(subject):
raise TemplateSyntaxError, "expected another tag, found end of string: %s" % subject
raise TemplateSyntaxError("expected another tag, found end of string: %s" % subject)
p = i
while i < len(subject) and subject[i] not in (' ', '\t'):
i += 1
@ -459,14 +387,14 @@ class TokenParser(object):
subject = self.subject
i = self.pointer
if i >= len(subject):
raise TemplateSyntaxError, "Searching for value. Expected another value but found end of string: %s" % subject
raise TemplateSyntaxError("Searching for value. Expected another value but found end of string: %s" % subject)
if subject[i] in ('"', "'"):
p = i
i += 1
while i < len(subject) and subject[i] != subject[p]:
i += 1
if i >= len(subject):
raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject)
raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
i += 1
res = subject[p:i]
while i < len(subject) and subject[i] in (' ', '\t'):
@ -483,7 +411,7 @@ class TokenParser(object):
while i < len(subject) and subject[i] != c:
i += 1
if i >= len(subject):
raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject)
raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
i += 1
s = subject[p:i]
while i < len(subject) and subject[i] in (' ', '\t'):
@ -542,8 +470,8 @@ class FilterExpression(object):
for match in matches:
start = match.start()
if upto != start:
raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s" % \
(token[:upto], token[upto:start], token[start:])
raise TemplateSyntaxError("Could not parse some characters: %s|%s|%s" % \
(token[:upto], token[upto:start], token[start:]))
if var == None:
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
if i18n_constant:
@ -552,9 +480,9 @@ class FilterExpression(object):
var = '"%s"' % constant.replace(r'\"', '"')
upto = match.end()
if var == None:
raise TemplateSyntaxError, "Could not find variable at start of %s" % token
raise TemplateSyntaxError("Could not find variable at start of %s" % token)
elif var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_':
raise TemplateSyntaxError, "Variables and attributes may not begin with underscores: '%s'" % var
raise TemplateSyntaxError("Variables and attributes may not begin with underscores: '%s'" % var)
else:
filter_name = match.group("filter_name")
args = []
@ -570,7 +498,7 @@ class FilterExpression(object):
filters.append( (filter_func,args))
upto = match.end()
if upto != len(token):
raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
raise TemplateSyntaxError("Could not parse the remainder: '%s' from '%s'" % (token[upto:], token))
self.filters = filters
self.var = Variable(var)
@ -627,7 +555,7 @@ class FilterExpression(object):
provided.pop(0)
except IndexError:
# Not enough
raise TemplateSyntaxError, "%s requires %d arguments, %d provided" % (name, len(nondefs), plen)
raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen))
# Defaults can be overridden.
defaults = defaults and list(defaults) or []
@ -636,7 +564,7 @@ class FilterExpression(object):
defaults.pop(0)
except IndexError:
# Too many.
raise TemplateSyntaxError, "%s requires %d arguments, %d provided" % (name, len(nondefs), plen)
raise TemplateSyntaxError("%s requires %d arguments, %d provided" % (name, len(nondefs), plen))
return True
args_check = staticmethod(args_check)
@ -816,22 +744,6 @@ class NodeList(list):
def render_node(self, node, context):
return node.render(context)
class DebugNodeList(NodeList):
def render_node(self, node, context):
try:
result = node.render(context)
except TemplateSyntaxError, e:
if not hasattr(e, 'source'):
e.source = node.source
raise
except Exception, e:
from sys import exc_info
wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
wrapped.source = node.source
wrapped.exc_info = exc_info()
raise wrapped
return result
class TextNode(Node):
def __init__(self, s):
self.s = s
@ -861,21 +773,6 @@ class VariableNode(Node):
else:
return force_unicode(output)
class DebugVariableNode(VariableNode):
def render(self, context):
try:
output = force_unicode(self.filter_expression.resolve(context))
except TemplateSyntaxError, e:
if not hasattr(e, 'source'):
e.source = self.source
raise
except UnicodeDecodeError:
return ''
if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
return escape(output)
else:
return output
def generic_tag_compiler(params, defaults, name, node_class, parser, token):
"Returns a template.Node subclass."
bits = token.split_contents()[1:]
@ -887,7 +784,7 @@ def generic_tag_compiler(params, defaults, name, node_class, parser, token):
message = "%s takes %s arguments" % (name, bmin)
else:
message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
raise TemplateSyntaxError, message
raise TemplateSyntaxError(message)
return node_class(bits)
class Library(object):
@ -913,7 +810,7 @@ class Library(object):
self.tags[name] = compile_function
return compile_function
else:
raise InvalidTemplateLibrary, "Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function)
raise InvalidTemplateLibrary("Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function))
def tag_function(self,func):
self.tags[getattr(func, "_decorated_function", func).__name__] = func
@ -937,7 +834,7 @@ class Library(object):
self.filters[name] = filter_func
return filter_func
else:
raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r)", (name, filter_func)
raise InvalidTemplateLibrary("Unsupported arguments to Library.filter: (%r, %r)", (name, filter_func))
def filter_function(self, func):
self.filters[getattr(func, "_decorated_function", func).__name__] = func
@ -966,7 +863,7 @@ class Library(object):
if params[0] == 'context':
params = params[1:]
else:
raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'"
raise TemplateSyntaxError("Any tag function decorated with takes_context=True must have a first argument of 'context'")
class InclusionNode(Node):
def __init__(self, vars_to_resolve):
@ -1003,12 +900,12 @@ def get_library(module_name):
try:
mod = __import__(module_name, {}, {}, [''])
except ImportError, e:
raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e)
raise InvalidTemplateLibrary("Could not load template library from %s, %s" % (module_name, e))
try:
lib = mod.register
libraries[module_name] = lib
except AttributeError:
raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % module_name
raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % module_name)
return lib
def add_to_builtins(module_name):

View File

@ -9,7 +9,6 @@ class ContextPopException(Exception):
class Context(object):
"A stack container for variable context"
def __init__(self, dict_=None, autoescape=True):
dict_ = dict_ or {}
self.dicts = [dict_]
@ -78,11 +77,11 @@ def get_standard_processors():
try:
mod = __import__(module, {}, {}, [attr])
except ImportError, e:
raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e)
raise ImproperlyConfigured('Error importing request processor module %s: "%s"' % (module, e))
try:
func = getattr(mod, attr)
except AttributeError:
raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable request processor' % (module, attr)
raise ImproperlyConfigured('Module "%s" does not define a "%s" callable request processor' % (module, attr))
processors.append(func)
_standard_context_processors = tuple(processors)
return _standard_context_processors
@ -102,4 +101,3 @@ class RequestContext(Context):
processors = tuple(processors)
for processor in get_standard_processors() + processors:
self.update(processor(request))

97
django/template/debug.py Normal file
View File

@ -0,0 +1,97 @@
from django.template import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError
from django.utils.encoding import force_unicode
from django.utils.html import escape
from django.utils.safestring import SafeData, EscapeData
class DebugLexer(Lexer):
def __init__(self, template_string, origin):
super(DebugLexer, self).__init__(template_string, origin)
def tokenize(self):
"Return a list of tokens from a given template_string"
result, upto = [], 0
for match in tag_re.finditer(self.template_string):
start, end = match.span()
if start > upto:
result.append(self.create_token(self.template_string[upto:start], (upto, start), False))
upto = start
result.append(self.create_token(self.template_string[start:end], (start, end), True))
upto = end
last_bit = self.template_string[upto:]
if last_bit:
result.append(self.create_token(last_bit, (upto, upto + len(last_bit)), False))
return result
def create_token(self, token_string, source, in_tag):
token = super(DebugLexer, self).create_token(token_string, in_tag)
token.source = self.origin, source
return token
class DebugParser(Parser):
def __init__(self, lexer):
super(DebugParser, self).__init__(lexer)
self.command_stack = []
def enter_command(self, command, token):
self.command_stack.append( (command, token.source) )
def exit_command(self):
self.command_stack.pop()
def error(self, token, msg):
return self.source_error(token.source, msg)
def source_error(self, source,msg):
e = TemplateSyntaxError(msg)
e.source = source
return e
def create_nodelist(self):
return DebugNodeList()
def create_variable_node(self, contents):
return DebugVariableNode(contents)
def extend_nodelist(self, nodelist, node, token):
node.source = token.source
super(DebugParser, self).extend_nodelist(nodelist, node, token)
def unclosed_block_tag(self, parse_until):
command, source = self.command_stack.pop()
msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until))
raise self.source_error(source, msg)
def compile_function_error(self, token, e):
if not hasattr(e, 'source'):
e.source = token.source
class DebugNodeList(NodeList):
def render_node(self, node, context):
try:
result = node.render(context)
except TemplateSyntaxError, e:
if not hasattr(e, 'source'):
e.source = node.source
raise
except Exception, e:
from sys import exc_info
wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
wrapped.source = node.source
wrapped.exc_info = exc_info()
raise wrapped
return result
class DebugVariableNode(VariableNode):
def render(self, context):
try:
output = force_unicode(self.filter_expression.resolve(context))
except TemplateSyntaxError, e:
if not hasattr(e, 'source'):
e.source = self.source
raise
except UnicodeDecodeError:
return ''
if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
return escape(output)
else:
return output

View File

@ -254,7 +254,7 @@ urlize.is_safe=True
urlize.needs_autoescape = True
urlize = stringfilter(urlize)
def urlizetrunc(value, limit):
def urlizetrunc(value, limit, autoescape=None):
"""
Converts URLs into clickable links, truncating URLs to the given character
limit, and adding 'rel=nofollow' attribute to discourage spamming.
@ -262,8 +262,10 @@ def urlizetrunc(value, limit):
Argument: Length to truncate URLs to.
"""
from django.utils.html import urlize
return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True))
return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True,
autoescape=autoescape))
urlizetrunc.is_safe = True
urlizetrunc.needs_autoescape = True
urlizetrunc = stringfilter(urlizetrunc)
def wordcount(value):

View File

@ -84,19 +84,16 @@ class FirstOfNode(Node):
return u''
class ForNode(Node):
def __init__(self, loopvars, sequence, reversed, nodelist_loop):
def __init__(self, loopvars, sequence, is_reversed, nodelist_loop):
self.loopvars, self.sequence = loopvars, sequence
self.reversed = reversed
self.is_reversed = is_reversed
self.nodelist_loop = nodelist_loop
def __repr__(self):
if self.reversed:
reversed = ' reversed'
else:
reversed = ''
reversed_text = self.is_reversed and ' reversed' or ''
return "<For Node: for %s in %s, tail_len: %d%s>" % \
(', '.join(self.loopvars), self.sequence, len(self.nodelist_loop),
reversed)
reversed_text)
def __iter__(self):
for node in self.nodelist_loop:
@ -125,22 +122,23 @@ class ForNode(Node):
if not hasattr(values, '__len__'):
values = list(values)
len_values = len(values)
if self.reversed:
if self.is_reversed:
values = reversed(values)
unpack = len(self.loopvars) > 1
# Create a forloop value in the context. We'll update counters on each
# iteration just below.
loop_dict = context['forloop'] = {'parentloop': parentloop}
for i, item in enumerate(values):
context['forloop'] = {
# Shortcuts for current loop iteration number.
'counter0': i,
'counter': i+1,
loop_dict['counter0'] = i
loop_dict['counter'] = i+1
# Reverse counter iteration numbers.
'revcounter': len_values - i,
'revcounter0': len_values - i - 1,
loop_dict['revcounter'] = len_values - i
loop_dict['revcounter0'] = len_values - i - 1
# Boolean values designating first and last times through loop.
'first': (i == 0),
'last': (i == len_values - 1),
'parentloop': parentloop,
}
loop_dict['first'] = (i == 0)
loop_dict['last'] = (i == len_values - 1)
if unpack:
# If there are multiple loop variables, unpack the item into
# them.
@ -619,8 +617,8 @@ def do_for(parser, token):
raise TemplateSyntaxError("'for' statements should have at least four"
" words: %s" % token.contents)
reversed = bits[-1] == 'reversed'
in_index = reversed and -3 or -2
is_reversed = bits[-1] == 'reversed'
in_index = is_reversed and -3 or -2
if bits[in_index] != 'in':
raise TemplateSyntaxError("'for' statements should use the format"
" 'for x in y': %s" % token.contents)
@ -634,7 +632,7 @@ def do_for(parser, token):
sequence = parser.compile_filter(bits[in_index+1])
nodelist_loop = parser.parse(('endfor',))
parser.delete_first_token()
return ForNode(loopvars, sequence, reversed, nodelist_loop)
return ForNode(loopvars, sequence, is_reversed, nodelist_loop)
do_for = register.tag("for", do_for)
def do_ifequal(parser, token, negate):
@ -814,7 +812,7 @@ def ssi(parser, token):
Outputs the contents of a given file into the page.
Like a simple "include" tag, the ``ssi`` tag includes the contents
of another file -- which must be specified using an absolute page --
of another file -- which must be specified using an absolute path --
in the current page::
{% ssi /home/html/ljworld.com/includes/right_generic.html %}
@ -926,20 +924,18 @@ def regroup(parser, token):
{% regroup people|dictsort:"gender" by gender as grouped %}
"""
firstbits = token.contents.split(None, 3)
if len(firstbits) != 4:
bits = token.contents.split()
if len(bits) != 6:
raise TemplateSyntaxError, "'regroup' tag takes five arguments"
target = parser.compile_filter(firstbits[1])
if firstbits[2] != 'by':
target = parser.compile_filter(bits[1])
if bits[2] != 'by':
raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'")
lastbits_reversed = firstbits[3][::-1].split(None, 2)
if lastbits_reversed[1][::-1] != 'as':
if bits[4] != 'as':
raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
" be 'as'")
expression = parser.compile_filter(lastbits_reversed[2][::-1])
var_name = lastbits_reversed[0][::-1]
expression = parser.compile_filter(bits[3])
var_name = bits[5]
return RegroupNode(target, expression, var_name)
regroup = register.tag(regroup)

View File

@ -1,4 +1,4 @@
import sys, time
import sys, time, os
from django.conf import settings
from django.db import connection, get_creation_module
from django.core import mail
@ -106,8 +106,31 @@ def create_test_db(verbosity=1, autoclobber=False):
if verbosity >= 1:
print "Creating test database..."
# If we're using SQLite, it's more convenient to test against an
# in-memory database.
# in-memory database. Using the TEST_DATABASE_NAME setting you can still choose
# to run on a physical database.
if settings.DATABASE_ENGINE == "sqlite3":
if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
# Erase the old test database
if verbosity >= 1:
print "Destroying old test database..."
if os.access(TEST_DATABASE_NAME, os.F_OK):
if not autoclobber:
confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
print "Destroying old test database..."
os.remove(TEST_DATABASE_NAME)
except Exception, e:
sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
sys.exit(2)
else:
print "Tests cancelled."
sys.exit(1)
if verbosity >= 1:
print "Creating test database..."
else:
TEST_DATABASE_NAME = ":memory:"
else:
suffix = {
@ -171,17 +194,20 @@ def destroy_test_db(old_database_name, verbosity=1):
creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)
return
# Unless we're using SQLite, remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
# connected to it.
if verbosity >= 1:
print "Destroying test database..."
connection.close()
TEST_DATABASE_NAME = settings.DATABASE_NAME
settings.DATABASE_NAME = old_database_name
if settings.DATABASE_ENGINE != "sqlite3":
if settings.DATABASE_ENGINE == "sqlite3":
if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":
# Remove the SQLite database file
os.remove(TEST_DATABASE_NAME)
else:
# Remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it's not allowed to delete a database while being
# connected to it.
cursor = connection.cursor()
_set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.

View File

@ -507,7 +507,7 @@ Exception Type: {{ exception_type|escape }} at {{ request.path|escape }}
Exception Value: {{ exception_value|escape }}
</textarea>
<br><br>
<input type="submit" value="Share this traceback on public Web site">
<input type="submit" value="Share this traceback on a public Web site">
</div>
</form>
</div>

View File

@ -59,10 +59,11 @@ def serve(request, path, document_root=None, show_indexes=False):
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
return HttpResponseNotModified()
mimetype = mimetypes.guess_type(fullpath)[0]
mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream'
contents = open(fullpath, 'rb').read()
response = HttpResponse(contents, mimetype=mimetype)
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
response["Content-Length"] = len(contents)
return response
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """

View File

@ -47,7 +47,11 @@ contenttypes
============
A light framework for hooking into "types" of content, where each installed
Django model is a separate content type. This is not yet documented.
Django model is a separate content type.
See the `contenttypes documentation`_.
.. _contenttypes documentation: ../contenttypes/
csrf
====
@ -177,9 +181,13 @@ localflavor
===========
A collection of various Django snippets that are useful only for a particular
country or culture. For example, ``django.contrib.localflavor.usa.forms``
country or culture. For example, ``django.contrib.localflavor.us.forms``
contains a ``USZipCodeField`` that you can use to validate U.S. zip codes.
See the `localflavor documentation`_.
.. _localflavor documentation: ../localflavor/
markup
======

View File

@ -247,8 +247,8 @@ Anonymous users
the ``django.contrib.auth.models.User`` interface, with these differences:
* ``id`` is always ``None``.
* ``is_staff`` and ``is_superuser`` are always False.
* ``is_active`` is always True.
* ``is_staff`` and ``is_superuser`` are always ``False``.
* ``is_active`` is always ``False``.
* ``groups`` and ``user_permissions`` are always empty.
* ``is_anonymous()`` returns ``True`` instead of ``False``.
* ``is_authenticated()`` returns ``False`` instead of ``True``.

View File

@ -44,8 +44,8 @@ Our class looks something like this::
# ... (other possibly useful methods omitted) ...
This is just an ordinary Python class, with nothing Django-specific about it.
We'd like to be able to things like this in our models (we assume the ``hand``
attribute on the model is an instance of ``Hand``)::
We'd like to be able to do things like this in our models (we assume the
``hand`` attribute on the model is an instance of ``Hand``)::
example = MyModel.objects.get(pk=1)
print example.hand.north

View File

@ -132,6 +132,13 @@ If no application name is provided, all installed applications will be dumped.
The output of ``dumpdata`` can be used as input for ``loaddata``.
Note that ``dumpdata`` uses the default manager on the model for selecting the
records to dump. If you're using a `custom manager`_ as the default manager
and it filters some of the available records, not all of the objects will be
dumped.
.. _custom manager: ../model-api/#custom-managers
--format
~~~~~~~~
@ -709,8 +716,8 @@ in Python package syntax, e.g. ``mysite.settings``. If this isn't provided,
``django-admin.py`` will use the ``DJANGO_SETTINGS_MODULE`` environment
variable.
Note that this option is unnecessary in ``manage.py``, because it takes care of
setting ``DJANGO_SETTINGS_MODULE`` for you.
Note that this option is unnecessary in ``manage.py``, because it uses
``settings.py`` from the current project by default.
Extra niceties
==============

View File

@ -1,6 +1,13 @@
Generating forms for models
===========================
.. admonition:: Note
The APIs described in this document have been deprecated. If you're
developing new code, use `ModelForms`_ instead.
.. _ModelForms: ../modelforms/
If you're building a database-driven app, chances are you'll have forms that
map closely to Django models. For instance, you might have a ``BlogComment``
model, and you want to create a form that lets people submit comments. In this

View File

@ -2,16 +2,22 @@
The "local flavor" add-ons
==========================
Django comes with assorted pieces of code that are useful only for a particular
country or culture. These pieces of code are organized as a set of
Following its "batteries included" philosophy, Django comes with assorted
pieces of code that are useful for particular countries or cultures. These are
called the "local flavor" add-ons and live in the ``django.contrib.localflavor``
package.
Inside that package, country- or culture-specific code is organized into
subpackages, named using `ISO 3166 country codes`_.
.. _ISO 3166 country codes: http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
Most of the ``localflavor`` add-ons are localized form components deriving from
the newforms_ framework. To use one of these localized components, just import
the relevant subpackage. For example, a form with a field for French telephone
numbers is created like so::
the newforms_ framework -- for example, a ``USStateField`` that knows how to
validate U.S. state abbreviations, and a ``FISocialSecurityNumber`` that knows
how to validate Finnish social security numbers.
To use one of these localized components, just import the relevant subpackage.
For example, here's how you can create a form with a field representing a
French telephone number::
from django import newforms as forms
from django.contrib.localflavor import fr
@ -19,32 +25,48 @@ numbers is created like so::
class MyForm(forms.Form):
my_french_phone_no = fr.forms.FRPhoneNumberField()
Supported countries
===================
Countries currently supported by ``localflavor`` are:
* Argentina_
* Australia_
* Brazil_
* Canada_
* Chile_
* Finland_
* France_
* Germany_
* Holland_
* Iceland_
* India_
* Italy_
* Japan_
* Mexico_
* Norway_
* Peru_
* Poland_
* Slovakia_
* `South Africa`_
* Spain_
* Switzerland_
* `United Kingdom`_
* `United States of America`_
* Argentina_
* Australia_
* Brazil_
* Canada_
* Chile_
* Finland_
* France_
* Germany_
* Holland_
* Iceland_
* India_
* Italy_
* Japan_
* Mexico_
* Norway_
* Peru_
* Poland_
* Slovakia_
* `South Africa`_
* Spain_
* Switzerland_
* `United Kingdom`_
* `United States of America`_
The ``localflavor`` package also includes a ``generic`` subpackage, containing
useful code that is not specific to one particular country or culture.
Currently, it defines date and datetime input fields based on those from
newforms_, but with non-US default formats. Here's an example of how to use
them::
from django import newforms as forms
from django.contrib.localflavor import generic
class MyForm(forms.Form):
my_date_field = generic.forms.DateField()
.. _ISO 3166 country codes: http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
.. _Argentina: `Argentina (django.contrib.localflavor.ar)`_
.. _Australia: `Australia (django.contrib.localflavor.au)`_
.. _Brazil: `Brazil (django.contrib.localflavor.br)`_
@ -68,29 +90,15 @@ Countries currently supported by ``localflavor`` are:
.. _Switzerland: `Switzerland (django.contrib.localflavor.ch)`_
.. _United Kingdom: `United Kingdom (django.contrib.localflavor.uk)`_
.. _United States of America: `United States of America (django.contrib.localflavor.us)`_
The ``localflavor`` add-on also includes the ``generic`` subpackage, containing
useful code that is not specific to one particular country or culture.
Currently, it defines date and date & time input fields based on those from
newforms_, but with non-US default formats. Here's an example of how to use
them::
from django import newforms as forms
from django.contrib.localflavor import generic
class MyForm(forms.Form):
my_date_field = generic.forms.DateField()
.. _newforms: ../newforms/
Adding flavors
==============
.. admonition:: Adding a Flavor
We'd love to add more of these to Django, so please create a ticket for
anything that you've found useful. Please use unicode objects
(``u'mystring'``) for strings, rather than setting the encoding in the file
(see any of the existing flavors for examples).
We'd love to add more of these to Django, so please `create a ticket`_ with
any code you'd like to contribute. One thing we ask is that you please use
Unicode objects (``u'mystring'``) for strings, rather than setting the encoding
in the file. See any of the existing flavors for examples.
Argentina (``django.contrib.localflavor.ar``)
=============================================
@ -108,7 +116,6 @@ ARProvinceSelect
A ``Select`` widget that uses a list of Argentina's provinces as its choices.
Australia (``django.contrib.localflavor.au``)
=============================================
@ -129,7 +136,6 @@ AUStateSelect
A ``Select`` widget that uses a list of Australian states/territories as its
choices.
Brazil (``django.contrib.localflavor.br``)
==========================================
@ -151,7 +157,6 @@ BRStateSelect
A ``Select`` widget that uses a list of Brazilian states/territories as its
choices.
Canada (``django.contrib.localflavor.ca``)
==========================================
@ -176,7 +181,7 @@ CASocialInsuranceNumberField
----------------------------
A form field that validates input as a Canadian Social Insurance Number (SIN).
A valid number must have the format XXX-XXX-XXXX and pass a `Luhn mod-10
A valid number must have the format XXX-XXX-XXX and pass a `Luhn mod-10
checksum`_.
.. _Luhn mod-10 checksum: http://en.wikipedia.org/wiki/Luhn_algorithm
@ -187,7 +192,6 @@ CAProvinceSelect
A ``Select`` widget that uses a list of Canadian provinces and territories as
its choices.
Chile (``django.contrib.localflavor.cl``)
=========================================
@ -203,7 +207,6 @@ CLRegionSelect
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
choices.
Finland (``django.contrib.localflavor.fi``)
===========================================
@ -224,7 +227,6 @@ FIMunicipalitySelect
A ``Select`` widget that uses a list of Finnish municipalities as its
choices.
France (``django.contrib.localflavor.fr``)
==========================================
@ -246,7 +248,6 @@ FRDepartmentSelect
A ``Select`` widget that uses a list of French departments as its choices.
Germany (``django.contrib.localflavor.de``)
===========================================
@ -270,7 +271,6 @@ DEStateSelect
A ``Select`` widget that uses a list of German states as its choices.
Holland (``django.contrib.localflavor.nl``)
===========================================
@ -296,7 +296,6 @@ NLProvinceSelect
A ``Select`` widget that uses a list of Dutch provinces as its list of
choices.
Iceland (``django.contrib.localflavor.is_``)
============================================
@ -318,7 +317,6 @@ ISPostalCodeSelect
A ``Select`` widget that uses a list of Icelandic postal codes as its
choices.
India (``django.contrib.localflavor.in_``)
==========================================
@ -341,7 +339,6 @@ INStateSelect
A ``Select`` widget that uses a list of Indian states/territories as its
choices.
Italy (``django.contrib.localflavor.it``)
=========================================
@ -374,22 +371,20 @@ ITRegionSelect
A ``Select`` widget that uses a list of Italian regions as its choices.
Japan (``django.contrib.localflavor.jp``)
=========================================
JPPostalCodeField
-----------------
A form field that validates input as a Japanese postcode.
It accepts seven digits, with or without a hyphen.
A form field that validates input as a Japanese postcode. It accepts seven
digits, with or without a hyphen.
JPPrefectureSelect
------------------
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
Mexico (``django.contrib.localflavor.mx``)
==========================================
@ -398,7 +393,6 @@ MXStateSelect
A ``Select`` widget that uses a list of Mexican states as its choices.
Norway (``django.contrib.localflavor.no``)
==========================================
@ -422,7 +416,6 @@ NOMunicipalitySelect
A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as
its choices.
Peru (``django.contrib.localflavor.pe``)
========================================
@ -436,14 +429,13 @@ PERUCField
----------
A form field that validates input as an RUC (Registro Unico de
Contribuyentes) number. Valid RUC numbers have eleven digits.
Contribuyentes) number. Valid RUC numbers have 11 digits.
PEDepartmentSelect
------------------
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
Poland (``django.contrib.localflavor.pl``)
==========================================
@ -490,7 +482,6 @@ PLVoivodeshipSelect
A ``Select`` widget that uses a list of Polish voivodeships (administrative
provinces) as its choices.
Slovakia (``django.contrib.localflavor.sk``)
============================================
@ -510,7 +501,6 @@ SKRegionSelect
A ``Select`` widget that uses a list of Slovak regions as its choices.
South Africa (``django.contrib.localflavor.za``)
================================================
@ -527,7 +517,6 @@ ZAPostCodeField
A form field that validates input as a South African postcode. Valid
postcodes must have four digits.
Spain (``django.contrib.localflavor.es``)
=========================================
@ -571,7 +560,6 @@ ESRegionSelect
A ``Select`` widget that uses a list of Spanish regions as its choices.
Switzerland (``django.contrib.localflavor.ch``)
===============================================
@ -600,7 +588,6 @@ CHStateSelect
A ``Select`` widget that uses a list of Swiss states as its choices.
United Kingdom (``django.contrib.localflavor.uk``)
==================================================
@ -611,6 +598,15 @@ A form field that validates input as a UK postcode. The regular
expression used is sourced from the schema for British Standard BS7666
address types at http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd.
UKCountySelect
--------------
A ``Select`` widget that uses a list of UK counties/regions as its choices.
UKNationSelect
--------------
A ``Select`` widget that uses a list of UK nations as its choices.
United States of America (``django.contrib.localflavor.us``)
============================================================
@ -626,11 +622,11 @@ USSocialSecurityNumberField
A form field that validates input as a U.S. Social Security Number (SSN).
A valid SSN must obey the following rules:
* Format of XXX-XX-XXXX
* No group of digits consisting entirely of zeroes
* Leading group of digits cannot be 666
* Number not in promotional block 987-65-4320 through 987-65-4329
* Number not one known to be invalid due to widespread promotional
* Format of XXX-XX-XXXX
* No group of digits consisting entirely of zeroes
* Leading group of digits cannot be 666
* Number not in promotional block 987-65-4320 through 987-65-4329
* Number not one known to be invalid due to widespread promotional
use or distribution (e.g., the Woolworth's number or the 1962
promotional number)
@ -644,11 +640,11 @@ for the given state.
USZipCodeField
--------------
A form field that validates input as a U.S. zip code. Valid formats are
A form field that validates input as a U.S. ZIP code. Valid formats are
XXXXX or XXXXX-XXXX.
USStateSelect
-------------
A form Select widget that uses a list of U.S. states/territories as its
A form ``Select`` widget that uses a list of U.S. states/territories as its
choices.

View File

@ -61,17 +61,18 @@ Adds a few conveniences for perfectionists:
settings.
If ``APPEND_SLASH`` is ``True`` and the initial URL doesn't end with a slash,
and it is not found in urlpatterns, a new URL is formed by appending a slash
at the end. If this new URL is found in urlpatterns, then an HTTP-redirect is
returned to this new URL; otherwise the initial URL is processed as usual.
and it is not found in the URLconf, then a new URL is formed by appending a
slash at the end. If this new URL is found in the URLconf, then Django
redirects the request to this new URL. Otherwise, the initial URL is
processed as usual.
So ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if you do not
have a valid urlpattern for ``foo.com/bar``, and do have a valid urlpattern
for ``foo.com/bar/``.
For example, ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if you
don't have a valid URL pattern for ``foo.com/bar`` but *do* have a valid
pattern for ``foo.com/bar/``.
**New in Django development version:** The behavior of ``APPEND_SLASH`` has
changed slightly in the development version. It didn't used to check to see
whether the pattern was matched in the URLconf.
changed slightly in the development version. It didn't used to check whether
the pattern was matched in the URLconf.
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
redirected to the same URL with a leading "www."
@ -153,6 +154,17 @@ every incoming ``HttpRequest`` object. See `Authentication in Web requests`_.
.. _Authentication in Web requests: ../authentication/#authentication-in-web-requests
django.contrib.csrf.middleware.CsrfMiddleware
---------------------------------------------
**New in Django development version**
Adds protection against Cross Site Request Forgeries by adding hidden form
fields to POST forms and checking requests for the correct value. See the
`Cross Site Request Forgery protection documentation`_.
.. _`Cross Site Request Forgery protection documentation`: ../csrf/
django.middleware.transaction.TransactionMiddleware
---------------------------------------------------

View File

@ -277,7 +277,7 @@ model fields:
any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
To avoid this failure, you must instantiate your model with initial values
for the missing, but required fields, or use ``save(commit=False)`` and
manually set anyextra required fields::
manually set any extra required fields::
instance = Instance(required_field='value')
form = InstanceForm(request.POST, instance=instance)
@ -296,7 +296,7 @@ Overriding the default field types
----------------------------------
The default field types, as described in the "Field types" table above, are
sensible defaults; if you have a ``DateField`` in your model, chances are you'd
sensible defaults. If you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
``ModelForm`` gives you the flexibility of changing the form field type
for a given model field. You do this by declaratively specifying fields like

View File

@ -156,6 +156,18 @@ Methods
Returns ``True`` or ``False``, designating whether ``request.GET`` or
``request.POST`` has the given key.
``get_host()``
**New in Django development version**
Returns the originating host of the request using information from the
``HTTP_X_FORWARDED_HOST`` and ``HTTP_HOST`` headers (in that order). If
they don't provide a value, the method uses a combination of
``SERVER_NAME`` and ``SERVER_PORT`` as detailed in `PEP 333`_.
.. _PEP 333: http://www.python.org/dev/peps/pep-0333/
Example: ``"127.0.0.1:8000"``
``get_full_path()``
Returns the ``path``, plus an appended query string, if applicable.
@ -452,7 +464,7 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
``HttpResponseNotModified``
The constructor doesn't take any arguments. Use this to designate that a
page hasn't been modified since the user's last request.
page hasn't been modified since the user's last request (status code 304).
``HttpResponseBadRequest``
**New in Django development version.**

View File

@ -99,7 +99,7 @@ It implements the following standard dictionary methods:
* ``items()``
* ``setdefault()``
* ``setdefault()`` (**New in Django development version**)
It also has these three methods:

View File

@ -981,8 +981,13 @@ TEST_DATABASE_NAME
Default: ``None``
The name of database to use when running the test suite. If a value of
``None`` is specified, the test database will use the name ``'test_' + settings.DATABASE_NAME``. See `Testing Django Applications`_.
The name of database to use when running the test suite.
If the default value (``None``) is used with the SQLite database engine, the
tests will use a memory resident database. For all other database engines the
test database will use the name ``'test_' + settings.DATABASE_NAME``.
See `Testing Django Applications`_.
.. _Testing Django Applications: ../testing/

View File

@ -97,7 +97,7 @@ Hooking into the current site from views
----------------------------------------
On a lower level, you can use the sites framework in your Django views to do
particular things based on what site in which the view is being called.
particular things based on the site in which the view is being called.
For example::
from django.conf import settings
@ -330,13 +330,13 @@ Here's how Django uses the sites framework:
retrieving flatpages to display.
* In the `syndication framework`_, the templates for ``title`` and
``description`` automatically have access to a variable ``{{{ site }}}``,
``description`` automatically have access to a variable ``{{ site }}``,
which is the ``Site`` object representing the current site. Also, the
hook for providing item URLs will use the ``domain`` from the current
``Site`` object if you don't specify a fully-qualified domain.
* In the `authentication framework`_, the ``django.contrib.auth.views.login``
view passes the current ``Site`` name to the template as ``{{{ site_name }}}``.
view passes the current ``Site`` name to the template as ``{{ site_name }}``.
* The shortcut view (``django.views.defaults.shortcut``) uses the domain of
the current ``Site`` object when calculating an object's URL.

View File

@ -201,7 +201,7 @@ the feed.
An example makes this clear. Here's the code for these beat-specific feeds::
from django.contrib.syndication import FeedDoesNotExist
from django.contrib.syndication.feeds import FeedDoesNotExist
class BeatFeed(Feed):
def get_object(self, bits):

View File

@ -691,8 +691,8 @@ This way, you'll be able to pass, say, an integer to this filter, and it
won't cause an ``AttributeError`` (because integers don't have ``lower()``
methods).
Registering a custom filters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Registering custom filters
~~~~~~~~~~~~~~~~~~~~~~~~~~
Once you've written your filter definition, you need to register it with
your ``Library`` instance, to make it available to Django's template language::

View File

@ -270,27 +270,21 @@ a test case, add the name of the test method to the label::
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
Understanding the test output
-----------------------------
The test database
-----------------
When you run your tests, you'll see a number of messages as the test runner
prepares itself::
Tests that require a database (namely, model tests) will not use
your "real" (production) database. A separate, blank database is created
for the tests.
Creating test database...
Creating table myapp_animal
Creating table myapp_mineral
Loading 'initial_data' fixtures...
No fixtures found.
Regardless of whether the tests pass or fail, the test database is destroyed
when all the tests have been executed.
This tells you that the test runner is creating a test database -- a blank,
from-scratch database that it will use for any tests that happen to require a
database (namely, model tests).
Don't worry -- the test runner will not touch your "real" (production)
database. It creates a separate database purely for the tests. This test
database gets its name by prepending ``test_`` to the value of the
``DATABASE_NAME`` setting. If you want to use a different name, specify the
``TEST_DATABASE_NAME`` setting.
By default this test database gets its name by prepending ``test_`` to the
value of the ``DATABASE_NAME`` setting. When using the SQLite database engine
the tests will by default use an in-memory database (i.e., the database will be
created in memory, bypassing the filesystem entirely!). If you want to use a
different database name, specify the ``TEST_DATABASE_NAME`` setting.
Aside from using a separate database, the test runner will otherwise use all of
the same database settings you have in your settings file: ``DATABASE_ENGINE``,
@ -306,6 +300,22 @@ settings_ documentation for details of these advanced settings.
.. _settings: ../settings/
Understanding the test output
-----------------------------
When you run your tests, you'll see a number of messages as the test runner
prepares itself. You can control the level of detail of these messages with the
``verbosity`` option on the command line::
Creating test database...
Creating table myapp_animal
Creating table myapp_mineral
Loading 'initial_data' fixtures...
No fixtures found.
This tells you that the test runner is creating a test database, as described
in the previous section.
Once the test database has been created, Django will run your tests.
If everything goes well, you'll see something like this::
@ -349,9 +359,6 @@ failed and erroneous tests. If all the tests pass, the return code is 0. This
feature is useful if you're using the test-runner script in a shell script and
need to test for success or failure at that level.
Regardless of whether the tests pass or fail, the test database is destroyed when
all the tests have been executed.
Testing tools
=============

View File

@ -213,13 +213,13 @@ u'046-454-286'
>>> f.clean('046-454-287')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXX format.']
>>> f.clean('046 454 286')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXX format.']
>>> f.clean('046-44-286')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXX format.']
"""

View File

@ -41,7 +41,7 @@ Strict RUT usage (does not allow imposible values)
>>> rut.clean('11-6')
Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
# valid format, bad verifier.
>>> rut.clean('11.111.111-0')
@ -53,17 +53,17 @@ ValidationError: [u'The Chilean RUT is not valid.']
>>> rut.clean('767484100')
Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
>>> rut.clean('78.412.790-7')
u'78.412.790-7'
>>> rut.clean('8.334.6043')
Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
>>> rut.clean('76793310-K')
Traceback (most recent call last):
...
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
ValidationError: [u'Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.']
## CLRegionSelect #########################################################
>>> from django.contrib.localflavor.cl.forms import CLRegionSelect

View File

@ -12,13 +12,15 @@ u'BT32 4PX'
>>> f.clean('GIR 0AA')
u'GIR 0AA'
>>> f.clean('BT324PX')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
u'BT32 4PX'
>>> f.clean('1NV 4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
ValidationError: [u'Enter a valid postcode.']
>>> f.clean('1NV4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid postcode.']
>>> f.clean(None)
Traceback (most recent call last):
...
@ -27,7 +29,20 @@ ValidationError: [u'This field is required.']
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(' so11aa ')
u'SO1 1AA'
>>> f.clean(' so1 1aa ')
u'SO1 1AA'
>>> f.clean('G2 3wt')
u'G2 3WT'
>>> f.clean('EC1A 1BB')
u'EC1A 1BB'
>>> f.clean('Ec1a1BB')
u'EC1A 1BB'
>>> f.clean(' b0gUS')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid postcode.']
>>> f = UKPostcodeField(required=False)
>>> f.clean('BT32 4PX')
u'BT32 4PX'
@ -36,11 +51,9 @@ u'GIR 0AA'
>>> f.clean('1NV 4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
ValidationError: [u'Enter a valid postcode.']
>>> f.clean('BT324PX')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
u'BT32 4PX'
>>> f.clean(None)
u''
>>> f.clean('')

View File

@ -391,9 +391,45 @@ u'\ufffd'
>>> q.getlist('foo')
[u'bar', u'\ufffd']
######################################
# HttpResponse with Unicode headers #
######################################
>>> r = HttpResponse()
If we insert a unicode value it will be converted to an ascii
string. This makes sure we comply with the HTTP specifications.
>>> r['value'] = u'test value'
>>> isinstance(r['value'], str)
True
An error is raised When a unicode object with non-ascii is assigned.
>>> r['value'] = u't\xebst value' # doctest:+ELLIPSIS
Traceback (most recent call last):
...
UnicodeEncodeError: ..., HTTP response headers must be in US-ASCII format
The response also converts unicode keys to strings.
>>> r[u'test'] = 'testing key'
>>> l = list(r.items())
>>> l.sort()
>>> l[1]
('test', 'testing key')
It will also raise errors for keys with non-ascii data.
>>> r[u't\xebst'] = 'testing key' # doctest:+ELLIPSIS
Traceback (most recent call last):
...
UnicodeEncodeError: ..., HTTP response headers must be in US-ASCII format
"""
from django.http import QueryDict
from django.http import QueryDict, HttpResponse
if __name__ == "__main__":
import doctest

View File

@ -108,8 +108,8 @@ 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": "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>'),
'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>'),
'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"),

View File

@ -441,6 +441,8 @@ class Templates(unittest.TestCase):
'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
'for-tag-vars05': ("{% for val in values %}{% if forloop.first %}f{% else %}x{% endif %}{% endfor %}", {"values": [6, 6, 6]}, "fxx"),
'for-tag-vars06': ("{% for val in values %}{% if forloop.last %}l{% else %}x{% endif %}{% endfor %}", {"values": [6, 6, 6]}, "xxl"),
'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
@ -808,6 +810,16 @@ class Templates(unittest.TestCase):
'{% endfor %}',
{}, ''),
# Test syntax.
'regroup03': ('{% regroup data by bar as %}', {},
template.TemplateSyntaxError),
'regroup04': ('{% regroup data by bar thisaintright grouped %}', {},
template.TemplateSyntaxError),
'regroup05': ('{% regroup data thisaintright bar as grouped %}', {},
template.TemplateSyntaxError),
'regroup06': ('{% regroup data by bar as grouped toomanyargs %}', {},
template.TemplateSyntaxError),
### TEMPLATETAG TAG #######################################################
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),

View File

@ -0,0 +1 @@
An unknown file extension.

View File

@ -13,6 +13,11 @@ class StaticTests(TestCase):
response = self.client.get('/views/site_media/%s' % filename)
file = open(path.join(media_dir, filename))
self.assertEquals(file.read(), response.content)
self.assertEquals(len(response.content), int(response['Content-Length']))
def test_unknown_mime_type(self):
response = self.client.get('/views/site_media/file.unknown')
self.assertEquals('application/octet-stream', response['Content-Type'])
def test_copes_with_empty_path_component(self):
file_name = 'file.txt'
@ -20,4 +25,3 @@ class StaticTests(TestCase):
file = open(path.join(media_dir, file_name))
self.assertEquals(file.read(), response.content)

View File

@ -93,6 +93,7 @@ def django_tests(verbosity, interactive, test_labels):
old_root_urlconf = settings.ROOT_URLCONF
old_template_dirs = settings.TEMPLATE_DIRS
old_use_i18n = settings.USE_I18N
old_login_url = settings.LOGIN_URL
old_language_code = settings.LANGUAGE_CODE
old_middleware_classes = settings.MIDDLEWARE_CLASSES
@ -102,6 +103,7 @@ def django_tests(verbosity, interactive, test_labels):
settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
settings.USE_I18N = True
settings.LANGUAGE_CODE = 'en'
settings.LOGIN_URL = '/accounts/login/'
settings.MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -153,6 +155,7 @@ def django_tests(verbosity, interactive, test_labels):
settings.TEMPLATE_DIRS = old_template_dirs
settings.USE_I18N = old_use_i18n
settings.LANGUAGE_CODE = old_language_code
settings.LOGIN_URL = old_login_url
settings.MIDDLEWARE_CLASSES = old_middleware_classes
if __name__ == "__main__":