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:
parent
ef0f46f1d0
commit
7e322b5908
3
AUTHORS
3
AUTHORS
@ -130,6 +130,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Matthew Flanagan <http://wadofstuff.blogspot.com>
|
Matthew Flanagan <http://wadofstuff.blogspot.com>
|
||||||
Eric Floehr <eric@intellovations.com>
|
Eric Floehr <eric@intellovations.com>
|
||||||
Vincent Foley <vfoleybourgon@yahoo.ca>
|
Vincent Foley <vfoleybourgon@yahoo.ca>
|
||||||
|
Rudolph Froger <rfroger@estrate.nl>
|
||||||
Jorge Gajon <gajon@gajon.org>
|
Jorge Gajon <gajon@gajon.org>
|
||||||
gandalf@owca.info
|
gandalf@owca.info
|
||||||
Marc Garcia <marc.garcia@accopensys.com>
|
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>
|
Georgi Stanojevski <glisha@gmail.com>
|
||||||
Vasiliy Stavenko <stavenko@gmail.com>
|
Vasiliy Stavenko <stavenko@gmail.com>
|
||||||
Thomas Steinacher <http://www.eggdrop.ch/>
|
Thomas Steinacher <http://www.eggdrop.ch/>
|
||||||
|
Johan C. Stöver <johan@nilling.nl>
|
||||||
nowell strite
|
nowell strite
|
||||||
Thomas Stromberg <tstromberg@google.com>
|
Thomas Stromberg <tstromberg@google.com>
|
||||||
Sundance
|
Sundance
|
||||||
@ -327,6 +329,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
tt@gurgle.no
|
tt@gurgle.no
|
||||||
Amit Upadhyay
|
Amit Upadhyay
|
||||||
Geert Vanderkelen
|
Geert Vanderkelen
|
||||||
|
I.S. van Oostveen <v.oostveen@idca.nl>
|
||||||
viestards.lists@gmail.com
|
viestards.lists@gmail.com
|
||||||
George Vilches <gav@thataddress.com>
|
George Vilches <gav@thataddress.com>
|
||||||
Vlado <vlado@labath.org>
|
Vlado <vlado@labath.org>
|
||||||
|
@ -52,7 +52,9 @@ class LazySettings(object):
|
|||||||
if not settings_module: # If it's set but is an empty string.
|
if not settings_module: # If it's set but is an empty string.
|
||||||
raise KeyError
|
raise KeyError
|
||||||
except 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)
|
self._target = Settings(settings_module)
|
||||||
|
|
||||||
|
Binary file not shown.
@ -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
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django 1.0\n"
|
"Project-Id-Version: Django 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2006-12-09 15:51+0100\n"
|
"POT-Creation-Date: 2006-12-09 15:51+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2007-12-17 21:14+0100\n"
|
||||||
"Last-Translator: Johan C. Stöver <johan@nilling.nl>\n"
|
"Last-Translator: I.S. van Oostveen\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\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
|
#: db/models/fields/__init__.py:381
|
||||||
msgid "This value must be either True or False."
|
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
|
#: db/models/fields/__init__.py:397
|
||||||
msgid "This field cannot be null."
|
msgid "This field cannot be null."
|
||||||
@ -279,7 +274,7 @@ msgstr "Alleen alfabetische karakters zijn toegestaan"
|
|||||||
|
|
||||||
#: core/validators.py:139
|
#: core/validators.py:139
|
||||||
msgid "Year must be 1900 or later."
|
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
|
#: core/validators.py:143
|
||||||
#, python-format
|
#, 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
|
#: core/validators.py:173 core/validators.py:442 forms/__init__.py:667
|
||||||
msgid "No file was submitted. Check the encoding type on the form."
|
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
|
#: core/validators.py:177
|
||||||
msgid ""
|
msgid ""
|
||||||
"Upload a valid image. The file you uploaded was either not an image or a "
|
"Upload a valid image. The file you uploaded was either not an image or a "
|
||||||
"corrupted image."
|
"corrupted image."
|
||||||
msgstr ""
|
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."
|
"beschadigd."
|
||||||
|
|
||||||
#: core/validators.py:184
|
#: core/validators.py:184
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The URL %s does not point to a valid image."
|
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
|
#: core/validators.py:188
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -321,7 +316,7 @@ msgstr ""
|
|||||||
#: core/validators.py:196
|
#: core/validators.py:196
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The URL %s does not point to a valid QuickTime video."
|
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
|
#: core/validators.py:200
|
||||||
msgid "A valid URL is required."
|
msgid "A valid URL is required."
|
||||||
@ -349,18 +344,18 @@ msgstr "Ongeldige URL: %s"
|
|||||||
#: core/validators.py:243 core/validators.py:245
|
#: core/validators.py:243 core/validators.py:245
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The URL %s is a broken link."
|
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
|
#: core/validators.py:251
|
||||||
msgid "Enter a valid U.S. state abbreviation."
|
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
|
#: core/validators.py:265
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Watch your mouth! The word %s is not allowed here."
|
msgid "Watch your mouth! The word %s is not allowed here."
|
||||||
msgid_plural "Watch your mouth! The words %s are 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[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
|
#: core/validators.py:272
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -373,7 +368,7 @@ msgstr "Voer tenminste één veld in."
|
|||||||
|
|
||||||
#: core/validators.py:300 core/validators.py:311
|
#: core/validators.py:300 core/validators.py:311
|
||||||
msgid "Please enter both fields or leave them both empty."
|
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
|
#: core/validators.py:318
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -450,7 +445,7 @@ msgstr "Zorg ervoor dat het bestand hoogstens %s bytes groot is."
|
|||||||
|
|
||||||
#: core/validators.py:453
|
#: core/validators.py:453
|
||||||
msgid "The format for this field is wrong."
|
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
|
#: core/validators.py:468
|
||||||
msgid "This field is invalid."
|
msgid "This field is invalid."
|
||||||
@ -536,7 +531,7 @@ msgid ""
|
|||||||
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
|
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
|
||||||
"required for logging in."
|
"required for logging in."
|
||||||
msgstr ""
|
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."
|
"moeten cookies worden geaccepteerd."
|
||||||
|
|
||||||
#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10
|
#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10
|
||||||
@ -645,7 +640,7 @@ msgstr "supergebruiker status"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Designates that this user has all permissions without explicitly assigning "
|
"Designates that this user has all permissions without explicitly assigning "
|
||||||
"them."
|
"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
|
#: contrib/auth/models.py:98
|
||||||
msgid "last login"
|
msgid "last login"
|
||||||
@ -685,7 +680,7 @@ msgstr "Rechten"
|
|||||||
|
|
||||||
#: contrib/auth/models.py:113
|
#: contrib/auth/models.py:113
|
||||||
msgid "Important dates"
|
msgid "Important dates"
|
||||||
msgstr "Belangrijke data"
|
msgstr "Belangrijke datums"
|
||||||
|
|
||||||
#: contrib/auth/models.py:114
|
#: contrib/auth/models.py:114
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
@ -783,7 +778,7 @@ msgid ""
|
|||||||
"Please log in again, because your session has expired. Don't worry: Your "
|
"Please log in again, because your session has expired. Don't worry: Your "
|
||||||
"submission has been saved."
|
"submission has been saved."
|
||||||
msgstr ""
|
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."
|
"is opgeslagen."
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:69
|
#: contrib/admin/views/decorators.py:69
|
||||||
@ -791,7 +786,7 @@ msgid ""
|
|||||||
"Looks like your browser isn't configured to accept cookies. Please enable "
|
"Looks like your browser isn't configured to accept cookies. Please enable "
|
||||||
"cookies, reload this page, and try again."
|
"cookies, reload this page, and try again."
|
||||||
msgstr ""
|
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."
|
"cookies aan in uw browser, laad deze pagina nogmaals en probeer het opnieuw."
|
||||||
|
|
||||||
#: contrib/admin/views/decorators.py:83
|
#: contrib/admin/views/decorators.py:83
|
||||||
@ -928,7 +923,7 @@ msgstr "Model %r niet gevonden in app %r"
|
|||||||
#: contrib/admin/views/doc.py:183
|
#: contrib/admin/views/doc.py:183
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "the related `%s.%s` object"
|
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:183 contrib/admin/views/doc.py:205
|
||||||
#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
|
#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
|
||||||
@ -938,7 +933,7 @@ msgstr "model:"
|
|||||||
#: contrib/admin/views/doc.py:214
|
#: contrib/admin/views/doc.py:214
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "related `%s.%s` objects"
|
msgid "related `%s.%s` objects"
|
||||||
msgstr "related `%s.%s` objects"
|
msgstr "de gerelateerde `%s.%s` objecten"
|
||||||
|
|
||||||
#: contrib/admin/views/doc.py:219
|
#: contrib/admin/views/doc.py:219
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -948,12 +943,12 @@ msgstr "alle %s"
|
|||||||
#: contrib/admin/views/doc.py:224
|
#: contrib/admin/views/doc.py:224
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "number of %s"
|
msgid "number of %s"
|
||||||
msgstr "nummer van %s"
|
msgstr "aantal %s"
|
||||||
|
|
||||||
#: contrib/admin/views/doc.py:229
|
#: contrib/admin/views/doc.py:229
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Fields on %s objects"
|
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:291 contrib/admin/views/doc.py:301
|
||||||
#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309
|
#: 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:"
|
"All of the following related items will be deleted:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Weet u zeker dat u %(object_name)s \"%(escaped_object)s\" wilt verwijderen? Alle "
|
"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
|
#: contrib/admin/templates/admin/delete_confirmation.html:26
|
||||||
msgid "Yes, I'm sure"
|
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:4
|
||||||
#: contrib/admin/templates/admin/404.html:8
|
#: contrib/admin/templates/admin/404.html:8
|
||||||
@ -1197,7 +1192,7 @@ msgstr "Opslaan en nieuw item"
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin/submit_line.html:6
|
#: contrib/admin/templates/admin/submit_line.html:6
|
||||||
msgid "Save and continue editing"
|
msgid "Save and continue editing"
|
||||||
msgstr "Opslaan en bewerk opnieuw"
|
msgstr "Opslaan en opnieuw bewerken"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/submit_line.html:7
|
#: contrib/admin/templates/admin/submit_line.html:7
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
@ -1224,7 +1219,7 @@ msgstr "Wijzigen"
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin/index.html:44
|
#: contrib/admin/templates/admin/index.html:44
|
||||||
msgid "You don't have permission to edit anything."
|
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
|
#: contrib/admin/templates/admin/index.html:52
|
||||||
msgid "Recent Actions"
|
msgid "Recent Actions"
|
||||||
@ -1380,7 +1375,7 @@ msgstr ""
|
|||||||
"de bookmarklet vanuit elke pagina op de site worden gekozen. Let erop dat "
|
"de bookmarklet vanuit elke pagina op de site worden gekozen. Let erop dat "
|
||||||
"het soms\n"
|
"het soms\n"
|
||||||
"noodzakelijk is dat de computer van waaruit de pagina wordt bekeken intern "
|
"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 "
|
"(Raadpleeg uw systeembeheerder of uw computer zich op het interne netwerk "
|
||||||
"bevind).<p>\n"
|
"bevind).<p>\n"
|
||||||
|
|
||||||
@ -1393,7 +1388,7 @@ msgid ""
|
|||||||
"Jumps you from any page to the documentation for the view that generates "
|
"Jumps you from any page to the documentation for the view that generates "
|
||||||
"that page."
|
"that page."
|
||||||
msgstr ""
|
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"
|
"wordt door die pagina"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
||||||
@ -1406,7 +1401,7 @@ msgid ""
|
|||||||
"object."
|
"object."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Toont de content-type en unieke ID voor pagina's die een enkel object "
|
"Toont de content-type en unieke ID voor pagina's die een enkel object "
|
||||||
"voorsteld."
|
"voorstellen."
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
|
||||||
msgid "Edit this object (current window)"
|
msgid "Edit this object (current window)"
|
||||||
@ -1414,7 +1409,7 @@ msgstr "Bewerk dit object (huidig venster)"
|
|||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
||||||
msgid "Jumps to the admin page for pages that represent a single object."
|
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
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
|
||||||
msgid "Edit this object (new window)"
|
msgid "Edit this object (new window)"
|
||||||
@ -1527,7 +1522,7 @@ msgid ""
|
|||||||
"password twice so we can verify you typed it in correctly."
|
"password twice so we can verify you typed it in correctly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vanwege de beveiliging moet u uw oude en twee keer een nieuw "
|
"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."
|
"gemaakt."
|
||||||
|
|
||||||
#: contrib/admin/templates/registration/password_change_form.html:17
|
#: 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 "
|
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
||||||
"will use 'flatpages/default.html'."
|
"will use 'flatpages/default.html'."
|
||||||
msgstr ""
|
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."
|
"'flatpages/default.html' gebruikt."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:14
|
#: 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:196
|
||||||
#: contrib/comments/views/comments.py:286
|
#: contrib/comments/views/comments.py:286
|
||||||
msgid "Somebody tampered with the comment form (security violation)"
|
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:206
|
||||||
#: contrib/comments/views/comments.py:292
|
#: contrib/comments/views/comments.py:292
|
||||||
|
@ -55,6 +55,12 @@ var POLISH_MAP = {
|
|||||||
'Ź':'Z', 'Ż':'Z'
|
'Ź':'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()
|
var ALL_DOWNCODE_MAPS=new Array()
|
||||||
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
|
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
|
||||||
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_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[5]=UKRAINIAN_MAP
|
||||||
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
||||||
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
|
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
|
||||||
|
ALL_DOWNCODE_MAPS[8]=LATVIAN_MAP
|
||||||
|
|
||||||
var Downcoder = new Object();
|
var Downcoder = new Object();
|
||||||
Downcoder.Initialize = function()
|
Downcoder.Initialize = function()
|
||||||
|
@ -12,6 +12,7 @@ from django.utils.safestring import mark_safe
|
|||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
EMPTY_VALUE = '(None)'
|
EMPTY_VALUE = '(None)'
|
||||||
|
DISPLAY_SIZE = 100
|
||||||
|
|
||||||
class EasyModel(object):
|
class EasyModel(object):
|
||||||
def __init__(self, site, model):
|
def __init__(self, site, model):
|
||||||
@ -93,8 +94,8 @@ class EasyInstance(object):
|
|||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
val = smart_unicode(self.instance)
|
val = smart_unicode(self.instance)
|
||||||
if len(val) > 30:
|
if len(val) > DISPLAY_SIZE:
|
||||||
return val[:30] + u'...'
|
return val[:DISPLAY_SIZE] + u'...'
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -24,18 +24,20 @@ class ARPostalCodeField(RegexField):
|
|||||||
|
|
||||||
See http://www.correoargentino.com.ar/consulta_cpa/home.php
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
|
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
|
||||||
min_length=4, max_length=8,
|
min_length=4, max_length=8, *args, **kwargs)
|
||||||
error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
value = super(ARPostalCodeField, self).clean(value)
|
value = super(ARPostalCodeField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
if len(value) not in (4, 8):
|
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:
|
if len(value) == 8:
|
||||||
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
|
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
|
||||||
return value
|
return value
|
||||||
@ -44,6 +46,11 @@ class ARDNIField(CharField):
|
|||||||
"""
|
"""
|
||||||
A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
|
A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext("This field requires only numbers."),
|
||||||
|
'max_digits': ugettext("This field requires 7 or 8 digits."),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
|
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
@ -58,10 +65,9 @@ class ARDNIField(CharField):
|
|||||||
if not value.isdigit():
|
if not value.isdigit():
|
||||||
value = value.replace('.', '')
|
value = value.replace('.', '')
|
||||||
if not value.isdigit():
|
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):
|
if len(value) not in (7, 8):
|
||||||
raise ValidationError(
|
raise ValidationError(self.error_messages['max_digits'])
|
||||||
ugettext("This field requires 7 or 8 digits."))
|
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -70,9 +76,13 @@ class ARCUITField(RegexField):
|
|||||||
This field validates a CUIT (Código Único de Identificación Tributaria). A
|
This field validates a CUIT (Código Único de Identificación Tributaria). A
|
||||||
CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
|
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)
|
*args, **kwargs)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
@ -85,7 +95,7 @@ class ARCUITField(RegexField):
|
|||||||
return u''
|
return u''
|
||||||
value, cd = self._canon(value)
|
value, cd = self._canon(value)
|
||||||
if self._calc_cd(value) != cd:
|
if self._calc_cd(value) != cd:
|
||||||
raise ValidationError(ugettext("Invalid CUIT."))
|
raise ValidationError(self.error_messages['checksum'])
|
||||||
return self._format(value, cd)
|
return self._format(value, cd)
|
||||||
|
|
||||||
def _canon(self, cuit):
|
def _canon(self, cuit):
|
||||||
|
@ -12,14 +12,20 @@ PHONE_DIGITS_RE = re.compile(r'^(\d{10})$')
|
|||||||
|
|
||||||
class AUPostCodeField(RegexField):
|
class AUPostCodeField(RegexField):
|
||||||
"""Australian post code field."""
|
"""Australian post code field."""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a 4 digit post code.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AUPostCodeField, self).__init__(r'^\d{4}$',
|
super(AUPostCodeField, self).__init__(r'^\d{4}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a 4 digit post code.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class AUPhoneNumberField(Field):
|
class AUPhoneNumberField(Field):
|
||||||
"""Australian phone number field."""
|
"""Australian phone number field."""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Phone numbers must contain 10 digits.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
Validate a phone number. Strips parentheses, whitespace and hyphens.
|
Validate a phone number. Strips parentheses, whitespace and hyphens.
|
||||||
@ -31,7 +37,7 @@ class AUPhoneNumberField(Field):
|
|||||||
phone_match = PHONE_DIGITS_RE.search(value)
|
phone_match = PHONE_DIGITS_RE.search(value)
|
||||||
if phone_match:
|
if phone_match:
|
||||||
return u'%s' % phone_match.group(1)
|
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):
|
class AUStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -17,13 +17,19 @@ except NameError:
|
|||||||
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
|
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
|
||||||
|
|
||||||
class BRZipCodeField(RegexField):
|
class BRZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a zip code in the format XXXXX-XXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
|
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_('Enter a zip code in the format XXXXX-XXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class BRPhoneNumberField(Field):
|
class BRPhoneNumberField(Field):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Phone numbers must be in XX-XXXX-XXXX format.'),
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(BRPhoneNumberField, self).clean(value)
|
super(BRPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
@ -32,7 +38,7 @@ class BRPhoneNumberField(Field):
|
|||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
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):
|
class BRStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -48,6 +54,9 @@ class BRStateChoiceField(Field):
|
|||||||
A choice field that uses a list of Brazilian states as its choices.
|
A choice field that uses a list of Brazilian states as its choices.
|
||||||
"""
|
"""
|
||||||
widget = Select
|
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,
|
def __init__(self, required=True, widget=None, label=None,
|
||||||
initial=None, help_text=None):
|
initial=None, help_text=None):
|
||||||
@ -65,9 +74,7 @@ class BRStateChoiceField(Field):
|
|||||||
return value
|
return value
|
||||||
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
|
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
|
||||||
if value not in valid_values:
|
if value not in valid_values:
|
||||||
raise ValidationError(_(u'Select a valid brazilian state.'
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
u' That state is not one'
|
|
||||||
u' of the available states.'))
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def DV_maker(v):
|
def DV_maker(v):
|
||||||
@ -83,6 +90,12 @@ class BRCPFField(CharField):
|
|||||||
More information:
|
More information:
|
||||||
http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
|
super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
|
||||||
|
|
||||||
@ -100,9 +113,9 @@ class BRCPFField(CharField):
|
|||||||
try:
|
try:
|
||||||
int(value)
|
int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(_("This field requires only numbers."))
|
raise ValidationError(self.error_messages['digits_only'])
|
||||||
if len(value) != 11:
|
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:]
|
orig_dv = value[-2:]
|
||||||
|
|
||||||
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
|
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)
|
new_2dv = DV_maker(new_2dv % 11)
|
||||||
value = value[:-1] + str(new_2dv)
|
value = value[:-1] + str(new_2dv)
|
||||||
if value[-2:] != orig_dv:
|
if value[-2:] != orig_dv:
|
||||||
raise ValidationError(_("Invalid CPF number."))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return orig_value
|
return orig_value
|
||||||
|
|
||||||
class BRCNPJField(Field):
|
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):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
|
Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
|
||||||
@ -131,10 +150,9 @@ class BRCNPJField(Field):
|
|||||||
try:
|
try:
|
||||||
int(value)
|
int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError("This field requires only numbers.")
|
raise ValidationError(self.error_messages['digits_only'])
|
||||||
if len(value) != 14:
|
if len(value) != 14:
|
||||||
raise ValidationError(
|
raise ValidationError(self.error_messages['max_digits'])
|
||||||
_("This field requires at least 14 digits"))
|
|
||||||
orig_dv = value[-2:]
|
orig_dv = value[-2:]
|
||||||
|
|
||||||
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
|
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)
|
new_2dv = DV_maker(new_2dv % 11)
|
||||||
value = value[:-1] + str(new_2dv)
|
value = value[:-1] + str(new_2dv)
|
||||||
if value[-2:] != orig_dv:
|
if value[-2:] != orig_dv:
|
||||||
raise ValidationError(_("Invalid CNPJ number."))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return orig_value
|
return orig_value
|
||||||
|
|
||||||
|
@ -1,37 +1,43 @@
|
|||||||
"""
|
"""
|
||||||
Canada-specific Form helpers
|
Canada-specific Form helpers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.newforms import ValidationError
|
from django.newforms import ValidationError
|
||||||
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
|
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
|
||||||
from django.newforms.util import smart_unicode
|
from django.newforms.util import smart_unicode
|
||||||
from django.utils.translation import gettext, ugettext
|
from django.utils.translation import gettext, ugettext
|
||||||
import re
|
import re
|
||||||
|
|
||||||
phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
|
phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
|
||||||
sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
|
sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
|
||||||
|
|
||||||
class CAPostalCodeField(RegexField):
|
class CAPostalCodeField(RegexField):
|
||||||
"""Canadian postal code field."""
|
"""Canadian postal code field."""
|
||||||
def __init__(self, *args, **kwargs):
|
default_error_messages = {
|
||||||
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
|
'invalid': gettext(u'Enter a postal code in the format XXX XXX.'),
|
||||||
max_length=None, min_length=None,
|
}
|
||||||
error_message=gettext(u'Enter a postal code in the format XXX XXX.'),
|
|
||||||
*args, **kwargs)
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
|
||||||
class CAPhoneNumberField(Field):
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
"""Canadian phone number field."""
|
|
||||||
def clean(self, value):
|
class CAPhoneNumberField(Field):
|
||||||
"""Validate a phone number.
|
"""Canadian phone number field."""
|
||||||
"""
|
default_error_messages = {
|
||||||
super(CAPhoneNumberField, self).clean(value)
|
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""Validate a phone number.
|
||||||
|
"""
|
||||||
|
super(CAPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
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):
|
class CAProvinceField(Field):
|
||||||
"""
|
"""
|
||||||
@ -39,6 +45,10 @@ class CAProvinceField(Field):
|
|||||||
It normalizes the input to the standard two-leter postal service
|
It normalizes the input to the standard two-leter postal service
|
||||||
abbreviation for the given province.
|
abbreviation for the given province.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Enter a Canadian province or territory.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
from ca_provinces import PROVINCES_NORMALIZED
|
from ca_provinces import PROVINCES_NORMALIZED
|
||||||
super(CAProvinceField, self).clean(value)
|
super(CAProvinceField, self).clean(value)
|
||||||
@ -53,45 +63,49 @@ class CAProvinceField(Field):
|
|||||||
return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
|
return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
raise ValidationError(u'Enter a Canadian province or territory.')
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
class CAProvinceSelect(Select):
|
class CAProvinceSelect(Select):
|
||||||
"""
|
"""
|
||||||
A Select widget that uses a list of Canadian provinces and
|
A Select widget that uses a list of Canadian provinces and
|
||||||
territories as its choices.
|
territories as its choices.
|
||||||
"""
|
"""
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
from ca_provinces import PROVINCE_CHOICES # relative import
|
from ca_provinces import PROVINCE_CHOICES # relative import
|
||||||
super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
|
super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
|
||||||
|
|
||||||
class CASocialInsuranceNumberField(Field):
|
class CASocialInsuranceNumberField(Field):
|
||||||
"""
|
"""
|
||||||
A Canadian Social Insurance Number (SIN).
|
A Canadian Social Insurance Number (SIN).
|
||||||
|
|
||||||
Checks the following rules to determine whether the number is valid:
|
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"
|
* Passes the check digit process "Luhn Algorithm"
|
||||||
See: http://en.wikipedia.org/wiki/Social_Insurance_Number
|
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):
|
def clean(self, value):
|
||||||
super(CASocialInsuranceNumberField, self).clean(value)
|
super(CASocialInsuranceNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.')
|
|
||||||
match = re.match(sin_re, value)
|
match = re.match(sin_re, value)
|
||||||
if not match:
|
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))
|
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))
|
check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
|
||||||
if not self.luhn_checksum_is_valid(check_number):
|
if not self.luhn_checksum_is_valid(check_number):
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return number
|
return number
|
||||||
|
|
||||||
def luhn_checksum_is_valid(self, number):
|
def luhn_checksum_is_valid(self, number):
|
||||||
"""
|
"""
|
||||||
Checks to make sure that the SIN passes a luhn mod-10 checksum
|
Checks to make sure that the SIN passes a luhn mod-10 checksum
|
||||||
See: http://en.wikipedia.org/wiki/Luhn_algorithm
|
See: http://en.wikipedia.org/wiki/Luhn_algorithm
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -109,4 +123,4 @@ class CASocialInsuranceNumberField(Field):
|
|||||||
|
|
||||||
sum = sum + digit
|
sum = sum + digit
|
||||||
|
|
||||||
return ( (sum % 10) == 0 )
|
return ( (sum % 10) == 0 )
|
||||||
|
@ -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}$')
|
phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
|
||||||
|
|
||||||
class CHZipCodeField(RegexField):
|
class CHZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(CHZipCodeField, self).__init__(r'^\d{4}$',
|
super(CHZipCodeField, self).__init__(r'^\d{4}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class CHPhoneNumberField(Field):
|
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' and '0XXXXXXXXX' validate but are corrected to
|
||||||
'0XX XXX XX XX'.
|
'0XX XXX XX XX'.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(CHPhoneNumberField, self).clean(value)
|
super(CHPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
@ -33,7 +39,7 @@ class CHPhoneNumberField(Field):
|
|||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
|
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):
|
class CHStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -54,6 +60,10 @@ class CHIdentityCardNumberField(Field):
|
|||||||
|
|
||||||
Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
|
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):
|
def has_valid_checksum(self, number):
|
||||||
given_number, given_checksum = number[:-1], number[-1]
|
given_number, given_checksum = number[:-1], number[-1]
|
||||||
new_number = given_number
|
new_number = given_number
|
||||||
@ -87,23 +97,22 @@ class CHIdentityCardNumberField(Field):
|
|||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(CHIdentityCardNumberField, self).clean(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:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
match = re.match(id_re, value)
|
match = re.match(id_re, value)
|
||||||
if not match:
|
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']
|
idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
|
||||||
|
|
||||||
if idnumber == '00000000' or \
|
if idnumber == '00000000' or \
|
||||||
idnumber == 'A0000000':
|
idnumber == 'A0000000':
|
||||||
raise ValidationError(error_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
all_digits = "%s%s%s" % (idnumber, pos9, checksum)
|
all_digits = "%s%s%s" % (idnumber, pos9, checksum)
|
||||||
if not self.has_valid_checksum(all_digits):
|
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)
|
return u'%s%s%s' % (idnumber, pos9, checksum)
|
||||||
|
|
||||||
|
@ -25,16 +25,21 @@ class CLRutField(RegexField):
|
|||||||
Samples for testing are available from
|
Samples for testing are available from
|
||||||
https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
if 'strict' in kwargs:
|
if 'strict' in kwargs:
|
||||||
del kwargs['strict']
|
del kwargs['strict']
|
||||||
super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
|
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.'),
|
error_message=self.default_error_messages['strict'], *args, **kwargs)
|
||||||
*args, **kwargs)
|
|
||||||
else:
|
else:
|
||||||
# In non-strict mode, accept RUTs that validate but do not exist in
|
# In non-strict mode, accept RUTs that validate but do not exist in
|
||||||
# the real world.
|
# 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):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
@ -47,7 +52,7 @@ class CLRutField(RegexField):
|
|||||||
if self._algorithm(rut) == verificador:
|
if self._algorithm(rut) == verificador:
|
||||||
return self._format(rut, verificador)
|
return self._format(rut, verificador)
|
||||||
else:
|
else:
|
||||||
raise ValidationError(u'The Chilean RUT is not valid.')
|
raise ValidationError(self.error_messages['checksum'])
|
||||||
|
|
||||||
def _algorithm(self, rut):
|
def _algorithm(self, rut):
|
||||||
"""
|
"""
|
||||||
|
@ -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})$")
|
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):
|
class DEZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
|
||||||
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DEZipCodeField, self).__init__(r'^\d{5}$',
|
super(DEZipCodeField, self).__init__(r'^\d{5}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class DEStateSelect(Select):
|
class DEStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -36,6 +37,10 @@ class DEIdentityCardNumberField(Field):
|
|||||||
|
|
||||||
Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis
|
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):
|
def has_valid_checksum(self, number):
|
||||||
given_number, given_checksum = number[:-1], number[-1]
|
given_number, given_checksum = number[:-1], number[-1]
|
||||||
calculated_checksum = 0
|
calculated_checksum = 0
|
||||||
@ -57,23 +62,22 @@ class DEIdentityCardNumberField(Field):
|
|||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(DEIdentityCardNumberField, self).clean(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:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
match = re.match(id_re, value)
|
match = re.match(id_re, value)
|
||||||
if not match:
|
if not match:
|
||||||
raise ValidationError(error_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
gd = match.groupdict()
|
gd = match.groupdict()
|
||||||
residence, origin = gd['residence'], gd['origin']
|
residence, origin = gd['residence'], gd['origin']
|
||||||
birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
|
birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
|
||||||
|
|
||||||
if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
|
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)
|
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 \
|
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):
|
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)
|
return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
|
||||||
|
@ -15,12 +15,14 @@ class ESPostalCodeField(RegexField):
|
|||||||
Spanish postal code is a five digits string, with two first digits
|
Spanish postal code is a five digits string, with two first digits
|
||||||
between 01 and 52, assigned to provinces code.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ESPostalCodeField, self).__init__(
|
super(ESPostalCodeField, self).__init__(
|
||||||
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
|
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class ESPhoneNumberField(RegexField):
|
class ESPhoneNumberField(RegexField):
|
||||||
"""
|
"""
|
||||||
@ -33,11 +35,13 @@ class ESPhoneNumberField(RegexField):
|
|||||||
|
|
||||||
TODO: accept and strip characters like dot, hyphen... in phone number
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
|
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class ESIdentityCardNumberField(RegexField):
|
class ESIdentityCardNumberField(RegexField):
|
||||||
"""
|
"""
|
||||||
@ -58,19 +62,23 @@ class ESIdentityCardNumberField(RegexField):
|
|||||||
public, and different authors have different opinions on which ones allows
|
public, and different authors have different opinions on which ones allows
|
||||||
letters, so both validations are assumed true for all types.
|
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):
|
def __init__(self, only_nif=False, *args, **kwargs):
|
||||||
self.only_nif = only_nif
|
self.only_nif = only_nif
|
||||||
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
|
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
|
||||||
self.cif_control = 'JABCDEFGHI'
|
self.cif_control = 'JABCDEFGHI'
|
||||||
self.cif_types = 'ABCDEFGHKLMNPQS'
|
self.cif_types = 'ABCDEFGHKLMNPQS'
|
||||||
self.nie_types = 'XT'
|
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()),
|
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,
|
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)
|
*args, **kwargs)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
@ -88,13 +96,13 @@ class ESIdentityCardNumberField(RegexField):
|
|||||||
if letter2 == nif_get_checksum(number):
|
if letter2 == nif_get_checksum(number):
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
raise ValidationError, _('Invalid checksum for NIF.')
|
raise ValidationError, self.error_messages['invalid_nif']
|
||||||
elif letter1 in self.nie_types and letter2:
|
elif letter1 in self.nie_types and letter2:
|
||||||
# NIE
|
# NIE
|
||||||
if letter2 == nif_get_checksum(number):
|
if letter2 == nif_get_checksum(number):
|
||||||
return value
|
return value
|
||||||
else:
|
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]:
|
elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]:
|
||||||
# CIF
|
# CIF
|
||||||
if not letter2:
|
if not letter2:
|
||||||
@ -103,9 +111,9 @@ class ESIdentityCardNumberField(RegexField):
|
|||||||
if letter2 in [checksum, self.cif_control[checksum]]:
|
if letter2 in [checksum, self.cif_control[checksum]]:
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
raise ValidationError, _('Invalid checksum for CIF.')
|
raise ValidationError, self.error_messages['invalid_cif']
|
||||||
else:
|
else:
|
||||||
raise ValidationError, _('Please enter a valid %s.' % self.id_types)
|
raise ValidationError, self.error_messages['invalid']
|
||||||
|
|
||||||
class ESCCCField(RegexField):
|
class ESCCCField(RegexField):
|
||||||
"""
|
"""
|
||||||
@ -130,11 +138,14 @@ class ESCCCField(RegexField):
|
|||||||
|
|
||||||
TODO: allow IBAN validation too
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
|
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(ESCCCField, self).clean(value)
|
super(ESCCCField, self).clean(value)
|
||||||
@ -147,7 +158,7 @@ class ESCCCField(RegexField):
|
|||||||
if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
|
if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
raise ValidationError, _('Invalid checksum for bank account number.')
|
raise ValidationError, self.error_messages['checksum']
|
||||||
|
|
||||||
class ESRegionSelect(Select):
|
class ESRegionSelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -8,11 +8,12 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
|
|||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
class FIZipCodeField(RegexField):
|
class FIZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
|
||||||
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(FIZipCodeField, self).__init__(r'^\d{5}$',
|
super(FIZipCodeField, self).__init__(r'^\d{5}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class FIMunicipalitySelect(Select):
|
class FIMunicipalitySelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -23,6 +24,10 @@ class FIMunicipalitySelect(Select):
|
|||||||
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
|
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
|
||||||
|
|
||||||
class FISocialSecurityNumber(Field):
|
class FISocialSecurityNumber(Field):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a valid Finnish social security number.'),
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(FISocialSecurityNumber, self).clean(value)
|
super(FISocialSecurityNumber, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
@ -37,9 +42,9 @@ class FISocialSecurityNumber(Field):
|
|||||||
(?P<serial>(\d{3}))
|
(?P<serial>(\d{3}))
|
||||||
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
|
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
|
||||||
if not result:
|
if not result:
|
||||||
raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
gd = result.groupdict()
|
gd = result.groupdict()
|
||||||
checksum = int(gd['date'] + gd['serial'])
|
checksum = int(gd['date'] + gd['serial'])
|
||||||
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
|
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
|
||||||
return u'%s' % value.upper()
|
return u'%s' % value.upper()
|
||||||
raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
@ -11,11 +11,13 @@ import re
|
|||||||
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
|
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
|
||||||
|
|
||||||
class FRZipCodeField(RegexField):
|
class FRZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(FRZipCodeField, self).__init__(r'^\d{5}$',
|
super(FRZipCodeField, self).__init__(r'^\d{5}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class FRPhoneNumberField(Field):
|
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' and '0XXXXXXXXX' validate but are corrected to
|
||||||
'0X XX XX XX XX'.
|
'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):
|
def clean(self, value):
|
||||||
super(FRPhoneNumberField, self).clean(value)
|
super(FRPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
@ -32,7 +38,7 @@ class FRPhoneNumberField(Field):
|
|||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
|
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):
|
class FRDepartmentSelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -10,11 +10,13 @@ import re
|
|||||||
|
|
||||||
|
|
||||||
class INZipCodeField(RegexField):
|
class INZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': gettext(u'Enter a zip code in the format XXXXXXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(INZipCodeField, self).__init__(r'^\d{6}$',
|
super(INZipCodeField, self).__init__(r'^\d{6}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class INStateField(Field):
|
class INStateField(Field):
|
||||||
"""
|
"""
|
||||||
@ -22,6 +24,10 @@ class INStateField(Field):
|
|||||||
abbreviation. It normalizes the input to the standard two-letter vehicle
|
abbreviation. It normalizes the input to the standard two-letter vehicle
|
||||||
registration abbreviation for the given state or union territory
|
registration abbreviation for the given state or union territory
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Enter a Indian state or territory.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
from in_states import STATES_NORMALIZED
|
from in_states import STATES_NORMALIZED
|
||||||
super(INStateField, self).clean(value)
|
super(INStateField, self).clean(value)
|
||||||
@ -36,7 +42,7 @@ class INStateField(Field):
|
|||||||
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
|
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
raise ValidationError(u'Enter a Indian state or territory.')
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
class INStateSelect(Select):
|
class INStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -13,10 +13,14 @@ class ISIdNumberField(RegexField):
|
|||||||
Icelandic identification number (kennitala). This is a number every citizen
|
Icelandic identification number (kennitala). This is a number every citizen
|
||||||
of Iceland has.
|
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):
|
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
|
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):
|
def clean(self, value):
|
||||||
value = super(ISIdNumberField, self).clean(value)
|
value = super(ISIdNumberField, self).clean(value)
|
||||||
@ -28,7 +32,7 @@ class ISIdNumberField(RegexField):
|
|||||||
if self._validate(value):
|
if self._validate(value):
|
||||||
return self._format(value)
|
return self._format(value)
|
||||||
else:
|
else:
|
||||||
raise ValidationError(ugettext(u'The Icelandic identification number is not valid.'))
|
raise ValidationError(self.error_messages['checksum'])
|
||||||
|
|
||||||
def _canonify(self, value):
|
def _canonify(self, value):
|
||||||
"""
|
"""
|
||||||
|
@ -10,11 +10,12 @@ from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
class ITZipCodeField(RegexField):
|
class ITZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a valid zip code.'),
|
||||||
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ITZipCodeField, self).__init__(r'^\d{5}$',
|
super(ITZipCodeField, self).__init__(r'^\d{5}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a valid zip code.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class ITRegionSelect(Select):
|
class ITRegionSelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -38,11 +39,13 @@ class ITSocialSecurityNumberField(RegexField):
|
|||||||
For reference see http://www.agenziaentrate.it/ and search for
|
For reference see http://www.agenziaentrate.it/ and search for
|
||||||
'Informazioni sulla codificazione delle persone fisiche'.
|
'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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
|
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,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
value = super(ITSocialSecurityNumberField, self).clean(value)
|
value = super(ITSocialSecurityNumberField, self).clean(value)
|
||||||
@ -52,26 +55,29 @@ class ITSocialSecurityNumberField(RegexField):
|
|||||||
try:
|
try:
|
||||||
check_digit = ssn_check_digit(value)
|
check_digit = ssn_check_digit(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(self.err_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
if not value[15] == check_digit:
|
if not value[15] == check_digit:
|
||||||
raise ValidationError(self.err_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return value
|
return value
|
||||||
|
|
||||||
class ITVatNumberField(Field):
|
class ITVatNumberField(Field):
|
||||||
"""
|
"""
|
||||||
A form field that validates Italian VAT numbers (partita IVA).
|
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):
|
def clean(self, value):
|
||||||
value = super(ITVatNumberField, self).clean(value)
|
value = super(ITVatNumberField, self).clean(value)
|
||||||
if value == u'':
|
if value == u'':
|
||||||
return value
|
return value
|
||||||
err_msg = ugettext(u'Enter a valid VAT number.')
|
|
||||||
try:
|
try:
|
||||||
vat_number = int(value)
|
vat_number = int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(err_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
vat_number = str(vat_number).zfill(11)
|
vat_number = str(vat_number).zfill(11)
|
||||||
check_digit = vat_number_check_digit(vat_number[0:10])
|
check_digit = vat_number_check_digit(vat_number[0:10])
|
||||||
if not vat_number[10] == check_digit:
|
if not vat_number[10] == check_digit:
|
||||||
raise ValidationError(err_msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return smart_unicode(vat_number)
|
return smart_unicode(vat_number)
|
||||||
|
@ -15,11 +15,13 @@ class JPPostalCodeField(RegexField):
|
|||||||
|
|
||||||
Accepts 7 digits, with or without a hyphen.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
|
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
|
@ -17,24 +17,27 @@ class NLZipCodeField(Field):
|
|||||||
"""
|
"""
|
||||||
A Dutch postal code field.
|
A Dutch postal code field.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid postal code'),
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(NLZipCodeField, self).clean(value)
|
super(NLZipCodeField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
msg = _('Enter a valid postal code')
|
|
||||||
value = value.strip().upper().replace(' ', '')
|
value = value.strip().upper().replace(' ', '')
|
||||||
if not pc_re.search(value):
|
if not pc_re.search(value):
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
if int(value[:4]) < 1000:
|
if int(value[:4]) < 1000:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return u'%s %s' % (value[:4], value[4:])
|
return u'%s %s' % (value[:4], value[4:])
|
||||||
|
|
||||||
class NLProvinceSelect(Select):
|
class NLProvinceSelect(Select):
|
||||||
"""
|
"""
|
||||||
A Select widget that uses a list of provinces of the Netherlands as its
|
A Select widget that uses a list of provinces of the Netherlands as its
|
||||||
choices.
|
choices.
|
||||||
"""
|
"""
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
@ -45,48 +48,53 @@ class NLPhoneNumberField(Field):
|
|||||||
"""
|
"""
|
||||||
A Dutch telephone number field.
|
A Dutch telephone number field.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid phone number'),
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(NLPhoneNumberField, self).clean(value)
|
super(NLPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
msg = _('Enter a valid phone number')
|
|
||||||
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
|
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
|
||||||
|
|
||||||
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
|
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
if phone_nr[:3] == '+31' and len(phone_nr) == 12 and \
|
if phone_nr[:3] == '+31' and len(phone_nr) == 12 and \
|
||||||
numeric_re.search(phone_nr[3:]):
|
numeric_re.search(phone_nr[3:]):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
class NLSoFiNumberField(Field):
|
class NLSoFiNumberField(Field):
|
||||||
"""
|
"""
|
||||||
A Dutch social security number (SoFi/BSN) field.
|
A Dutch social security number (SoFi/BSN) field.
|
||||||
|
|
||||||
http://nl.wikipedia.org/wiki/Sofinummer
|
http://nl.wikipedia.org/wiki/Sofinummer
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid SoFi number'),
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(NLSoFiNumberField, self).clean(value)
|
super(NLSoFiNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
msg = _('Enter a valid SoFi number')
|
|
||||||
|
|
||||||
if not sofi_re.search(value):
|
if not sofi_re.search(value):
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
if int(value) == 0:
|
if int(value) == 0:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
checksum = 0
|
checksum = 0
|
||||||
for i in range(9, 1, -1):
|
for i in range(9, 1, -1):
|
||||||
checksum += int(value[9-i]) * i
|
checksum += int(value[9-i]) * i
|
||||||
checksum -= int(value[-1])
|
checksum -= int(value[-1])
|
||||||
|
|
||||||
if checksum % 11 != 0:
|
if checksum % 11 != 0:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
@ -8,11 +8,13 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
|
|||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
class NOZipCodeField(RegexField):
|
class NOZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(NOZipCodeField, self).__init__(r'^\d{4}$',
|
super(NOZipCodeField, self).__init__(r'^\d{4}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class NOMunicipalitySelect(Select):
|
class NOMunicipalitySelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -27,14 +29,17 @@ class NOSocialSecurityNumber(Field):
|
|||||||
"""
|
"""
|
||||||
Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer
|
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):
|
def clean(self, value):
|
||||||
super(NOSocialSecurityNumber, self).clean(value)
|
super(NOSocialSecurityNumber, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
msg = ugettext(u'Enter a valid Norwegian social security number.')
|
|
||||||
if not re.match(r'^\d{11}$', value):
|
if not re.match(r'^\d{11}$', value):
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
day = int(value[:2])
|
day = int(value[:2])
|
||||||
month = int(value[2:4])
|
month = int(value[2:4])
|
||||||
@ -52,7 +57,7 @@ class NOSocialSecurityNumber(Field):
|
|||||||
if 900 <= inum < 1000 and year2 > 39:
|
if 900 <= inum < 1000 and year2 > 39:
|
||||||
self.birthday = datetime.date(1900+year2, month, day)
|
self.birthday = datetime.date(1900+year2, month, day)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
sexnum = int(value[8])
|
sexnum = int(value[8])
|
||||||
if sexnum % 2 == 0:
|
if sexnum % 2 == 0:
|
||||||
@ -68,9 +73,9 @@ class NOSocialSecurityNumber(Field):
|
|||||||
return sum([(a * b) for (a, b) in zip(aval, bval)])
|
return sum([(a * b) for (a, b) in zip(aval, bval)])
|
||||||
|
|
||||||
if multiply_reduce(digits, weight_1) % 11 != 0:
|
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:
|
if multiply_reduce(digits, weight_2) % 11 != 0:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -19,6 +19,11 @@ class PEDNIField(CharField):
|
|||||||
"""
|
"""
|
||||||
A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers.
|
A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext("This field requires only numbers."),
|
||||||
|
'max_digits': ugettext("This field requires 8 digits."),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PEDNIField, self).__init__(max_length=8, min_length=8, *args,
|
super(PEDNIField, self).__init__(max_length=8, min_length=8, *args,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
@ -31,9 +36,9 @@ class PEDNIField(CharField):
|
|||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
if not value.isdigit():
|
if not value.isdigit():
|
||||||
raise ValidationError(ugettext("This field requires only numbers."))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
if len(value) != 8:
|
if len(value) != 8:
|
||||||
raise ValidationError(ugettext("This field requires 8 digits."))
|
raise ValidationError(self.error_messages['max_digits'])
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -42,6 +47,11 @@ class PERUCField(RegexField):
|
|||||||
This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of
|
This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of
|
||||||
the form XXXXXXXXXXX.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PERUCField, self).__init__(max_length=11, min_length=11, *args,
|
super(PERUCField, self).__init__(max_length=11, min_length=11, *args,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
@ -54,8 +64,8 @@ class PERUCField(RegexField):
|
|||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
if not value.isdigit():
|
if not value.isdigit():
|
||||||
raise ValidationError(ugettext("This field requires only numbers."))
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
if len(value) != 11:
|
if len(value) != 11:
|
||||||
raise ValidationError(ugettext("This field requires 11 digits."))
|
raise ValidationError(self.error_messages['max_digits'])
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -35,16 +35,19 @@ class PLNationalIdentificationNumberField(RegexField):
|
|||||||
|
|
||||||
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
|
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
|
||||||
max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self,value):
|
def clean(self,value):
|
||||||
super(PLNationalIdentificationNumberField, self).clean(value)
|
super(PLNationalIdentificationNumberField, self).clean(value)
|
||||||
if not self.has_valid_checksum(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
|
return u'%s' % value
|
||||||
|
|
||||||
def has_valid_checksum(self, number):
|
def has_valid_checksum(self, number):
|
||||||
@ -65,17 +68,20 @@ class PLTaxNumberField(RegexField):
|
|||||||
Checksum algorithm based on documentation at
|
Checksum algorithm based on documentation at
|
||||||
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
|
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):
|
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}$',
|
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,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self,value):
|
def clean(self,value):
|
||||||
super(PLTaxNumberField, self).clean(value)
|
super(PLTaxNumberField, self).clean(value)
|
||||||
value = re.sub("[-]", "", value)
|
value = re.sub("[-]", "", value)
|
||||||
if not self.has_valid_checksum(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
|
return u'%s' % value
|
||||||
|
|
||||||
def has_valid_checksum(self, number):
|
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
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',
|
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.'),
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self,value):
|
def clean(self,value):
|
||||||
super(PLNationalBusinessRegisterField, self).clean(value)
|
super(PLNationalBusinessRegisterField, self).clean(value)
|
||||||
if not self.has_valid_checksum(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
|
return u'%s' % value
|
||||||
|
|
||||||
def has_valid_checksum(self, number):
|
def has_valid_checksum(self, number):
|
||||||
@ -142,9 +152,10 @@ class PLPostalCodeField(RegexField):
|
|||||||
A form field that validates as Polish postal code.
|
A form field that validates as Polish postal code.
|
||||||
Valid code is XX-XXX where X is digit.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
|
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=_(u'Enter a postal code in the format XX-XXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
|
@ -26,11 +26,13 @@ class SKPostalCodeField(RegexField):
|
|||||||
A form field that validates its input as Slovak postal code.
|
A form field that validates its input as Slovak postal code.
|
||||||
Valid form is XXXXX or XXX XX, where X represents integer.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
|
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"""
|
"""
|
||||||
|
@ -2,21 +2,39 @@
|
|||||||
UK-specific Form helpers
|
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
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
class UKPostcodeField(RegexField):
|
class UKPostcodeField(CharField):
|
||||||
"""
|
"""
|
||||||
A form field that validates its input is a UK postcode.
|
A form field that validates its input is a UK postcode.
|
||||||
|
|
||||||
The regular expression used is sourced from the schema for British Standard
|
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
|
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):
|
default_error_messages = {
|
||||||
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})$',
|
'invalid': ugettext(u'Enter a valid postcode.'),
|
||||||
max_length=None, min_length=None,
|
}
|
||||||
error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
|
outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
|
||||||
*args, **kwargs)
|
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):
|
class UKCountySelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -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})$")
|
ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$")
|
||||||
|
|
||||||
class USZipCodeField(RegexField):
|
class USZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
|
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
|
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
class USPhoneNumberField(Field):
|
class USPhoneNumberField(Field):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
super(USPhoneNumberField, self).clean(value)
|
super(USPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
@ -27,7 +33,7 @@ class USPhoneNumberField(Field):
|
|||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
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):
|
class USSocialSecurityNumberField(Field):
|
||||||
"""
|
"""
|
||||||
@ -44,28 +50,31 @@ class USSocialSecurityNumberField(Field):
|
|||||||
promotional use or distribution (e.g., the Woolworth's number or the
|
promotional use or distribution (e.g., the Woolworth's number or the
|
||||||
1962 promotional number).
|
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):
|
def clean(self, value):
|
||||||
super(USSocialSecurityNumberField, self).clean(value)
|
super(USSocialSecurityNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
|
|
||||||
match = re.match(ssn_re, value)
|
match = re.match(ssn_re, value)
|
||||||
if not match:
|
if not match:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
|
area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
|
||||||
|
|
||||||
# First pass: no blocks of all zeroes.
|
# First pass: no blocks of all zeroes.
|
||||||
if area == '000' or \
|
if area == '000' or \
|
||||||
group == '00' or \
|
group == '00' or \
|
||||||
serial == '0000':
|
serial == '0000':
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
# Second pass: promotional and otherwise permanently invalid numbers.
|
# Second pass: promotional and otherwise permanently invalid numbers.
|
||||||
if area == '666' or \
|
if area == '666' or \
|
||||||
(area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \
|
(area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \
|
||||||
value == '078-05-1120' or \
|
value == '078-05-1120' or \
|
||||||
value == '219-09-9999':
|
value == '219-09-9999':
|
||||||
raise ValidationError(msg)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return u'%s-%s-%s' % (area, group, serial)
|
return u'%s-%s-%s' % (area, group, serial)
|
||||||
|
|
||||||
class USStateField(Field):
|
class USStateField(Field):
|
||||||
@ -74,6 +83,10 @@ class USStateField(Field):
|
|||||||
It normalizes the input to the standard two-leter postal service
|
It normalizes the input to the standard two-leter postal service
|
||||||
abbreviation for the given state.
|
abbreviation for the given state.
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': u'Enter a U.S. state or territory.',
|
||||||
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
from us_states import STATES_NORMALIZED
|
from us_states import STATES_NORMALIZED
|
||||||
super(USStateField, self).clean(value)
|
super(USStateField, self).clean(value)
|
||||||
@ -88,7 +101,7 @@ class USStateField(Field):
|
|||||||
return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
|
return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
raise ValidationError(u'Enter a U.S. state or territory.')
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
class USStateSelect(Select):
|
class USStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
|
@ -16,10 +16,9 @@ class ZAIDField(Field):
|
|||||||
using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
|
using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
|
||||||
check for the birthdate
|
check for the birthdate
|
||||||
"""
|
"""
|
||||||
|
default_error_messages = {
|
||||||
def __init__(self, *args, **kwargs):
|
'invalid': _(u'Enter a valid South African ID number'),
|
||||||
super(ZAIDField, self).__init__()
|
}
|
||||||
self.error_message = _(u'Enter a valid South African ID number')
|
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
# strip spaces and dashes
|
# strip spaces and dashes
|
||||||
@ -31,9 +30,9 @@ class ZAIDField(Field):
|
|||||||
return u''
|
return u''
|
||||||
|
|
||||||
match = re.match(id_re, value)
|
match = re.match(id_re, value)
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
raise ValidationError(self.error_message)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
g = match.groupdict()
|
g = match.groupdict()
|
||||||
|
|
||||||
@ -43,15 +42,18 @@ class ZAIDField(Field):
|
|||||||
# There is no way to guess the century of a ZA ID number
|
# 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']))
|
d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(self.error_message)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
if not luhn(value):
|
if not luhn(value):
|
||||||
raise ValidationError(self.error_message)
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
class ZAPostCodeField(RegexField):
|
class ZAPostCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _(u'Enter a valid South African postal code'),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ZAPostCodeField, self).__init__(r'^\d{4}$',
|
super(ZAPostCodeField, self).__init__(r'^\d{4}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None)
|
||||||
error_message=_(u'Enter a valid South African postal code'))
|
|
||||||
|
@ -67,42 +67,32 @@ def make_msgid(idstring=None):
|
|||||||
class BadHeaderError(ValueError):
|
class BadHeaderError(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
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))
|
||||||
|
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)
|
||||||
|
return name, val
|
||||||
|
|
||||||
class SafeMIMEText(MIMEText):
|
class SafeMIMEText(MIMEText):
|
||||||
def __setitem__(self, name, val):
|
def __setitem__(self, name, val):
|
||||||
"Forbids multi-line headers, to prevent header injection."
|
name, val = forbid_multi_line_headers(name, val)
|
||||||
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)
|
|
||||||
MIMEText.__setitem__(self, name, val)
|
MIMEText.__setitem__(self, name, val)
|
||||||
|
|
||||||
class SafeMIMEMultipart(MIMEMultipart):
|
class SafeMIMEMultipart(MIMEMultipart):
|
||||||
def __setitem__(self, name, val):
|
def __setitem__(self, name, val):
|
||||||
"Forbids multi-line headers, to prevent header injection."
|
name, val = forbid_multi_line_headers(name, val)
|
||||||
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)
|
|
||||||
MIMEMultipart.__setitem__(self, name, val)
|
MIMEMultipart.__setitem__(self, name, val)
|
||||||
|
|
||||||
class SMTPConnection(object):
|
class SMTPConnection(object):
|
||||||
@ -209,8 +199,14 @@ class EmailMessage(object):
|
|||||||
bytestrings). The SafeMIMEText class will handle any necessary encoding
|
bytestrings). The SafeMIMEText class will handle any necessary encoding
|
||||||
conversions.
|
conversions.
|
||||||
"""
|
"""
|
||||||
self.to = to or []
|
if to:
|
||||||
self.bcc = bcc or []
|
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.from_email = from_email or settings.DEFAULT_FROM_EMAIL
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.body = body
|
self.body = body
|
||||||
|
@ -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.'),
|
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',
|
make_option('--pythonpath',
|
||||||
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
|
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 = ''
|
help = ''
|
||||||
args = ''
|
args = ''
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.core import serializers
|
||||||
|
|
||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
option_list = BaseCommand.option_list + (
|
option_list = BaseCommand.option_list + (
|
||||||
make_option('--format', default='json', dest='format',
|
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',
|
make_option('--indent', default=None, dest='indent', type='int',
|
||||||
help='Specifies the indent level to use when pretty-printing output'),
|
help='Specifies the indent level to use when pretty-printing output'),
|
||||||
)
|
)
|
||||||
@ -14,10 +15,10 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def handle(self, *app_labels, **options):
|
def handle(self, *app_labels, **options):
|
||||||
from django.db.models import get_app, get_apps, get_models
|
from django.db.models import get_app, get_apps, get_models
|
||||||
from django.core import serializers
|
|
||||||
|
|
||||||
format = options.get('format', 'json')
|
format = options.get('format', 'json')
|
||||||
indent = options.get('indent', None)
|
indent = options.get('indent', None)
|
||||||
|
show_traceback = options.get('traceback', False)
|
||||||
|
|
||||||
if len(app_labels) == 0:
|
if len(app_labels) == 0:
|
||||||
app_list = get_apps()
|
app_list = get_apps()
|
||||||
@ -26,6 +27,9 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Check that the serialization format exists; this is a shortcut to
|
# Check that the serialization format exists; this is a shortcut to
|
||||||
# avoid collating all the objects and _then_ failing.
|
# 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:
|
try:
|
||||||
serializers.get_serializer(format)
|
serializers.get_serializer(format)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -34,8 +38,10 @@ class Command(BaseCommand):
|
|||||||
objects = []
|
objects = []
|
||||||
for app in app_list:
|
for app in app_list:
|
||||||
for model in get_models(app):
|
for model in get_models(app):
|
||||||
objects.extend(model.objects.all())
|
objects.extend(model._default_manager.all())
|
||||||
try:
|
try:
|
||||||
return serializers.serialize(format, objects, indent=indent)
|
return serializers.serialize(format, objects, indent=indent)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
if show_traceback:
|
||||||
|
raise
|
||||||
raise CommandError("Unable to serialize database: %s" % e)
|
raise CommandError("Unable to serialize database: %s" % e)
|
||||||
|
@ -27,6 +27,7 @@ class Command(BaseCommand):
|
|||||||
self.style = no_style()
|
self.style = no_style()
|
||||||
|
|
||||||
verbosity = int(options.get('verbosity', 1))
|
verbosity = int(options.get('verbosity', 1))
|
||||||
|
show_traceback = options.get('traceback', False)
|
||||||
|
|
||||||
# Keep a count of the installed objects and fixtures
|
# Keep a count of the installed objects and fixtures
|
||||||
count = [0, 0]
|
count = [0, 0]
|
||||||
@ -50,10 +51,10 @@ class Command(BaseCommand):
|
|||||||
parts = fixture_label.split('.')
|
parts = fixture_label.split('.')
|
||||||
if len(parts) == 1:
|
if len(parts) == 1:
|
||||||
fixture_name = fixture_label
|
fixture_name = fixture_label
|
||||||
formats = serializers.get_serializer_formats()
|
formats = serializers.get_public_serializer_formats()
|
||||||
else:
|
else:
|
||||||
fixture_name, format = '.'.join(parts[:-1]), parts[-1]
|
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]
|
formats = [format]
|
||||||
else:
|
else:
|
||||||
formats = []
|
formats = []
|
||||||
@ -98,11 +99,13 @@ class Command(BaseCommand):
|
|||||||
label_found = True
|
label_found = True
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
fixture.close()
|
fixture.close()
|
||||||
|
transaction.rollback()
|
||||||
|
transaction.leave_transaction_management()
|
||||||
|
if show_traceback:
|
||||||
|
raise
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
self.style.ERROR("Problem installing fixture '%s': %s\n" %
|
self.style.ERROR("Problem installing fixture '%s': %s\n" %
|
||||||
(full_path, str(e))))
|
(full_path, str(e))))
|
||||||
transaction.rollback()
|
|
||||||
transaction.leave_transaction_management()
|
|
||||||
return
|
return
|
||||||
fixture.close()
|
fixture.close()
|
||||||
except:
|
except:
|
||||||
|
@ -116,6 +116,7 @@ def sql_delete(app, style):
|
|||||||
"Returns a list of the DROP TABLE SQL statements for the given app."
|
"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 import connection, models, get_introspection_module
|
||||||
from django.db.backends.util import truncate_name
|
from django.db.backends.util import truncate_name
|
||||||
|
from django.contrib.contenttypes import generic
|
||||||
introspection = get_introspection_module()
|
introspection = get_introspection_module()
|
||||||
|
|
||||||
# This should work even if a connection isn't available
|
# This should work even if a connection isn't available
|
||||||
@ -179,6 +180,8 @@ def sql_delete(app, style):
|
|||||||
for model in app_models:
|
for model in app_models:
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
for f in opts.many_to_many:
|
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:
|
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
|
||||||
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
|
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
|
||||||
style.SQL_TABLE(qn(f.m2m_db_table()))))
|
style.SQL_TABLE(qn(f.m2m_db_table()))))
|
||||||
|
@ -53,6 +53,11 @@ def get_serializer_formats():
|
|||||||
_load_serializers()
|
_load_serializers()
|
||||||
return _serializers.keys()
|
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):
|
def get_deserializer(format):
|
||||||
if not _serializers:
|
if not _serializers:
|
||||||
_load_serializers()
|
_load_serializers()
|
||||||
|
@ -22,6 +22,10 @@ class Serializer(object):
|
|||||||
Abstract serializer base class.
|
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):
|
def serialize(self, queryset, **options):
|
||||||
"""
|
"""
|
||||||
Serialize a queryset.
|
Serialize a queryset.
|
||||||
|
@ -20,6 +20,8 @@ class Serializer(PythonSerializer):
|
|||||||
"""
|
"""
|
||||||
Convert a queryset to JSON.
|
Convert a queryset to JSON.
|
||||||
"""
|
"""
|
||||||
|
internal_use_only = False
|
||||||
|
|
||||||
def end_serialization(self):
|
def end_serialization(self):
|
||||||
self.options.pop('stream', None)
|
self.options.pop('stream', None)
|
||||||
self.options.pop('fields', None)
|
self.options.pop('fields', None)
|
||||||
|
@ -13,7 +13,9 @@ class Serializer(base.Serializer):
|
|||||||
"""
|
"""
|
||||||
Serializes a QuerySet to basic Python objects.
|
Serializes a QuerySet to basic Python objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
internal_use_only = True
|
||||||
|
|
||||||
def start_serialization(self):
|
def start_serialization(self):
|
||||||
self._current = None
|
self._current = None
|
||||||
self.objects = []
|
self.objects = []
|
||||||
|
@ -19,6 +19,8 @@ class Serializer(PythonSerializer):
|
|||||||
Convert a queryset to YAML.
|
Convert a queryset to YAML.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
internal_use_only = False
|
||||||
|
|
||||||
def handle_field(self, obj, field):
|
def handle_field(self, obj, field):
|
||||||
# A nasty special case: base YAML doesn't support serialization of time
|
# A nasty special case: base YAML doesn't support serialization of time
|
||||||
# types (as opposed to dates or datetimes, which it does support). Since
|
# types (as opposed to dates or datetimes, which it does support). Since
|
||||||
|
@ -398,8 +398,20 @@ class ServerHandler(object):
|
|||||||
self.bytes_sent += len(data)
|
self.bytes_sent += len(data)
|
||||||
|
|
||||||
# XXX check Content-Length and truncate if too many bytes written?
|
# XXX check Content-Length and truncate if too many bytes written?
|
||||||
self._write(data)
|
|
||||||
self._flush()
|
# 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()
|
||||||
|
|
||||||
def sendfile(self):
|
def sendfile(self):
|
||||||
"""Platform-specific file transmission
|
"""Platform-specific file transmission
|
||||||
|
@ -413,6 +413,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
return self.connection is not None
|
return self.connection is not None
|
||||||
|
|
||||||
def _cursor(self, settings):
|
def _cursor(self, settings):
|
||||||
|
cursor = None
|
||||||
if not self._valid_connection():
|
if not self._valid_connection():
|
||||||
if len(settings.DATABASE_HOST.strip()) == 0:
|
if len(settings.DATABASE_HOST.strip()) == 0:
|
||||||
settings.DATABASE_HOST = 'localhost'
|
settings.DATABASE_HOST = 'localhost'
|
||||||
@ -422,16 +423,25 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
else:
|
else:
|
||||||
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
|
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
|
||||||
self.connection = Database.connect(conn_string, **self.options)
|
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:
|
try:
|
||||||
self.oracle_version = int(self.connection.version.split('.')[0])
|
self.oracle_version = int(self.connection.version.split('.')[0])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
cursor = FormatStylePlaceholderCursor(self.connection)
|
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.
|
# Default arraysize of 1 is highly sub-optimal.
|
||||||
cursor.arraysize = 100
|
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
|
return cursor
|
||||||
|
|
||||||
class FormatStylePlaceholderCursor(Database.Cursor):
|
class FormatStylePlaceholderCursor(Database.Cursor):
|
||||||
|
@ -714,7 +714,7 @@ class EmailField(CharField):
|
|||||||
class FileField(Field):
|
class FileField(Field):
|
||||||
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
|
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
|
||||||
self.upload_to = upload_to
|
self.upload_to = upload_to
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
|
|
||||||
def get_db_prep_save(self, value):
|
def get_db_prep_save(self, value):
|
||||||
@ -910,6 +910,11 @@ class NullBooleanField(Field):
|
|||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
return [oldforms.NullBooleanField]
|
return [oldforms.NullBooleanField]
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {'form_class': forms.NullBooleanField}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(NullBooleanField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PhoneNumberField(IntegerField):
|
class PhoneNumberField(IntegerField):
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
return [oldforms.PhoneNumberField]
|
return [oldforms.PhoneNumberField]
|
||||||
@ -926,11 +931,11 @@ class PhoneNumberField(IntegerField):
|
|||||||
class PositiveIntegerField(IntegerField):
|
class PositiveIntegerField(IntegerField):
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
return [oldforms.PositiveIntegerField]
|
return [oldforms.PositiveIntegerField]
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'min_value': 0}
|
defaults = {'min_value': 0}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(PositiveIntegerField, self).formfield(**defaults)
|
return super(PositiveIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PositiveSmallIntegerField(IntegerField):
|
class PositiveSmallIntegerField(IntegerField):
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
@ -939,7 +944,7 @@ class PositiveSmallIntegerField(IntegerField):
|
|||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'min_value': 0}
|
defaults = {'min_value': 0}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class SlugField(CharField):
|
class SlugField(CharField):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -277,7 +277,20 @@ class HttpResponse(object):
|
|||||||
for key, value in self._headers.values()]) \
|
for key, value in self._headers.values()]) \
|
||||||
+ '\n\n' + self.content
|
+ '\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):
|
def __setitem__(self, header, value):
|
||||||
|
header, value = self._convert_to_ascii(header, value)
|
||||||
self._headers[header.lower()] = (header, value)
|
self._headers[header.lower()] = (header, value)
|
||||||
|
|
||||||
def __delitem__(self, header):
|
def __delitem__(self, header):
|
||||||
|
@ -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
|
determining the formfield for a given database field. It's a callable that
|
||||||
takes a database Field instance and returns a form Field instance.
|
takes a database Field instance and returns a form Field instance.
|
||||||
"""
|
"""
|
||||||
warn("form_for_model is deprecated, use ModelForm instead.",
|
warn("form_for_model is deprecated. Use ModelForm instead.",
|
||||||
PendingDeprecationWarning,
|
PendingDeprecationWarning, stacklevel=3)
|
||||||
stacklevel=3)
|
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
field_list = []
|
field_list = []
|
||||||
for f in opts.fields + opts.many_to_many:
|
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
|
takes a database Field instance, plus **kwargs, and returns a form Field
|
||||||
instance with the given kwargs (i.e. 'initial').
|
instance with the given kwargs (i.e. 'initial').
|
||||||
"""
|
"""
|
||||||
warn("form_for_instance is deprecated, use ModelForm instead.",
|
warn("form_for_instance is deprecated. Use ModelForm instead.",
|
||||||
PendingDeprecationWarning,
|
PendingDeprecationWarning, stacklevel=3)
|
||||||
stacklevel=3)
|
|
||||||
model = instance.__class__
|
model = instance.__class__
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
field_list = []
|
field_list = []
|
||||||
@ -149,10 +147,10 @@ def model_to_dict(instance, fields=None, exclude=None):
|
|||||||
"""
|
"""
|
||||||
Returns a dict containing the data in ``instance`` suitable for passing as
|
Returns a dict containing the data in ``instance`` suitable for passing as
|
||||||
a Form's ``initial`` keyword argument.
|
a Form's ``initial`` keyword argument.
|
||||||
|
|
||||||
``fields`` is an optional list of field names. If provided, only the named
|
``fields`` is an optional list of field names. If provided, only the named
|
||||||
fields will be included in the returned dict.
|
fields will be included in the returned dict.
|
||||||
|
|
||||||
``exclude`` is an optional list of field names. If provided, the named
|
``exclude`` is an optional list of field names. If provided, the named
|
||||||
fields will be excluded from the returned dict, even if they are listed in
|
fields will be excluded from the returned dict, even if they are listed in
|
||||||
the ``fields`` argument.
|
the ``fields`` argument.
|
||||||
@ -187,7 +185,7 @@ def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda
|
|||||||
|
|
||||||
``fields`` is an optional list of field names. If provided, only the named
|
``fields`` is an optional list of field names. If provided, only the named
|
||||||
fields will be included in the returned fields.
|
fields will be included in the returned fields.
|
||||||
|
|
||||||
``exclude`` is an optional list of field names. If provided, the named
|
``exclude`` is an optional list of field names. If provided, the named
|
||||||
fields will be excluded from the returned fields, even if they are listed
|
fields will be excluded from the returned fields, even if they are listed
|
||||||
in the ``fields`` argument.
|
in the ``fields`` argument.
|
||||||
@ -214,9 +212,8 @@ class ModelFormOptions(object):
|
|||||||
self.exclude = getattr(options, 'exclude', None)
|
self.exclude = getattr(options, 'exclude', None)
|
||||||
|
|
||||||
class ModelFormMetaclass(type):
|
class ModelFormMetaclass(type):
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs,
|
||||||
# TODO: no way to specify formfield_callback yet, do we need one, or
|
formfield_callback=lambda f: f.formfield()):
|
||||||
# should it be a special case for the admin?
|
|
||||||
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
|
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))
|
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)
|
base_model = getattr(base_opts, 'model', None)
|
||||||
if base_model and base_model is not opts.model:
|
if base_model and base_model is not opts.model:
|
||||||
raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
|
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
|
# fields declared in base classes override fields from the model
|
||||||
model_fields.update(declared_fields)
|
model_fields.update(declared_fields)
|
||||||
attrs['base_fields'] = model_fields
|
attrs['base_fields'] = model_fields
|
||||||
|
@ -154,15 +154,12 @@ class StringOrigin(Origin):
|
|||||||
|
|
||||||
class Template(object):
|
class Template(object):
|
||||||
def __init__(self, template_string, origin=None, name='<Unknown Template>'):
|
def __init__(self, template_string, origin=None, name='<Unknown Template>'):
|
||||||
"Compilation stage"
|
|
||||||
try:
|
try:
|
||||||
template_string = smart_unicode(template_string)
|
template_string = smart_unicode(template_string)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
raise TemplateEncodingError("Templates can only be constructed from unicode or UTF-8 strings.")
|
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)
|
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.nodelist = compile_string(template_string, origin)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
@ -177,13 +174,18 @@ class Template(object):
|
|||||||
|
|
||||||
def compile_string(template_string, origin):
|
def compile_string(template_string, origin):
|
||||||
"Compiles template_string into NodeList ready for rendering"
|
"Compiles template_string into NodeList ready for rendering"
|
||||||
lexer = lexer_factory(template_string, origin)
|
if settings.TEMPLATE_DEBUG:
|
||||||
parser = parser_factory(lexer.tokenize())
|
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()
|
return parser.parse()
|
||||||
|
|
||||||
class Token(object):
|
class Token(object):
|
||||||
def __init__(self, token_type, contents):
|
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
|
self.token_type, self.contents = token_type, contents
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -200,7 +202,7 @@ class Lexer(object):
|
|||||||
self.origin = origin
|
self.origin = origin
|
||||||
|
|
||||||
def tokenize(self):
|
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
|
in_tag = False
|
||||||
result = []
|
result = []
|
||||||
for bit in tag_re.split(self.template_string):
|
for bit in tag_re.split(self.template_string):
|
||||||
@ -226,30 +228,6 @@ class Lexer(object):
|
|||||||
token = Token(TOKEN_TEXT, token_string)
|
token = Token(TOKEN_TEXT, token_string)
|
||||||
return token
|
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):
|
class Parser(object):
|
||||||
def __init__(self, tokens):
|
def __init__(self, tokens):
|
||||||
self.tokens = tokens
|
self.tokens = tokens
|
||||||
@ -319,17 +297,17 @@ class Parser(object):
|
|||||||
def exit_command(self):
|
def exit_command(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def error(self, token, msg ):
|
def error(self, token, msg):
|
||||||
return TemplateSyntaxError(msg)
|
return TemplateSyntaxError(msg)
|
||||||
|
|
||||||
def empty_variable(self, token):
|
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):
|
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):
|
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):
|
def unclosed_block_tag(self, parse_until):
|
||||||
raise self.error(None, "Unclosed tags: %s " % ', '.join(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:
|
if filter_name in self.filters:
|
||||||
return self.filters[filter_name]
|
return self.filters[filter_name]
|
||||||
else:
|
else:
|
||||||
raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name
|
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)
|
|
||||||
|
|
||||||
class TokenParser(object):
|
class TokenParser(object):
|
||||||
"""
|
"""
|
||||||
@ -426,7 +354,7 @@ class TokenParser(object):
|
|||||||
|
|
||||||
def top(self):
|
def top(self):
|
||||||
"Overload this method to do the actual parsing and return the result."
|
"Overload this method to do the actual parsing and return the result."
|
||||||
raise NotImplemented
|
raise NotImplementedError()
|
||||||
|
|
||||||
def more(self):
|
def more(self):
|
||||||
"Returns True if there is more stuff in the tag."
|
"Returns True if there is more stuff in the tag."
|
||||||
@ -435,7 +363,7 @@ class TokenParser(object):
|
|||||||
def back(self):
|
def back(self):
|
||||||
"Undoes the last microparser. Use this for lookahead and backtracking."
|
"Undoes the last microparser. Use this for lookahead and backtracking."
|
||||||
if not len(self.backout):
|
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()
|
self.pointer = self.backout.pop()
|
||||||
|
|
||||||
def tag(self):
|
def tag(self):
|
||||||
@ -443,7 +371,7 @@ class TokenParser(object):
|
|||||||
subject = self.subject
|
subject = self.subject
|
||||||
i = self.pointer
|
i = self.pointer
|
||||||
if i >= len(subject):
|
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
|
p = i
|
||||||
while i < len(subject) and subject[i] not in (' ', '\t'):
|
while i < len(subject) and subject[i] not in (' ', '\t'):
|
||||||
i += 1
|
i += 1
|
||||||
@ -459,14 +387,14 @@ class TokenParser(object):
|
|||||||
subject = self.subject
|
subject = self.subject
|
||||||
i = self.pointer
|
i = self.pointer
|
||||||
if i >= len(subject):
|
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 ('"', "'"):
|
if subject[i] in ('"', "'"):
|
||||||
p = i
|
p = i
|
||||||
i += 1
|
i += 1
|
||||||
while i < len(subject) and subject[i] != subject[p]:
|
while i < len(subject) and subject[i] != subject[p]:
|
||||||
i += 1
|
i += 1
|
||||||
if i >= len(subject):
|
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
|
i += 1
|
||||||
res = subject[p:i]
|
res = subject[p:i]
|
||||||
while i < len(subject) and subject[i] in (' ', '\t'):
|
while i < len(subject) and subject[i] in (' ', '\t'):
|
||||||
@ -483,7 +411,7 @@ class TokenParser(object):
|
|||||||
while i < len(subject) and subject[i] != c:
|
while i < len(subject) and subject[i] != c:
|
||||||
i += 1
|
i += 1
|
||||||
if i >= len(subject):
|
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
|
i += 1
|
||||||
s = subject[p:i]
|
s = subject[p:i]
|
||||||
while i < len(subject) and subject[i] in (' ', '\t'):
|
while i < len(subject) and subject[i] in (' ', '\t'):
|
||||||
@ -542,8 +470,8 @@ class FilterExpression(object):
|
|||||||
for match in matches:
|
for match in matches:
|
||||||
start = match.start()
|
start = match.start()
|
||||||
if upto != start:
|
if upto != start:
|
||||||
raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s" % \
|
raise TemplateSyntaxError("Could not parse some characters: %s|%s|%s" % \
|
||||||
(token[:upto], token[upto:start], token[start:])
|
(token[:upto], token[upto:start], token[start:]))
|
||||||
if var == None:
|
if var == None:
|
||||||
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
|
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
|
||||||
if i18n_constant:
|
if i18n_constant:
|
||||||
@ -552,9 +480,9 @@ class FilterExpression(object):
|
|||||||
var = '"%s"' % constant.replace(r'\"', '"')
|
var = '"%s"' % constant.replace(r'\"', '"')
|
||||||
upto = match.end()
|
upto = match.end()
|
||||||
if var == None:
|
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] == '_':
|
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:
|
else:
|
||||||
filter_name = match.group("filter_name")
|
filter_name = match.group("filter_name")
|
||||||
args = []
|
args = []
|
||||||
@ -570,7 +498,7 @@ class FilterExpression(object):
|
|||||||
filters.append( (filter_func,args))
|
filters.append( (filter_func,args))
|
||||||
upto = match.end()
|
upto = match.end()
|
||||||
if upto != len(token):
|
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.filters = filters
|
||||||
self.var = Variable(var)
|
self.var = Variable(var)
|
||||||
|
|
||||||
@ -627,7 +555,7 @@ class FilterExpression(object):
|
|||||||
provided.pop(0)
|
provided.pop(0)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Not enough
|
# 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 can be overridden.
|
||||||
defaults = defaults and list(defaults) or []
|
defaults = defaults and list(defaults) or []
|
||||||
@ -636,7 +564,7 @@ class FilterExpression(object):
|
|||||||
defaults.pop(0)
|
defaults.pop(0)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Too many.
|
# 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
|
return True
|
||||||
args_check = staticmethod(args_check)
|
args_check = staticmethod(args_check)
|
||||||
@ -816,22 +744,6 @@ class NodeList(list):
|
|||||||
def render_node(self, node, context):
|
def render_node(self, node, context):
|
||||||
return node.render(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):
|
class TextNode(Node):
|
||||||
def __init__(self, s):
|
def __init__(self, s):
|
||||||
self.s = s
|
self.s = s
|
||||||
@ -861,21 +773,6 @@ class VariableNode(Node):
|
|||||||
else:
|
else:
|
||||||
return force_unicode(output)
|
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):
|
def generic_tag_compiler(params, defaults, name, node_class, parser, token):
|
||||||
"Returns a template.Node subclass."
|
"Returns a template.Node subclass."
|
||||||
bits = token.split_contents()[1:]
|
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)
|
message = "%s takes %s arguments" % (name, bmin)
|
||||||
else:
|
else:
|
||||||
message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
|
message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
|
||||||
raise TemplateSyntaxError, message
|
raise TemplateSyntaxError(message)
|
||||||
return node_class(bits)
|
return node_class(bits)
|
||||||
|
|
||||||
class Library(object):
|
class Library(object):
|
||||||
@ -913,7 +810,7 @@ class Library(object):
|
|||||||
self.tags[name] = compile_function
|
self.tags[name] = compile_function
|
||||||
return compile_function
|
return compile_function
|
||||||
else:
|
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):
|
def tag_function(self,func):
|
||||||
self.tags[getattr(func, "_decorated_function", func).__name__] = func
|
self.tags[getattr(func, "_decorated_function", func).__name__] = func
|
||||||
@ -937,7 +834,7 @@ class Library(object):
|
|||||||
self.filters[name] = filter_func
|
self.filters[name] = filter_func
|
||||||
return filter_func
|
return filter_func
|
||||||
else:
|
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):
|
def filter_function(self, func):
|
||||||
self.filters[getattr(func, "_decorated_function", func).__name__] = func
|
self.filters[getattr(func, "_decorated_function", func).__name__] = func
|
||||||
@ -966,7 +863,7 @@ class Library(object):
|
|||||||
if params[0] == 'context':
|
if params[0] == 'context':
|
||||||
params = params[1:]
|
params = params[1:]
|
||||||
else:
|
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):
|
class InclusionNode(Node):
|
||||||
def __init__(self, vars_to_resolve):
|
def __init__(self, vars_to_resolve):
|
||||||
@ -1003,12 +900,12 @@ def get_library(module_name):
|
|||||||
try:
|
try:
|
||||||
mod = __import__(module_name, {}, {}, [''])
|
mod = __import__(module_name, {}, {}, [''])
|
||||||
except ImportError, e:
|
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:
|
try:
|
||||||
lib = mod.register
|
lib = mod.register
|
||||||
libraries[module_name] = lib
|
libraries[module_name] = lib
|
||||||
except AttributeError:
|
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
|
return lib
|
||||||
|
|
||||||
def add_to_builtins(module_name):
|
def add_to_builtins(module_name):
|
||||||
|
@ -9,7 +9,6 @@ class ContextPopException(Exception):
|
|||||||
|
|
||||||
class Context(object):
|
class Context(object):
|
||||||
"A stack container for variable context"
|
"A stack container for variable context"
|
||||||
|
|
||||||
def __init__(self, dict_=None, autoescape=True):
|
def __init__(self, dict_=None, autoescape=True):
|
||||||
dict_ = dict_ or {}
|
dict_ = dict_ or {}
|
||||||
self.dicts = [dict_]
|
self.dicts = [dict_]
|
||||||
@ -78,11 +77,11 @@ def get_standard_processors():
|
|||||||
try:
|
try:
|
||||||
mod = __import__(module, {}, {}, [attr])
|
mod = __import__(module, {}, {}, [attr])
|
||||||
except ImportError, e:
|
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:
|
try:
|
||||||
func = getattr(mod, attr)
|
func = getattr(mod, attr)
|
||||||
except AttributeError:
|
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)
|
processors.append(func)
|
||||||
_standard_context_processors = tuple(processors)
|
_standard_context_processors = tuple(processors)
|
||||||
return _standard_context_processors
|
return _standard_context_processors
|
||||||
@ -102,4 +101,3 @@ class RequestContext(Context):
|
|||||||
processors = tuple(processors)
|
processors = tuple(processors)
|
||||||
for processor in get_standard_processors() + processors:
|
for processor in get_standard_processors() + processors:
|
||||||
self.update(processor(request))
|
self.update(processor(request))
|
||||||
|
|
||||||
|
97
django/template/debug.py
Normal file
97
django/template/debug.py
Normal 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
|
@ -254,7 +254,7 @@ urlize.is_safe=True
|
|||||||
urlize.needs_autoescape = True
|
urlize.needs_autoescape = True
|
||||||
urlize = stringfilter(urlize)
|
urlize = stringfilter(urlize)
|
||||||
|
|
||||||
def urlizetrunc(value, limit):
|
def urlizetrunc(value, limit, autoescape=None):
|
||||||
"""
|
"""
|
||||||
Converts URLs into clickable links, truncating URLs to the given character
|
Converts URLs into clickable links, truncating URLs to the given character
|
||||||
limit, and adding 'rel=nofollow' attribute to discourage spamming.
|
limit, and adding 'rel=nofollow' attribute to discourage spamming.
|
||||||
@ -262,8 +262,10 @@ def urlizetrunc(value, limit):
|
|||||||
Argument: Length to truncate URLs to.
|
Argument: Length to truncate URLs to.
|
||||||
"""
|
"""
|
||||||
from django.utils.html import urlize
|
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.is_safe = True
|
||||||
|
urlizetrunc.needs_autoescape = True
|
||||||
urlizetrunc = stringfilter(urlizetrunc)
|
urlizetrunc = stringfilter(urlizetrunc)
|
||||||
|
|
||||||
def wordcount(value):
|
def wordcount(value):
|
||||||
|
@ -84,19 +84,16 @@ class FirstOfNode(Node):
|
|||||||
return u''
|
return u''
|
||||||
|
|
||||||
class ForNode(Node):
|
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.loopvars, self.sequence = loopvars, sequence
|
||||||
self.reversed = reversed
|
self.is_reversed = is_reversed
|
||||||
self.nodelist_loop = nodelist_loop
|
self.nodelist_loop = nodelist_loop
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self.reversed:
|
reversed_text = self.is_reversed and ' reversed' or ''
|
||||||
reversed = ' reversed'
|
|
||||||
else:
|
|
||||||
reversed = ''
|
|
||||||
return "<For Node: for %s in %s, tail_len: %d%s>" % \
|
return "<For Node: for %s in %s, tail_len: %d%s>" % \
|
||||||
(', '.join(self.loopvars), self.sequence, len(self.nodelist_loop),
|
(', '.join(self.loopvars), self.sequence, len(self.nodelist_loop),
|
||||||
reversed)
|
reversed_text)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for node in self.nodelist_loop:
|
for node in self.nodelist_loop:
|
||||||
@ -125,22 +122,23 @@ class ForNode(Node):
|
|||||||
if not hasattr(values, '__len__'):
|
if not hasattr(values, '__len__'):
|
||||||
values = list(values)
|
values = list(values)
|
||||||
len_values = len(values)
|
len_values = len(values)
|
||||||
if self.reversed:
|
if self.is_reversed:
|
||||||
values = reversed(values)
|
values = reversed(values)
|
||||||
unpack = len(self.loopvars) > 1
|
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):
|
for i, item in enumerate(values):
|
||||||
context['forloop'] = {
|
# Shortcuts for current loop iteration number.
|
||||||
# Shortcuts for current loop iteration number.
|
loop_dict['counter0'] = i
|
||||||
'counter0': i,
|
loop_dict['counter'] = i+1
|
||||||
'counter': i+1,
|
# Reverse counter iteration numbers.
|
||||||
# Reverse counter iteration numbers.
|
loop_dict['revcounter'] = len_values - i
|
||||||
'revcounter': len_values - i,
|
loop_dict['revcounter0'] = len_values - i - 1
|
||||||
'revcounter0': len_values - i - 1,
|
# Boolean values designating first and last times through loop.
|
||||||
# Boolean values designating first and last times through loop.
|
loop_dict['first'] = (i == 0)
|
||||||
'first': (i == 0),
|
loop_dict['last'] = (i == len_values - 1)
|
||||||
'last': (i == len_values - 1),
|
|
||||||
'parentloop': parentloop,
|
|
||||||
}
|
|
||||||
if unpack:
|
if unpack:
|
||||||
# If there are multiple loop variables, unpack the item into
|
# If there are multiple loop variables, unpack the item into
|
||||||
# them.
|
# them.
|
||||||
@ -619,8 +617,8 @@ def do_for(parser, token):
|
|||||||
raise TemplateSyntaxError("'for' statements should have at least four"
|
raise TemplateSyntaxError("'for' statements should have at least four"
|
||||||
" words: %s" % token.contents)
|
" words: %s" % token.contents)
|
||||||
|
|
||||||
reversed = bits[-1] == 'reversed'
|
is_reversed = bits[-1] == 'reversed'
|
||||||
in_index = reversed and -3 or -2
|
in_index = is_reversed and -3 or -2
|
||||||
if bits[in_index] != 'in':
|
if bits[in_index] != 'in':
|
||||||
raise TemplateSyntaxError("'for' statements should use the format"
|
raise TemplateSyntaxError("'for' statements should use the format"
|
||||||
" 'for x in y': %s" % token.contents)
|
" 'for x in y': %s" % token.contents)
|
||||||
@ -634,7 +632,7 @@ def do_for(parser, token):
|
|||||||
sequence = parser.compile_filter(bits[in_index+1])
|
sequence = parser.compile_filter(bits[in_index+1])
|
||||||
nodelist_loop = parser.parse(('endfor',))
|
nodelist_loop = parser.parse(('endfor',))
|
||||||
parser.delete_first_token()
|
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)
|
do_for = register.tag("for", do_for)
|
||||||
|
|
||||||
def do_ifequal(parser, token, negate):
|
def do_ifequal(parser, token, negate):
|
||||||
@ -814,7 +812,7 @@ def ssi(parser, token):
|
|||||||
Outputs the contents of a given file into the page.
|
Outputs the contents of a given file into the page.
|
||||||
|
|
||||||
Like a simple "include" tag, the ``ssi`` tag includes the contents
|
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::
|
in the current page::
|
||||||
|
|
||||||
{% ssi /home/html/ljworld.com/includes/right_generic.html %}
|
{% 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 %}
|
{% regroup people|dictsort:"gender" by gender as grouped %}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
firstbits = token.contents.split(None, 3)
|
bits = token.contents.split()
|
||||||
if len(firstbits) != 4:
|
if len(bits) != 6:
|
||||||
raise TemplateSyntaxError, "'regroup' tag takes five arguments"
|
raise TemplateSyntaxError, "'regroup' tag takes five arguments"
|
||||||
target = parser.compile_filter(firstbits[1])
|
target = parser.compile_filter(bits[1])
|
||||||
if firstbits[2] != 'by':
|
if bits[2] != 'by':
|
||||||
raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'")
|
raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'")
|
||||||
lastbits_reversed = firstbits[3][::-1].split(None, 2)
|
if bits[4] != 'as':
|
||||||
if lastbits_reversed[1][::-1] != 'as':
|
|
||||||
raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
|
raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
|
||||||
" be 'as'")
|
" be 'as'")
|
||||||
|
|
||||||
expression = parser.compile_filter(lastbits_reversed[2][::-1])
|
expression = parser.compile_filter(bits[3])
|
||||||
|
var_name = bits[5]
|
||||||
var_name = lastbits_reversed[0][::-1]
|
|
||||||
return RegroupNode(target, expression, var_name)
|
return RegroupNode(target, expression, var_name)
|
||||||
regroup = register.tag(regroup)
|
regroup = register.tag(regroup)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import sys, time
|
import sys, time, os
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import connection, get_creation_module
|
from django.db import connection, get_creation_module
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
@ -106,9 +106,32 @@ def create_test_db(verbosity=1, autoclobber=False):
|
|||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
print "Creating test database..."
|
print "Creating test database..."
|
||||||
# If we're using SQLite, it's more convenient to test against an
|
# 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.DATABASE_ENGINE == "sqlite3":
|
||||||
TEST_DATABASE_NAME = ":memory:"
|
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:
|
else:
|
||||||
suffix = {
|
suffix = {
|
||||||
'postgresql': get_postgresql_create_suffix,
|
'postgresql': get_postgresql_create_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)
|
creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)
|
||||||
return
|
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:
|
if verbosity >= 1:
|
||||||
print "Destroying test database..."
|
print "Destroying test database..."
|
||||||
connection.close()
|
connection.close()
|
||||||
TEST_DATABASE_NAME = settings.DATABASE_NAME
|
TEST_DATABASE_NAME = settings.DATABASE_NAME
|
||||||
settings.DATABASE_NAME = old_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()
|
cursor = connection.cursor()
|
||||||
_set_autocommit(connection)
|
_set_autocommit(connection)
|
||||||
time.sleep(1) # To avoid "database is being accessed by other users" errors.
|
time.sleep(1) # To avoid "database is being accessed by other users" errors.
|
||||||
|
@ -507,7 +507,7 @@ Exception Type: {{ exception_type|escape }} at {{ request.path|escape }}
|
|||||||
Exception Value: {{ exception_value|escape }}
|
Exception Value: {{ exception_value|escape }}
|
||||||
</textarea>
|
</textarea>
|
||||||
<br><br>
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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'),
|
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
|
||||||
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
|
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
|
||||||
return HttpResponseNotModified()
|
return HttpResponseNotModified()
|
||||||
mimetype = mimetypes.guess_type(fullpath)[0]
|
mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream'
|
||||||
contents = open(fullpath, 'rb').read()
|
contents = open(fullpath, 'rb').read()
|
||||||
response = HttpResponse(contents, mimetype=mimetype)
|
response = HttpResponse(contents, mimetype=mimetype)
|
||||||
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
|
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
|
||||||
|
response["Content-Length"] = len(contents)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
|
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
|
||||||
|
@ -47,7 +47,11 @@ contenttypes
|
|||||||
============
|
============
|
||||||
|
|
||||||
A light framework for hooking into "types" of content, where each installed
|
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
|
csrf
|
||||||
====
|
====
|
||||||
@ -177,9 +181,13 @@ localflavor
|
|||||||
===========
|
===========
|
||||||
|
|
||||||
A collection of various Django snippets that are useful only for a particular
|
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.
|
contains a ``USZipCodeField`` that you can use to validate U.S. zip codes.
|
||||||
|
|
||||||
|
See the `localflavor documentation`_.
|
||||||
|
|
||||||
|
.. _localflavor documentation: ../localflavor/
|
||||||
|
|
||||||
markup
|
markup
|
||||||
======
|
======
|
||||||
|
|
||||||
|
@ -247,8 +247,8 @@ Anonymous users
|
|||||||
the ``django.contrib.auth.models.User`` interface, with these differences:
|
the ``django.contrib.auth.models.User`` interface, with these differences:
|
||||||
|
|
||||||
* ``id`` is always ``None``.
|
* ``id`` is always ``None``.
|
||||||
* ``is_staff`` and ``is_superuser`` are always False.
|
* ``is_staff`` and ``is_superuser`` are always ``False``.
|
||||||
* ``is_active`` is always True.
|
* ``is_active`` is always ``False``.
|
||||||
* ``groups`` and ``user_permissions`` are always empty.
|
* ``groups`` and ``user_permissions`` are always empty.
|
||||||
* ``is_anonymous()`` returns ``True`` instead of ``False``.
|
* ``is_anonymous()`` returns ``True`` instead of ``False``.
|
||||||
* ``is_authenticated()`` returns ``False`` instead of ``True``.
|
* ``is_authenticated()`` returns ``False`` instead of ``True``.
|
||||||
|
@ -44,8 +44,8 @@ Our class looks something like this::
|
|||||||
# ... (other possibly useful methods omitted) ...
|
# ... (other possibly useful methods omitted) ...
|
||||||
|
|
||||||
This is just an ordinary Python class, with nothing Django-specific about it.
|
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``
|
We'd like to be able to do things like this in our models (we assume the
|
||||||
attribute on the model is an instance of ``Hand``)::
|
``hand`` attribute on the model is an instance of ``Hand``)::
|
||||||
|
|
||||||
example = MyModel.objects.get(pk=1)
|
example = MyModel.objects.get(pk=1)
|
||||||
print example.hand.north
|
print example.hand.north
|
||||||
|
@ -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``.
|
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
|
--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
|
``django-admin.py`` will use the ``DJANGO_SETTINGS_MODULE`` environment
|
||||||
variable.
|
variable.
|
||||||
|
|
||||||
Note that this option is unnecessary in ``manage.py``, because it takes care of
|
Note that this option is unnecessary in ``manage.py``, because it uses
|
||||||
setting ``DJANGO_SETTINGS_MODULE`` for you.
|
``settings.py`` from the current project by default.
|
||||||
|
|
||||||
Extra niceties
|
Extra niceties
|
||||||
==============
|
==============
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
Generating forms for models
|
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
|
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``
|
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
|
model, and you want to create a form that lets people submit comments. In this
|
||||||
|
@ -2,16 +2,22 @@
|
|||||||
The "local flavor" add-ons
|
The "local flavor" add-ons
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Django comes with assorted pieces of code that are useful only for a particular
|
Following its "batteries included" philosophy, Django comes with assorted
|
||||||
country or culture. These pieces of code are organized as a set of
|
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`_.
|
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
|
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 newforms_ framework -- for example, a ``USStateField`` that knows how to
|
||||||
the relevant subpackage. For example, a form with a field for French telephone
|
validate U.S. state abbreviations, and a ``FISocialSecurityNumber`` that knows
|
||||||
numbers is created like so::
|
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 import newforms as forms
|
||||||
from django.contrib.localflavor import fr
|
from django.contrib.localflavor import fr
|
||||||
@ -19,32 +25,48 @@ numbers is created like so::
|
|||||||
class MyForm(forms.Form):
|
class MyForm(forms.Form):
|
||||||
my_french_phone_no = fr.forms.FRPhoneNumberField()
|
my_french_phone_no = fr.forms.FRPhoneNumberField()
|
||||||
|
|
||||||
|
Supported countries
|
||||||
|
===================
|
||||||
|
|
||||||
Countries currently supported by ``localflavor`` are:
|
Countries currently supported by ``localflavor`` are:
|
||||||
|
|
||||||
* Argentina_
|
* Argentina_
|
||||||
* Australia_
|
* Australia_
|
||||||
* Brazil_
|
* Brazil_
|
||||||
* Canada_
|
* Canada_
|
||||||
* Chile_
|
* Chile_
|
||||||
* Finland_
|
* Finland_
|
||||||
* France_
|
* France_
|
||||||
* Germany_
|
* Germany_
|
||||||
* Holland_
|
* Holland_
|
||||||
* Iceland_
|
* Iceland_
|
||||||
* India_
|
* India_
|
||||||
* Italy_
|
* Italy_
|
||||||
* Japan_
|
* Japan_
|
||||||
* Mexico_
|
* Mexico_
|
||||||
* Norway_
|
* Norway_
|
||||||
* Peru_
|
* Peru_
|
||||||
* Poland_
|
* Poland_
|
||||||
* Slovakia_
|
* Slovakia_
|
||||||
* `South Africa`_
|
* `South Africa`_
|
||||||
* Spain_
|
* Spain_
|
||||||
* Switzerland_
|
* Switzerland_
|
||||||
* `United Kingdom`_
|
* `United Kingdom`_
|
||||||
* `United States of America`_
|
* `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)`_
|
.. _Argentina: `Argentina (django.contrib.localflavor.ar)`_
|
||||||
.. _Australia: `Australia (django.contrib.localflavor.au)`_
|
.. _Australia: `Australia (django.contrib.localflavor.au)`_
|
||||||
.. _Brazil: `Brazil (django.contrib.localflavor.br)`_
|
.. _Brazil: `Brazil (django.contrib.localflavor.br)`_
|
||||||
@ -68,29 +90,15 @@ Countries currently supported by ``localflavor`` are:
|
|||||||
.. _Switzerland: `Switzerland (django.contrib.localflavor.ch)`_
|
.. _Switzerland: `Switzerland (django.contrib.localflavor.ch)`_
|
||||||
.. _United Kingdom: `United Kingdom (django.contrib.localflavor.uk)`_
|
.. _United Kingdom: `United Kingdom (django.contrib.localflavor.uk)`_
|
||||||
.. _United States of America: `United States of America (django.contrib.localflavor.us)`_
|
.. _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/
|
.. _newforms: ../newforms/
|
||||||
|
|
||||||
|
Adding flavors
|
||||||
|
==============
|
||||||
|
|
||||||
.. admonition:: Adding a Flavor
|
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
|
||||||
We'd love to add more of these to Django, so please create a ticket for
|
Unicode objects (``u'mystring'``) for strings, rather than setting the encoding
|
||||||
anything that you've found useful. Please use unicode objects
|
in the file. See any of the existing flavors for examples.
|
||||||
(``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``)
|
Argentina (``django.contrib.localflavor.ar``)
|
||||||
=============================================
|
=============================================
|
||||||
@ -108,7 +116,6 @@ ARProvinceSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Argentina's provinces as its choices.
|
A ``Select`` widget that uses a list of Argentina's provinces as its choices.
|
||||||
|
|
||||||
|
|
||||||
Australia (``django.contrib.localflavor.au``)
|
Australia (``django.contrib.localflavor.au``)
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
@ -129,7 +136,6 @@ AUStateSelect
|
|||||||
A ``Select`` widget that uses a list of Australian states/territories as its
|
A ``Select`` widget that uses a list of Australian states/territories as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
Brazil (``django.contrib.localflavor.br``)
|
Brazil (``django.contrib.localflavor.br``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -151,7 +157,6 @@ BRStateSelect
|
|||||||
A ``Select`` widget that uses a list of Brazilian states/territories as its
|
A ``Select`` widget that uses a list of Brazilian states/territories as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
Canada (``django.contrib.localflavor.ca``)
|
Canada (``django.contrib.localflavor.ca``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -176,7 +181,7 @@ CASocialInsuranceNumberField
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
A form field that validates input as a Canadian Social Insurance Number (SIN).
|
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`_.
|
checksum`_.
|
||||||
|
|
||||||
.. _Luhn mod-10 checksum: http://en.wikipedia.org/wiki/Luhn_algorithm
|
.. _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
|
A ``Select`` widget that uses a list of Canadian provinces and territories as
|
||||||
its choices.
|
its choices.
|
||||||
|
|
||||||
|
|
||||||
Chile (``django.contrib.localflavor.cl``)
|
Chile (``django.contrib.localflavor.cl``)
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
@ -203,7 +207,6 @@ CLRegionSelect
|
|||||||
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
|
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
Finland (``django.contrib.localflavor.fi``)
|
Finland (``django.contrib.localflavor.fi``)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
@ -215,7 +218,7 @@ A form field that validates input as a Finnish social security number.
|
|||||||
FIZipCodeField
|
FIZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as a Finnish zip code. Valid codes
|
A form field that validates input as a Finnish zip code. Valid codes
|
||||||
consist of five digits.
|
consist of five digits.
|
||||||
|
|
||||||
FIMunicipalitySelect
|
FIMunicipalitySelect
|
||||||
@ -224,7 +227,6 @@ FIMunicipalitySelect
|
|||||||
A ``Select`` widget that uses a list of Finnish municipalities as its
|
A ``Select`` widget that uses a list of Finnish municipalities as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
France (``django.contrib.localflavor.fr``)
|
France (``django.contrib.localflavor.fr``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -232,13 +234,13 @@ FRPhoneNumberField
|
|||||||
------------------
|
------------------
|
||||||
|
|
||||||
A form field that validates input as a French local phone number. The
|
A form field that validates input as a French local phone number. The
|
||||||
correct format is 0X XX XX XX XX. 0X.XX.XX.XX.XX and 0XXXXXXXXX validate
|
correct format is 0X XX XX XX XX. 0X.XX.XX.XX.XX and 0XXXXXXXXX validate
|
||||||
but are corrected to 0X XX XX XX XX.
|
but are corrected to 0X XX XX XX XX.
|
||||||
|
|
||||||
FRZipCodeField
|
FRZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as a French zip code. Valid codes
|
A form field that validates input as a French zip code. Valid codes
|
||||||
consist of five digits.
|
consist of five digits.
|
||||||
|
|
||||||
FRDepartmentSelect
|
FRDepartmentSelect
|
||||||
@ -246,7 +248,6 @@ FRDepartmentSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of French departments as its choices.
|
A ``Select`` widget that uses a list of French departments as its choices.
|
||||||
|
|
||||||
|
|
||||||
Germany (``django.contrib.localflavor.de``)
|
Germany (``django.contrib.localflavor.de``)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ DEIdentityCardNumberField
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
A form field that validates input as a German identity card number
|
A form field that validates input as a German identity card number
|
||||||
(Personalausweis_). Valid numbers have the format
|
(Personalausweis_). Valid numbers have the format
|
||||||
XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes.
|
XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes.
|
||||||
|
|
||||||
.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis
|
.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis
|
||||||
@ -262,7 +263,7 @@ XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes.
|
|||||||
DEZipCodeField
|
DEZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as a German zip code. Valid codes
|
A form field that validates input as a German zip code. Valid codes
|
||||||
consist of five digits.
|
consist of five digits.
|
||||||
|
|
||||||
DEStateSelect
|
DEStateSelect
|
||||||
@ -270,7 +271,6 @@ DEStateSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of German states as its choices.
|
A ``Select`` widget that uses a list of German states as its choices.
|
||||||
|
|
||||||
|
|
||||||
Holland (``django.contrib.localflavor.nl``)
|
Holland (``django.contrib.localflavor.nl``)
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
@ -296,7 +296,6 @@ NLProvinceSelect
|
|||||||
A ``Select`` widget that uses a list of Dutch provinces as its list of
|
A ``Select`` widget that uses a list of Dutch provinces as its list of
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
Iceland (``django.contrib.localflavor.is_``)
|
Iceland (``django.contrib.localflavor.is_``)
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
@ -304,7 +303,7 @@ ISIdNumberField
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
A form field that validates input as an Icelandic identification number
|
A form field that validates input as an Icelandic identification number
|
||||||
(kennitala). The format is XXXXXX-XXXX.
|
(kennitala). The format is XXXXXX-XXXX.
|
||||||
|
|
||||||
ISPhoneNumberField
|
ISPhoneNumberField
|
||||||
------------------
|
------------------
|
||||||
@ -318,7 +317,6 @@ ISPostalCodeSelect
|
|||||||
A ``Select`` widget that uses a list of Icelandic postal codes as its
|
A ``Select`` widget that uses a list of Icelandic postal codes as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
India (``django.contrib.localflavor.in_``)
|
India (``django.contrib.localflavor.in_``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -326,7 +324,7 @@ INStateField
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
A form field that validates input as an Indian state/territory name or
|
A form field that validates input as an Indian state/territory name or
|
||||||
abbreviation. Input is normalized to the standard two-letter vehicle
|
abbreviation. Input is normalized to the standard two-letter vehicle
|
||||||
registration abbreviation for the given state or territory.
|
registration abbreviation for the given state or territory.
|
||||||
|
|
||||||
INZipCodeField
|
INZipCodeField
|
||||||
@ -341,7 +339,6 @@ INStateSelect
|
|||||||
A ``Select`` widget that uses a list of Indian states/territories as its
|
A ``Select`` widget that uses a list of Indian states/territories as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
|
||||||
Italy (``django.contrib.localflavor.it``)
|
Italy (``django.contrib.localflavor.it``)
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
@ -361,7 +358,7 @@ A form field that validates Italian VAT numbers (partita IVA).
|
|||||||
ITZipCodeField
|
ITZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as an Italian zip code. Valid codes
|
A form field that validates input as an Italian zip code. Valid codes
|
||||||
must have five digits.
|
must have five digits.
|
||||||
|
|
||||||
ITProvinceSelect
|
ITProvinceSelect
|
||||||
@ -374,22 +371,20 @@ ITRegionSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Italian regions as its choices.
|
A ``Select`` widget that uses a list of Italian regions as its choices.
|
||||||
|
|
||||||
|
|
||||||
Japan (``django.contrib.localflavor.jp``)
|
Japan (``django.contrib.localflavor.jp``)
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
JPPostalCodeField
|
JPPostalCodeField
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A form field that validates input as a Japanese postcode.
|
A form field that validates input as a Japanese postcode. It accepts seven
|
||||||
It accepts seven digits, with or without a hyphen.
|
digits, with or without a hyphen.
|
||||||
|
|
||||||
JPPrefectureSelect
|
JPPrefectureSelect
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
|
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
|
||||||
|
|
||||||
|
|
||||||
Mexico (``django.contrib.localflavor.mx``)
|
Mexico (``django.contrib.localflavor.mx``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -398,7 +393,6 @@ MXStateSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Mexican states as its choices.
|
A ``Select`` widget that uses a list of Mexican states as its choices.
|
||||||
|
|
||||||
|
|
||||||
Norway (``django.contrib.localflavor.no``)
|
Norway (``django.contrib.localflavor.no``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -413,7 +407,7 @@ A form field that validates input as a Norwegian social security number
|
|||||||
NOZipCodeField
|
NOZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as a Norwegian zip code. Valid codes
|
A form field that validates input as a Norwegian zip code. Valid codes
|
||||||
have four digits.
|
have four digits.
|
||||||
|
|
||||||
NOMunicipalitySelect
|
NOMunicipalitySelect
|
||||||
@ -422,7 +416,6 @@ NOMunicipalitySelect
|
|||||||
A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as
|
A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as
|
||||||
its choices.
|
its choices.
|
||||||
|
|
||||||
|
|
||||||
Peru (``django.contrib.localflavor.pe``)
|
Peru (``django.contrib.localflavor.pe``)
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
@ -436,14 +429,13 @@ PERUCField
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
A form field that validates input as an RUC (Registro Unico de
|
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
|
PEDepartmentSelect
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
|
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
|
||||||
|
|
||||||
|
|
||||||
Poland (``django.contrib.localflavor.pl``)
|
Poland (``django.contrib.localflavor.pl``)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
@ -459,7 +451,7 @@ PLNationalBusinessRegisterField
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
A form field that validates input as a Polish National Official Business
|
A form field that validates input as a Polish National Official Business
|
||||||
Register Number (REGON_), having either seven or nine digits. The checksum
|
Register Number (REGON_), having either seven or nine digits. The checksum
|
||||||
algorithm used for REGONs is documented at
|
algorithm used for REGONs is documented at
|
||||||
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
||||||
|
|
||||||
@ -468,14 +460,14 @@ http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
|||||||
PLPostalCodeField
|
PLPostalCodeField
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A form field that validates input as a Polish postal code. The valid format
|
A form field that validates input as a Polish postal code. The valid format
|
||||||
is XX-XXX, where X is a digit.
|
is XX-XXX, where X is a digit.
|
||||||
|
|
||||||
PLTaxNumberField
|
PLTaxNumberField
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
A form field that validates input as a Polish Tax Number (NIP). Valid
|
A form field that validates input as a Polish Tax Number (NIP). Valid
|
||||||
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
|
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
|
||||||
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
||||||
|
|
||||||
PLAdministrativeUnitSelect
|
PLAdministrativeUnitSelect
|
||||||
@ -490,14 +482,13 @@ PLVoivodeshipSelect
|
|||||||
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
||||||
provinces) as its choices.
|
provinces) as its choices.
|
||||||
|
|
||||||
|
|
||||||
Slovakia (``django.contrib.localflavor.sk``)
|
Slovakia (``django.contrib.localflavor.sk``)
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
SKPostalCodeField
|
SKPostalCodeField
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A form field that validates input as a Slovak postal code. Valid formats
|
A form field that validates input as a Slovak postal code. Valid formats
|
||||||
are XXXXX or XXX XX, where X is a digit.
|
are XXXXX or XXX XX, where X is a digit.
|
||||||
|
|
||||||
SKDistrictSelect
|
SKDistrictSelect
|
||||||
@ -510,24 +501,22 @@ SKRegionSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Slovak regions as its choices.
|
A ``Select`` widget that uses a list of Slovak regions as its choices.
|
||||||
|
|
||||||
|
|
||||||
South Africa (``django.contrib.localflavor.za``)
|
South Africa (``django.contrib.localflavor.za``)
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
ZAIDField
|
ZAIDField
|
||||||
---------
|
---------
|
||||||
|
|
||||||
A form field that validates input as a South African ID number. Validation
|
A form field that validates input as a South African ID number. Validation
|
||||||
uses the Luhn checksum and a simplistic (i.e., not entirely accurate) check
|
uses the Luhn checksum and a simplistic (i.e., not entirely accurate) check
|
||||||
for birth date.
|
for birth date.
|
||||||
|
|
||||||
ZAPostCodeField
|
ZAPostCodeField
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
A form field that validates input as a South African postcode. Valid
|
A form field that validates input as a South African postcode. Valid
|
||||||
postcodes must have four digits.
|
postcodes must have four digits.
|
||||||
|
|
||||||
|
|
||||||
Spain (``django.contrib.localflavor.es``)
|
Spain (``django.contrib.localflavor.es``)
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
@ -541,23 +530,23 @@ ESCCCField
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
A form field that validates input as a Spanish bank account number (Codigo
|
A form field that validates input as a Spanish bank account number (Codigo
|
||||||
Cuenta Cliente or CCC). A valid CCC number has the format
|
Cuenta Cliente or CCC). A valid CCC number has the format
|
||||||
EEEE-OOOO-CC-AAAAAAAAAA, where the E, O, C and A digits denote the entity,
|
EEEE-OOOO-CC-AAAAAAAAAA, where the E, O, C and A digits denote the entity,
|
||||||
office, checksum and account, respectively. The first checksum digit
|
office, checksum and account, respectively. The first checksum digit
|
||||||
validates the entity and office. The second checksum digit validates the
|
validates the entity and office. The second checksum digit validates the
|
||||||
account. It is also valid to use a space as a delimiter, or to use no
|
account. It is also valid to use a space as a delimiter, or to use no
|
||||||
delimiter.
|
delimiter.
|
||||||
|
|
||||||
ESPhoneNumberField
|
ESPhoneNumberField
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
A form field that validates input as a Spanish phone number. Valid numbers
|
A form field that validates input as a Spanish phone number. Valid numbers
|
||||||
have nine digits, the first of which is 6, 8 or 9.
|
have nine digits, the first of which is 6, 8 or 9.
|
||||||
|
|
||||||
ESPostalCodeField
|
ESPostalCodeField
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A form field that validates input as a Spanish postal code. Valid codes
|
A form field that validates input as a Spanish postal code. Valid codes
|
||||||
have five digits, the first two being in the range 01 to 52, representing
|
have five digits, the first two being in the range 01 to 52, representing
|
||||||
the province.
|
the province.
|
||||||
|
|
||||||
@ -571,7 +560,6 @@ ESRegionSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Spanish regions as its choices.
|
A ``Select`` widget that uses a list of Spanish regions as its choices.
|
||||||
|
|
||||||
|
|
||||||
Switzerland (``django.contrib.localflavor.ch``)
|
Switzerland (``django.contrib.localflavor.ch``)
|
||||||
===============================================
|
===============================================
|
||||||
|
|
||||||
@ -585,14 +573,14 @@ have the correct checksums -- see http://adi.kousz.ch/artikel/IDCHE.htm.
|
|||||||
CHPhoneNumberField
|
CHPhoneNumberField
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
A form field that validates input as a Swiss phone number. The correct
|
A form field that validates input as a Swiss phone number. The correct
|
||||||
format is 0XX XXX XX XX. 0XX.XXX.XX.XX and 0XXXXXXXXX validate but are
|
format is 0XX XXX XX XX. 0XX.XXX.XX.XX and 0XXXXXXXXX validate but are
|
||||||
corrected to 0XX XXX XX XX.
|
corrected to 0XX XXX XX XX.
|
||||||
|
|
||||||
CHZipCodeField
|
CHZipCodeField
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
A form field that validates input as a Swiss zip code. Valid codes
|
A form field that validates input as a Swiss zip code. Valid codes
|
||||||
consist of four digits.
|
consist of four digits.
|
||||||
|
|
||||||
CHStateSelect
|
CHStateSelect
|
||||||
@ -600,7 +588,6 @@ CHStateSelect
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Swiss states as its choices.
|
A ``Select`` widget that uses a list of Swiss states as its choices.
|
||||||
|
|
||||||
|
|
||||||
United Kingdom (``django.contrib.localflavor.uk``)
|
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
|
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.
|
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``)
|
United States of America (``django.contrib.localflavor.us``)
|
||||||
============================================================
|
============================================================
|
||||||
@ -626,13 +622,13 @@ USSocialSecurityNumberField
|
|||||||
A form field that validates input as a U.S. Social Security Number (SSN).
|
A form field that validates input as a U.S. Social Security Number (SSN).
|
||||||
A valid SSN must obey the following rules:
|
A valid SSN must obey the following rules:
|
||||||
|
|
||||||
* Format of XXX-XX-XXXX
|
* Format of XXX-XX-XXXX
|
||||||
* No group of digits consisting entirely of zeroes
|
* No group of digits consisting entirely of zeroes
|
||||||
* Leading group of digits cannot be 666
|
* Leading group of digits cannot be 666
|
||||||
* Number not in promotional block 987-65-4320 through 987-65-4329
|
* Number not in promotional block 987-65-4320 through 987-65-4329
|
||||||
* Number not one known to be invalid due to widespread promotional
|
* Number not one known to be invalid due to widespread promotional
|
||||||
use or distribution (e.g., the Woolworth's number or the 1962
|
use or distribution (e.g., the Woolworth's number or the 1962
|
||||||
promotional number)
|
promotional number)
|
||||||
|
|
||||||
USStateField
|
USStateField
|
||||||
------------
|
------------
|
||||||
@ -644,11 +640,11 @@ for the given state.
|
|||||||
USZipCodeField
|
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.
|
XXXXX or XXXXX-XXXX.
|
||||||
|
|
||||||
USStateSelect
|
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.
|
choices.
|
||||||
|
@ -61,17 +61,18 @@ Adds a few conveniences for perfectionists:
|
|||||||
settings.
|
settings.
|
||||||
|
|
||||||
If ``APPEND_SLASH`` is ``True`` and the initial URL doesn't end with a slash,
|
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
|
and it is not found in the URLconf, then a new URL is formed by appending a
|
||||||
at the end. If this new URL is found in urlpatterns, then an HTTP-redirect is
|
slash at the end. If this new URL is found in the URLconf, then Django
|
||||||
returned to this new URL; otherwise the initial URL is processed as usual.
|
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
|
For example, ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if you
|
||||||
have a valid urlpattern for ``foo.com/bar``, and do have a valid urlpattern
|
don't have a valid URL pattern for ``foo.com/bar`` but *do* have a valid
|
||||||
for ``foo.com/bar/``.
|
pattern for ``foo.com/bar/``.
|
||||||
|
|
||||||
**New in Django development version:** The behavior of ``APPEND_SLASH`` has
|
**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
|
changed slightly in the development version. It didn't used to check whether
|
||||||
whether the pattern was matched in the URLconf.
|
the pattern was matched in the URLconf.
|
||||||
|
|
||||||
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
|
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
|
||||||
redirected to the same URL with a leading "www."
|
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
|
.. _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
|
django.middleware.transaction.TransactionMiddleware
|
||||||
---------------------------------------------------
|
---------------------------------------------------
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ model fields:
|
|||||||
any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
|
any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
|
||||||
To avoid this failure, you must instantiate your model with initial values
|
To avoid this failure, you must instantiate your model with initial values
|
||||||
for the missing, but required fields, or use ``save(commit=False)`` and
|
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')
|
instance = Instance(required_field='value')
|
||||||
form = InstanceForm(request.POST, instance=instance)
|
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
|
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
|
want that to be represented as a ``DateField`` in your form. But
|
||||||
``ModelForm`` gives you the flexibility of changing the form field type
|
``ModelForm`` gives you the flexibility of changing the form field type
|
||||||
for a given model field. You do this by declaratively specifying fields like
|
for a given model field. You do this by declaratively specifying fields like
|
||||||
|
@ -156,6 +156,18 @@ Methods
|
|||||||
Returns ``True`` or ``False``, designating whether ``request.GET`` or
|
Returns ``True`` or ``False``, designating whether ``request.GET`` or
|
||||||
``request.POST`` has the given key.
|
``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()``
|
``get_full_path()``
|
||||||
Returns the ``path``, plus an appended query string, if applicable.
|
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``
|
``HttpResponseNotModified``
|
||||||
The constructor doesn't take any arguments. Use this to designate that a
|
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``
|
``HttpResponseBadRequest``
|
||||||
**New in Django development version.**
|
**New in Django development version.**
|
||||||
|
@ -99,7 +99,7 @@ It implements the following standard dictionary methods:
|
|||||||
|
|
||||||
* ``items()``
|
* ``items()``
|
||||||
|
|
||||||
* ``setdefault()``
|
* ``setdefault()`` (**New in Django development version**)
|
||||||
|
|
||||||
It also has these three methods:
|
It also has these three methods:
|
||||||
|
|
||||||
|
@ -981,8 +981,13 @@ TEST_DATABASE_NAME
|
|||||||
|
|
||||||
Default: ``None``
|
Default: ``None``
|
||||||
|
|
||||||
The name of database to use when running the test suite. If a value of
|
The name of database to use when running the test suite.
|
||||||
``None`` is specified, the test database will use the name ``'test_' + settings.DATABASE_NAME``. See `Testing Django Applications`_.
|
|
||||||
|
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/
|
.. _Testing Django Applications: ../testing/
|
||||||
|
|
||||||
|
@ -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
|
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::
|
For example::
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -330,13 +330,13 @@ Here's how Django uses the sites framework:
|
|||||||
retrieving flatpages to display.
|
retrieving flatpages to display.
|
||||||
|
|
||||||
* In the `syndication framework`_, the templates for ``title`` and
|
* 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
|
which is the ``Site`` object representing the current site. Also, the
|
||||||
hook for providing item URLs will use the ``domain`` from the current
|
hook for providing item URLs will use the ``domain`` from the current
|
||||||
``Site`` object if you don't specify a fully-qualified domain.
|
``Site`` object if you don't specify a fully-qualified domain.
|
||||||
|
|
||||||
* In the `authentication framework`_, the ``django.contrib.auth.views.login``
|
* 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 shortcut view (``django.views.defaults.shortcut``) uses the domain of
|
||||||
the current ``Site`` object when calculating an object's URL.
|
the current ``Site`` object when calculating an object's URL.
|
||||||
|
@ -201,7 +201,7 @@ the feed.
|
|||||||
|
|
||||||
An example makes this clear. Here's the code for these beat-specific feeds::
|
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):
|
class BeatFeed(Feed):
|
||||||
def get_object(self, bits):
|
def get_object(self, bits):
|
||||||
|
@ -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()``
|
won't cause an ``AttributeError`` (because integers don't have ``lower()``
|
||||||
methods).
|
methods).
|
||||||
|
|
||||||
Registering a custom filters
|
Registering custom filters
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Once you've written your filter definition, you need to register it with
|
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::
|
your ``Library`` instance, to make it available to Django's template language::
|
||||||
|
@ -270,27 +270,21 @@ a test case, add the name of the test method to the label::
|
|||||||
|
|
||||||
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
|
$ ./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
|
Tests that require a database (namely, model tests) will not use
|
||||||
prepares itself::
|
your "real" (production) database. A separate, blank database is created
|
||||||
|
for the tests.
|
||||||
|
|
||||||
Creating test database...
|
Regardless of whether the tests pass or fail, the test database is destroyed
|
||||||
Creating table myapp_animal
|
when all the tests have been executed.
|
||||||
Creating table myapp_mineral
|
|
||||||
Loading 'initial_data' fixtures...
|
|
||||||
No fixtures found.
|
|
||||||
|
|
||||||
This tells you that the test runner is creating a test database -- a blank,
|
By default this test database gets its name by prepending ``test_`` to the
|
||||||
from-scratch database that it will use for any tests that happen to require a
|
value of the ``DATABASE_NAME`` setting. When using the SQLite database engine
|
||||||
database (namely, model tests).
|
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
|
||||||
Don't worry -- the test runner will not touch your "real" (production)
|
different database name, specify the ``TEST_DATABASE_NAME`` setting.
|
||||||
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.
|
|
||||||
|
|
||||||
Aside from using a separate database, the test runner will otherwise use all of
|
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``,
|
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/
|
.. _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.
|
Once the test database has been created, Django will run your tests.
|
||||||
If everything goes well, you'll see something like this::
|
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
|
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.
|
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
|
Testing tools
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -213,13 +213,13 @@ u'046-454-286'
|
|||||||
>>> f.clean('046-454-287')
|
>>> f.clean('046-454-287')
|
||||||
Traceback (most recent call last):
|
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')
|
>>> f.clean('046 454 286')
|
||||||
Traceback (most recent call last):
|
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')
|
>>> f.clean('046-44-286')
|
||||||
Traceback (most recent call last):
|
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.']
|
||||||
"""
|
"""
|
||||||
|
@ -41,7 +41,7 @@ Strict RUT usage (does not allow imposible values)
|
|||||||
>>> rut.clean('11-6')
|
>>> rut.clean('11-6')
|
||||||
Traceback (most recent call last):
|
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.
|
# valid format, bad verifier.
|
||||||
>>> rut.clean('11.111.111-0')
|
>>> rut.clean('11.111.111-0')
|
||||||
@ -53,17 +53,17 @@ ValidationError: [u'The Chilean RUT is not valid.']
|
|||||||
>>> rut.clean('767484100')
|
>>> rut.clean('767484100')
|
||||||
Traceback (most recent call last):
|
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')
|
>>> rut.clean('78.412.790-7')
|
||||||
u'78.412.790-7'
|
u'78.412.790-7'
|
||||||
>>> rut.clean('8.334.6043')
|
>>> rut.clean('8.334.6043')
|
||||||
Traceback (most recent call last):
|
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')
|
>>> rut.clean('76793310-K')
|
||||||
Traceback (most recent call last):
|
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 #########################################################
|
## CLRegionSelect #########################################################
|
||||||
>>> from django.contrib.localflavor.cl.forms import CLRegionSelect
|
>>> from django.contrib.localflavor.cl.forms import CLRegionSelect
|
||||||
|
@ -12,13 +12,15 @@ u'BT32 4PX'
|
|||||||
>>> f.clean('GIR 0AA')
|
>>> f.clean('GIR 0AA')
|
||||||
u'GIR 0AA'
|
u'GIR 0AA'
|
||||||
>>> f.clean('BT324PX')
|
>>> f.clean('BT324PX')
|
||||||
Traceback (most recent call last):
|
u'BT32 4PX'
|
||||||
...
|
|
||||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
|
||||||
>>> f.clean('1NV 4L1D')
|
>>> f.clean('1NV 4L1D')
|
||||||
Traceback (most recent call last):
|
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)
|
>>> f.clean(None)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -27,7 +29,20 @@ ValidationError: [u'This field is required.']
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'This field is required.']
|
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 = UKPostcodeField(required=False)
|
||||||
>>> f.clean('BT32 4PX')
|
>>> f.clean('BT32 4PX')
|
||||||
u'BT32 4PX'
|
u'BT32 4PX'
|
||||||
@ -36,11 +51,9 @@ u'GIR 0AA'
|
|||||||
>>> f.clean('1NV 4L1D')
|
>>> f.clean('1NV 4L1D')
|
||||||
Traceback (most recent call last):
|
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')
|
>>> f.clean('BT324PX')
|
||||||
Traceback (most recent call last):
|
u'BT32 4PX'
|
||||||
...
|
|
||||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
|
||||||
>>> f.clean(None)
|
>>> f.clean(None)
|
||||||
u''
|
u''
|
||||||
>>> f.clean('')
|
>>> f.clean('')
|
||||||
|
@ -391,9 +391,45 @@ u'\ufffd'
|
|||||||
>>> q.getlist('foo')
|
>>> q.getlist('foo')
|
||||||
[u'bar', u'\ufffd']
|
[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__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
|
@ -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-urlize05': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": "<script>alert('foo')</script>"}, "<script>alert('foo')</script>"),
|
||||||
'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '<script>alert('foo')</script>'),
|
'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '<script>alert('foo')</script>'),
|
||||||
|
|
||||||
'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-urlizetrunc01': ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('"Safe" http://example.com?x=&y=')}, u'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> "Safe" <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-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('"Safe" http://example.com?x=&y=')}, u'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> "Safe" <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 & b")}, "3 3"),
|
'filter-wordcount01': ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a & b")}, "3 3"),
|
||||||
'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a & b")}, "3 3"),
|
'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a & b")}, "3 3"),
|
||||||
|
@ -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-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-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-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-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-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/"),
|
'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
@ -807,6 +809,16 @@ class Templates(unittest.TestCase):
|
|||||||
'{% endfor %},' + \
|
'{% endfor %},' + \
|
||||||
'{% endfor %}',
|
'{% 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 #######################################################
|
### TEMPLATETAG TAG #######################################################
|
||||||
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
||||||
|
1
tests/regressiontests/views/media/file.unknown
Normal file
1
tests/regressiontests/views/media/file.unknown
Normal file
@ -0,0 +1 @@
|
|||||||
|
An unknown file extension.
|
@ -13,11 +13,15 @@ class StaticTests(TestCase):
|
|||||||
response = self.client.get('/views/site_media/%s' % filename)
|
response = self.client.get('/views/site_media/%s' % filename)
|
||||||
file = open(path.join(media_dir, filename))
|
file = open(path.join(media_dir, filename))
|
||||||
self.assertEquals(file.read(), response.content)
|
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):
|
def test_copes_with_empty_path_component(self):
|
||||||
file_name = 'file.txt'
|
file_name = 'file.txt'
|
||||||
response = self.client.get('/views/site_media//%s' % file_name)
|
response = self.client.get('/views/site_media//%s' % file_name)
|
||||||
file = open(path.join(media_dir, file_name))
|
file = open(path.join(media_dir, file_name))
|
||||||
self.assertEquals(file.read(), response.content)
|
self.assertEquals(file.read(), response.content)
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
old_root_urlconf = settings.ROOT_URLCONF
|
old_root_urlconf = settings.ROOT_URLCONF
|
||||||
old_template_dirs = settings.TEMPLATE_DIRS
|
old_template_dirs = settings.TEMPLATE_DIRS
|
||||||
old_use_i18n = settings.USE_I18N
|
old_use_i18n = settings.USE_I18N
|
||||||
|
old_login_url = settings.LOGIN_URL
|
||||||
old_language_code = settings.LANGUAGE_CODE
|
old_language_code = settings.LANGUAGE_CODE
|
||||||
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
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.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
||||||
settings.USE_I18N = True
|
settings.USE_I18N = True
|
||||||
settings.LANGUAGE_CODE = 'en'
|
settings.LANGUAGE_CODE = 'en'
|
||||||
|
settings.LOGIN_URL = '/accounts/login/'
|
||||||
settings.MIDDLEWARE_CLASSES = (
|
settings.MIDDLEWARE_CLASSES = (
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
@ -153,6 +155,7 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
settings.TEMPLATE_DIRS = old_template_dirs
|
settings.TEMPLATE_DIRS = old_template_dirs
|
||||||
settings.USE_I18N = old_use_i18n
|
settings.USE_I18N = old_use_i18n
|
||||||
settings.LANGUAGE_CODE = old_language_code
|
settings.LANGUAGE_CODE = old_language_code
|
||||||
|
settings.LOGIN_URL = old_login_url
|
||||||
settings.MIDDLEWARE_CLASSES = old_middleware_classes
|
settings.MIDDLEWARE_CLASSES = old_middleware_classes
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user