summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-12-19 05:08:37 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-12-19 05:08:37 +0000
commit97091940b1efbc6018133e9f77402c2983fa702f (patch)
treee003a3ec00ab4b0bd0cda7799485cedbf787cd31 /django
parent13d3162aaf7fce11c06d447f397e32b7648ae199 (diff)
queryset-refactor: Merged from trunk up to [6953].
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6954 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/conf/__init__.py4
-rw-r--r--django/conf/locale/ca/LC_MESSAGES/django.mobin61655 -> 62260 bytes
-rw-r--r--django/conf/locale/ca/LC_MESSAGES/django.po392
-rw-r--r--django/conf/locale/nl/LC_MESSAGES/django.mobin38003 -> 38049 bytes
-rw-r--r--django/conf/locale/nl/LC_MESSAGES/django.po73
-rw-r--r--django/contrib/admin/media/js/urlify.js7
-rw-r--r--django/contrib/admin/templatetags/admin_list.py2
-rw-r--r--django/contrib/auth/models.py2
-rw-r--r--django/contrib/auth/tests.py12
-rw-r--r--django/contrib/contenttypes/generic.py42
-rw-r--r--django/contrib/databrowse/datastructures.py5
-rw-r--r--django/contrib/localflavor/ar/forms.py28
-rw-r--r--django/contrib/localflavor/au/forms.py14
-rw-r--r--django/contrib/localflavor/br/forms.py47
-rw-r--r--django/contrib/localflavor/ca/forms.py100
-rw-r--r--django/contrib/localflavor/ch/forms.py25
-rw-r--r--django/contrib/localflavor/cl/forms.py13
-rw-r--r--django/contrib/localflavor/de/forms.py18
-rw-r--r--django/contrib/localflavor/es/forms.py49
-rw-r--r--django/contrib/localflavor/fi/forms.py15
-rw-r--r--django/contrib/localflavor/fr/forms.py14
-rw-r--r--django/contrib/localflavor/in_/forms.py14
-rw-r--r--django/contrib/localflavor/is_/forms.py10
-rw-r--r--django/contrib/localflavor/it/forms.py28
-rw-r--r--django/contrib/localflavor/jp/forms.py8
-rw-r--r--django/contrib/localflavor/nl/forms.py56
-rw-r--r--django/contrib/localflavor/no/forms.py21
-rw-r--r--django/contrib/localflavor/pe/forms.py18
-rw-r--r--django/contrib/localflavor/pl/forms.py37
-rw-r--r--django/contrib/localflavor/sk/forms.py8
-rw-r--r--django/contrib/localflavor/uk/forms.py32
-rw-r--r--django/contrib/localflavor/us/forms.py31
-rw-r--r--django/contrib/localflavor/za/forms.py22
-rw-r--r--django/contrib/sessions/backends/file.py13
-rw-r--r--django/contrib/sessions/tests.py8
-rw-r--r--django/core/cache/backends/filebased.py110
-rw-r--r--django/core/cache/backends/locmem.py59
-rw-r--r--django/core/mail.py10
-rw-r--r--django/core/management/__init__.py78
-rw-r--r--django/core/management/base.py2
-rw-r--r--django/core/management/commands/dumpdata.py12
-rw-r--r--django/core/management/commands/loaddata.py17
-rw-r--r--django/core/management/sql.py3
-rw-r--r--django/core/serializers/__init__.py5
-rw-r--r--django/core/serializers/base.py4
-rw-r--r--django/core/serializers/json.py2
-rw-r--r--django/core/serializers/python.py4
-rw-r--r--django/core/serializers/pyyaml.py18
-rw-r--r--django/core/servers/basehttp.py16
-rw-r--r--django/db/__init__.py4
-rw-r--r--django/db/backends/oracle/base.py19
-rw-r--r--django/db/models/fields/__init__.py13
-rw-r--r--django/http/__init__.py15
-rw-r--r--django/newforms/fields.py4
-rw-r--r--django/newforms/models.py47
-rw-r--r--django/template/defaultfilters.py32
-rw-r--r--django/template/defaulttags.py2
-rw-r--r--django/test/utils.py44
-rw-r--r--django/utils/html.py22
-rw-r--r--django/utils/maxlength.py18
-rw-r--r--django/views/debug.py44
-rw-r--r--django/views/static.py3
62 files changed, 1088 insertions, 687 deletions
diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index c24e87e6ed..61d9ff7536 100644
--- a/django/conf/__init__.py
+++ b/django/conf/__init__.py
@@ -52,7 +52,9 @@ class LazySettings(object):
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
- raise ImportError, "Environment variable %s is undefined so settings cannot be imported." % ENVIRONMENT_VARIABLE # NOTE: This is arguably an EnvironmentError, but that causes problems with Python's interactive help
+ # NOTE: This is arguably an EnvironmentError, but that causes
+ # problems with Python's interactive help.
+ raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
self._target = Settings(settings_module)
diff --git a/django/conf/locale/ca/LC_MESSAGES/django.mo b/django/conf/locale/ca/LC_MESSAGES/django.mo
index fdba04abd2..a39a4551bb 100644
--- a/django/conf/locale/ca/LC_MESSAGES/django.mo
+++ b/django/conf/locale/ca/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/ca/LC_MESSAGES/django.po b/django/conf/locale/ca/LC_MESSAGES/django.po
index 9f561acc5b..2929ea114e 100644
--- a/django/conf/locale/ca/LC_MESSAGES/django.po
+++ b/django/conf/locale/ca/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-11-05 17:33+0100\n"
-"PO-Revision-Date: 2007-11-05 17:34+0100\n"
-"Last-Translator: Marc Garcia <marc.garcia@accopensys.com>\n"
+"POT-Creation-Date: 2007-12-02 22:26+0100\n"
+"PO-Revision-Date: 2007-12-02 22:32+0100\n"
+"Last-Translator: Marc Fargas <telenieko@telenieko.com>\n"
"Language-Team: <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -194,7 +194,7 @@ msgstr "Xinés simplificat"
msgid "Traditional Chinese"
msgstr "Xinés tradicional"
-#: contrib/admin/filterspecs.py:42
+#: contrib/admin/filterspecs.py:44
#, python-format
msgid ""
"<h3>By %s:</h3>\n"
@@ -203,71 +203,71 @@ msgstr ""
"<h3>Per %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90
-#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171
+#: contrib/admin/filterspecs.py:74 contrib/admin/filterspecs.py:92
+#: contrib/admin/filterspecs.py:147 contrib/admin/filterspecs.py:173
msgid "All"
msgstr "Tots"
-#: contrib/admin/filterspecs.py:111
+#: contrib/admin/filterspecs.py:113
msgid "Any date"
msgstr "Qualsevol data"
-#: contrib/admin/filterspecs.py:112
+#: contrib/admin/filterspecs.py:114
msgid "Today"
msgstr "Avui"
-#: contrib/admin/filterspecs.py:115
+#: contrib/admin/filterspecs.py:117
msgid "Past 7 days"
msgstr "Últims 7 dies"
-#: contrib/admin/filterspecs.py:117
+#: contrib/admin/filterspecs.py:119
msgid "This month"
msgstr "Aquest mes"
-#: contrib/admin/filterspecs.py:119
+#: contrib/admin/filterspecs.py:121
msgid "This year"
msgstr "Aquest any"
-#: contrib/admin/filterspecs.py:145 newforms/widgets.py:221
-#: oldforms/__init__.py:591
+#: contrib/admin/filterspecs.py:147 newforms/widgets.py:231
+#: oldforms/__init__.py:592
msgid "Yes"
msgstr "Si"
-#: contrib/admin/filterspecs.py:145 newforms/widgets.py:221
-#: oldforms/__init__.py:591
+#: contrib/admin/filterspecs.py:147 newforms/widgets.py:231
+#: oldforms/__init__.py:592
msgid "No"
msgstr "No"
-#: contrib/admin/filterspecs.py:152 newforms/widgets.py:221
-#: oldforms/__init__.py:591
+#: contrib/admin/filterspecs.py:154 newforms/widgets.py:231
+#: oldforms/__init__.py:592
msgid "Unknown"
msgstr "Desconegut"
-#: contrib/admin/models.py:17
+#: contrib/admin/models.py:18
msgid "action time"
msgstr "moment de l'acció"
-#: contrib/admin/models.py:20
+#: contrib/admin/models.py:21
msgid "object id"
msgstr "id del objecte"
-#: contrib/admin/models.py:21
+#: contrib/admin/models.py:22
msgid "object repr"
msgstr "'repr' de l'objecte"
-#: contrib/admin/models.py:22
+#: contrib/admin/models.py:23
msgid "action flag"
msgstr "marca de l'acció"
-#: contrib/admin/models.py:23
+#: contrib/admin/models.py:24
msgid "change message"
msgstr "missatge del canvi"
-#: contrib/admin/models.py:26
+#: contrib/admin/models.py:27
msgid "log entry"
msgstr "entrada del registre"
-#: contrib/admin/models.py:27
+#: contrib/admin/models.py:28
msgid "log entries"
msgstr "entrades del registre"
@@ -469,7 +469,7 @@ msgid "Password:"
msgstr "Contrasenya:"
#: contrib/admin/templates/admin/login.html:25
-#: contrib/admin/views/decorators.py:24
+#: contrib/admin/views/decorators.py:25
msgid "Log in"
msgstr "Iniciar sessió"
@@ -769,17 +769,17 @@ msgstr "Actualment:"
msgid "Change:"
msgstr "Modificar:"
-#: contrib/admin/templatetags/admin_list.py:254
+#: contrib/admin/templatetags/admin_list.py:257
msgid "All dates"
msgstr "Totes les dates"
-#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:267
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "El/la %(name)s \"%(obj)s\".ha estat agregat/da amb èxit."
-#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268
-#: contrib/admin/views/main.py:354
+#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:271
+#: contrib/admin/views/main.py:356
msgid "You may edit it again below."
msgstr "Pot editar-lo de nou abaix."
@@ -796,7 +796,7 @@ msgstr "Canvi de clau exitós"
msgid "Change password: %s"
msgstr "Canviar clau: %s"
-#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
+#: contrib/admin/views/decorators.py:11 contrib/auth/forms.py:60
msgid ""
"Please enter a correct username and password. Note that both fields are case-"
"sensitive."
@@ -804,7 +804,7 @@ msgstr ""
"Si us plau, introdueixi un nom d'usuari i contrasenya vàlids. Tingui en "
"compte que tots dos camps son sensibles a majúscules i minúscules."
-#: contrib/admin/views/decorators.py:62
+#: contrib/admin/views/decorators.py:63
msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
@@ -812,7 +812,7 @@ msgstr ""
"Si us plau, identifiquis de nou doncs la seva sessió ha expirat. No es "
"preocupi, el seu enviament està emmagatzemat."
-#: contrib/admin/views/decorators.py:69
+#: contrib/admin/views/decorators.py:70
msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
@@ -821,247 +821,247 @@ msgstr ""
"'cookies' (galetes). Si us plau, habiliti les 'cookies', recarregui aquesta "
"pàgina i provi-ho de nou. "
-#: contrib/admin/views/decorators.py:83
+#: contrib/admin/views/decorators.py:84
msgid "Usernames cannot contain the '@' character."
msgstr "Els noms d'usuari no poden contenir el caracter '@'."
-#: contrib/admin/views/decorators.py:85
+#: contrib/admin/views/decorators.py:86
#, python-format
msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr ""
"La seva adreça de correu no és el seu nom d'usuari. Provi '%s' en tot cas."
-#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49
-#: contrib/admin/views/doc.py:51
+#: contrib/admin/views/doc.py:48 contrib/admin/views/doc.py:50
+#: contrib/admin/views/doc.py:52
msgid "tag:"
msgstr "etiqueta:"
-#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80
-#: contrib/admin/views/doc.py:82
+#: contrib/admin/views/doc.py:79 contrib/admin/views/doc.py:81
+#: contrib/admin/views/doc.py:83
msgid "filter:"
msgstr "filtre:"
-#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138
-#: contrib/admin/views/doc.py:140
+#: contrib/admin/views/doc.py:137 contrib/admin/views/doc.py:139
+#: contrib/admin/views/doc.py:141
msgid "view:"
msgstr "vista:"
-#: contrib/admin/views/doc.py:165
+#: contrib/admin/views/doc.py:166
#, python-format
msgid "App %r not found"
msgstr "La aplicació %r no s'ha pogut trobar"
-#: contrib/admin/views/doc.py:172
+#: contrib/admin/views/doc.py:173
#, python-format
msgid "Model %(name)r not found in app %(label)r"
msgstr "El model %(name)r no s'ha trobat en la aplicació %(label)r"
-#: contrib/admin/views/doc.py:184
+#: contrib/admin/views/doc.py:185
#, python-format
msgid "the related `%(label)s.%(type)s` object"
msgstr "el objecte relacionat `%(label)s.%(type)s`"
-#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206
-#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225
+#: contrib/admin/views/doc.py:185 contrib/admin/views/doc.py:207
+#: contrib/admin/views/doc.py:221 contrib/admin/views/doc.py:226
msgid "model:"
msgstr "model:"
-#: contrib/admin/views/doc.py:215
+#: contrib/admin/views/doc.py:216
#, python-format
msgid "related `%(label)s.%(name)s` objects"
msgstr "objectes relacionats `%(label)s.%(name)s`"
-#: contrib/admin/views/doc.py:220
+#: contrib/admin/views/doc.py:221
#, python-format
msgid "all %s"
msgstr "tots %s"
-#: contrib/admin/views/doc.py:225
+#: contrib/admin/views/doc.py:226
#, python-format
msgid "number of %s"
msgstr "nombre de %s"
-#: contrib/admin/views/doc.py:230
+#: contrib/admin/views/doc.py:231
#, python-format
msgid "Fields on %s objects"
msgstr "Camps en objectes %s"
-#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303
-#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311
-#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314
+#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:304
+#: contrib/admin/views/doc.py:306 contrib/admin/views/doc.py:312
+#: contrib/admin/views/doc.py:313 contrib/admin/views/doc.py:315
msgid "Integer"
msgstr "Enter"
-#: contrib/admin/views/doc.py:293
+#: contrib/admin/views/doc.py:294
msgid "Boolean (Either True or False)"
msgstr "Booleà (Verdader o Fals)"
-#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313
+#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:314
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "Cadena (de fins a %(max_length)s)"
-#: contrib/admin/views/doc.py:295
+#: contrib/admin/views/doc.py:296
msgid "Comma-separated integers"
msgstr "Enters separats per comes"
-#: contrib/admin/views/doc.py:296
+#: contrib/admin/views/doc.py:297
msgid "Date (without time)"
msgstr "Data (sense hora)"
-#: contrib/admin/views/doc.py:297
+#: contrib/admin/views/doc.py:298
msgid "Date (with time)"
msgstr "Data (amb hora)"
-#: contrib/admin/views/doc.py:298
+#: contrib/admin/views/doc.py:299
msgid "Decimal number"
msgstr "Número decimal"
-#: contrib/admin/views/doc.py:299
+#: contrib/admin/views/doc.py:300
msgid "E-mail address"
msgstr "Adreça de correu electrònic"
-#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301
-#: contrib/admin/views/doc.py:304
+#: contrib/admin/views/doc.py:301 contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:305
msgid "File path"
msgstr "Ruta del fitxer"
-#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:303
msgid "Floating point number"
msgstr "Número amb punt de coma flotant"
-#: contrib/admin/views/doc.py:306 contrib/comments/models.py:85
+#: contrib/admin/views/doc.py:307 contrib/comments/models.py:85
msgid "IP address"
msgstr "Adreça IP"
-#: contrib/admin/views/doc.py:308
+#: contrib/admin/views/doc.py:309
msgid "Boolean (Either True, False or None)"
msgstr "Booleà (Verdader, Fals o 'None' (cap))"
-#: contrib/admin/views/doc.py:309
+#: contrib/admin/views/doc.py:310
msgid "Relation to parent model"
msgstr "Relació amb el model pare"
-#: contrib/admin/views/doc.py:310
+#: contrib/admin/views/doc.py:311
msgid "Phone number"
msgstr "Número de telèfon"
-#: contrib/admin/views/doc.py:315
+#: contrib/admin/views/doc.py:316
msgid "Text"
msgstr "Texte"
-#: contrib/admin/views/doc.py:316
+#: contrib/admin/views/doc.py:317
msgid "Time"
msgstr "Hora"
-#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:318 contrib/flatpages/models.py:7
msgid "URL"
msgstr "URL"
-#: contrib/admin/views/doc.py:318
+#: contrib/admin/views/doc.py:319
msgid "U.S. state (two uppercase letters)"
msgstr "Estat dels E.U.A. (dos lletres majúscules)"
-#: contrib/admin/views/doc.py:319
+#: contrib/admin/views/doc.py:320
msgid "XML text"
msgstr "Texte XML"
-#: contrib/admin/views/doc.py:345
+#: contrib/admin/views/doc.py:346
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s no sembla ser un objecte 'urlpattern'"
-#: contrib/admin/views/main.py:230
+#: contrib/admin/views/main.py:233
msgid "Site administration"
msgstr "Lloc administratiu"
-#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363
+#: contrib/admin/views/main.py:280 contrib/admin/views/main.py:365
#, python-format
msgid "You may add another %s below."
msgstr "Pot afegir un altre %s a baix."
-#: contrib/admin/views/main.py:296
+#: contrib/admin/views/main.py:298
#, python-format
msgid "Add %s"
msgstr "Afegir %s"
-#: contrib/admin/views/main.py:342
+#: contrib/admin/views/main.py:344
#, python-format
msgid "Added %s."
msgstr "Agregat %s."
-#: contrib/admin/views/main.py:342 contrib/admin/views/main.py:344
-#: contrib/admin/views/main.py:346 core/validators.py:283
+#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+#: contrib/admin/views/main.py:348 core/validators.py:283
#: db/models/manipulators.py:309
msgid "and"
msgstr "i"
-#: contrib/admin/views/main.py:344
+#: contrib/admin/views/main.py:346
#, python-format
msgid "Changed %s."
msgstr "Modificat %s."
-#: contrib/admin/views/main.py:346
+#: contrib/admin/views/main.py:348
#, python-format
msgid "Deleted %s."
msgstr "Eliminat %s."
-#: contrib/admin/views/main.py:349
+#: contrib/admin/views/main.py:351
msgid "No fields changed."
msgstr "Cap camp canviat."
-#: contrib/admin/views/main.py:352
+#: contrib/admin/views/main.py:354
#, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "S'ha modificat amb èxist el/la %(name)s \"%(obj)s."
-#: contrib/admin/views/main.py:360
+#: contrib/admin/views/main.py:362
#, python-format
msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr ""
"S'ha agregat amb èxit el/la %(name)s \"%(obj)s\". Pot editar-lo de nou abaix."
-#: contrib/admin/views/main.py:398
+#: contrib/admin/views/main.py:400
#, python-format
msgid "Change %s"
msgstr "Modificar %s"
-#: contrib/admin/views/main.py:483
+#: contrib/admin/views/main.py:487
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "Un o més %(fieldname)s en %(name)s: %(obj)s"
-#: contrib/admin/views/main.py:488
+#: contrib/admin/views/main.py:492
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
msgstr "Un o més %(fieldname)s en %(name)s:"
-#: contrib/admin/views/main.py:520
+#: contrib/admin/views/main.py:524
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "El/la %(name)s \"%(obj)s\".ha estat eliminat amb èxit."
-#: contrib/admin/views/main.py:523
+#: contrib/admin/views/main.py:527
msgid "Are you sure?"
msgstr "Està segur?"
-#: contrib/admin/views/main.py:545
+#: contrib/admin/views/main.py:549
#, python-format
msgid "Change history: %s"
msgstr "Modificar històric: %s"
-#: contrib/admin/views/main.py:579
+#: contrib/admin/views/main.py:583
#, python-format
msgid "Select %s"
msgstr "Seleccioni %s"
-#: contrib/admin/views/main.py:579
+#: contrib/admin/views/main.py:583
#, python-format
msgid "Select %s to change"
msgstr "Seleccioni %s per modificar"
-#: contrib/admin/views/main.py:780
+#: contrib/admin/views/main.py:784
msgid "Database error"
msgstr "Error de/en la base de dades"
@@ -1622,72 +1622,72 @@ msgstr "n"
msgid "rd"
msgstr "r"
-#: contrib/humanize/templatetags/humanize.py:50
+#: contrib/humanize/templatetags/humanize.py:52
#, python-format
msgid "%(value).1f million"
msgid_plural "%(value).1f million"
msgstr[0] "%(value).1f milió"
msgstr[1] "%(value).1f milions"
-#: contrib/humanize/templatetags/humanize.py:53
+#: contrib/humanize/templatetags/humanize.py:55
#, python-format
msgid "%(value).1f billion"
msgid_plural "%(value).1f billion"
msgstr[0] "%(value).1f bilió"
msgstr[1] "%(value).1f bilions"
-#: contrib/humanize/templatetags/humanize.py:56
+#: contrib/humanize/templatetags/humanize.py:58
#, python-format
msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion"
msgstr[0] "%(value).1f trilió"
msgstr[1] "%(value).1f trilions"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "one"
msgstr "un"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "two"
msgstr "dos"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "three"
msgstr "tres"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "four"
msgstr "cuatre"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "five"
msgstr "cinc"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "six"
msgstr "sis"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "seven"
msgstr "set"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "eight"
msgstr "vuit"
-#: contrib/humanize/templatetags/humanize.py:71
+#: contrib/humanize/templatetags/humanize.py:74
msgid "nine"
msgstr "nou"
-#: contrib/humanize/templatetags/humanize.py:90
+#: contrib/humanize/templatetags/humanize.py:94
msgid "today"
msgstr "avui"
-#: contrib/humanize/templatetags/humanize.py:92
+#: contrib/humanize/templatetags/humanize.py:96
msgid "tomorrow"
msgstr "demà"
-#: contrib/humanize/templatetags/humanize.py:94
+#: contrib/humanize/templatetags/humanize.py:98
msgid "yesterday"
msgstr "ahir"
@@ -3024,6 +3024,50 @@ msgstr ""
"Introdueixi un número vàlid de la Seguretat Social dels E.U.A. en el format "
"XXX-XX-XXXX."
+#: contrib/localflavor/za/forms.py:22
+msgid "Enter a valid South African ID number"
+msgstr "Introdueixi un número d'Identitat Sud Africà valid"
+
+#: contrib/localflavor/za/forms.py:57
+msgid "Enter a valid South African postal code"
+msgstr "Introdueixi un codi postal Sud Africà vàlid."
+
+#: contrib/localflavor/za/za_provinces.py:4
+msgid "Eastern Cape"
+msgstr "Eastern Cape"
+
+#: contrib/localflavor/za/za_provinces.py:5
+msgid "Free State"
+msgstr "Free State"
+
+#: contrib/localflavor/za/za_provinces.py:6
+msgid "Gauteng"
+msgstr "Gauteng"
+
+#: contrib/localflavor/za/za_provinces.py:7
+msgid "KwaZulu-Natal"
+msgstr "KwaZulu-Natal"
+
+#: contrib/localflavor/za/za_provinces.py:8
+msgid "Limpopo"
+msgstr "Limpopo"
+
+#: contrib/localflavor/za/za_provinces.py:9
+msgid "Mpumalanga"
+msgstr "Mpumalanga"
+
+#: contrib/localflavor/za/za_provinces.py:10
+msgid "Northern Cape"
+msgstr "Northern Cape"
+
+#: contrib/localflavor/za/za_provinces.py:11
+msgid "North West"
+msgstr "North West"
+
+#: contrib/localflavor/za/za_provinces.py:12
+msgid "Western Cape"
+msgstr "Western Cape"
+
#: contrib/redirects/models.py:7
msgid "redirect from"
msgstr "redreçar des de"
@@ -3056,23 +3100,23 @@ msgstr "redreçament"
msgid "redirects"
msgstr "redreçaments"
-#: contrib/sessions/models.py:80
+#: contrib/sessions/models.py:46
msgid "session key"
msgstr "clau de la sessió"
-#: contrib/sessions/models.py:81
+#: contrib/sessions/models.py:47
msgid "session data"
msgstr "dades de la sessió"
-#: contrib/sessions/models.py:82
+#: contrib/sessions/models.py:48
msgid "expire date"
msgstr "data de caducitat"
-#: contrib/sessions/models.py:87
+#: contrib/sessions/models.py:53
msgid "session"
msgstr "sessió"
-#: contrib/sessions/models.py:88
+#: contrib/sessions/models.py:54
msgid "sessions"
msgstr "sessions"
@@ -3141,7 +3185,7 @@ msgstr "No s'admeten caracters no numèrics."
msgid "This value can't be comprised solely of digits."
msgstr "Aquest valor no pot contenir només dígits."
-#: core/validators.py:128 newforms/fields.py:157
+#: core/validators.py:128 newforms/fields.py:151
msgid "Enter a whole number."
msgstr "Introdueixi un número sencer."
@@ -3170,17 +3214,17 @@ msgstr "Introdueixi una hora vàlida en el format HH:MM."
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Introdueixi un data/hora vàlida en format YYYY-MM-DD HH:MM."
-#: core/validators.py:170 newforms/fields.py:408
+#: core/validators.py:170 newforms/fields.py:402
msgid "Enter a valid e-mail address."
msgstr "Introdueixi una adreça de correu vàlida."
-#: core/validators.py:182 core/validators.py:474 newforms/fields.py:438
-#: oldforms/__init__.py:686
+#: core/validators.py:182 core/validators.py:474 newforms/fields.py:432
+#: oldforms/__init__.py:687
msgid "No file was submitted. Check the encoding type on the form."
msgstr ""
"No s'ha enviat cap fitxer. Comprovi el tipus de codificació del formulari."
-#: core/validators.py:193 newforms/fields.py:462
+#: core/validators.py:193 newforms/fields.py:456
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
@@ -3431,7 +3475,7 @@ msgstr "Ja existeix %(optname)s amb auqest %(fieldname)s."
#: db/models/fields/__init__.py:161 db/models/fields/__init__.py:318
#: db/models/fields/__init__.py:735 db/models/fields/__init__.py:746
-#: newforms/fields.py:45 newforms/models.py:211 oldforms/__init__.py:373
+#: newforms/fields.py:45 oldforms/__init__.py:374
msgid "This field is required."
msgstr "Aquest camp és obligatori."
@@ -3484,150 +3528,150 @@ msgstr[1] ""
msgid "Enter a valid value."
msgstr "Introdueixi un valor vàlid."
-#: newforms/fields.py:129
+#: newforms/fields.py:123
#, python-format
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
msgstr ""
"Asseguris de que el valor té com a màxim %(max)d caràcters (en té %(length)"
"d)."
-#: newforms/fields.py:130
+#: newforms/fields.py:124
#, python-format
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
msgstr ""
"Asseguris de que el valor té com a mínim %(min)d caràcters (en té %(length)"
"d)."
-#: newforms/fields.py:158 newforms/fields.py:187 newforms/fields.py:216
+#: newforms/fields.py:152 newforms/fields.py:181 newforms/fields.py:210
#, python-format
msgid "Ensure this value is less than or equal to %s."
msgstr "Aquest valor ha de ser menor o igual a %s."
-#: newforms/fields.py:159 newforms/fields.py:188 newforms/fields.py:217
+#: newforms/fields.py:153 newforms/fields.py:182 newforms/fields.py:211
#, python-format
msgid "Ensure this value is greater than or equal to %s."
msgstr "Asseguris de que aquest valor sigui superior o igual a %s."
-#: newforms/fields.py:186 newforms/fields.py:215
+#: newforms/fields.py:180 newforms/fields.py:209
msgid "Enter a number."
msgstr "Introdueixi un número."
-#: newforms/fields.py:218
+#: newforms/fields.py:212
#, python-format
msgid "Ensure that there are no more than %s digits in total."
msgstr "Asseguris de que no hi ha més de %s dígits en total."
-#: newforms/fields.py:219
+#: newforms/fields.py:213
#, python-format
msgid "Ensure that there are no more than %s decimal places."
msgstr "Asseguris de que no hi ha més de %s decimals."
-#: newforms/fields.py:220
+#: newforms/fields.py:214
#, python-format
msgid "Ensure that there are no more than %s digits before the decimal point."
msgstr "Asseguris de que no hia ha més de %s dígits decimals."
-#: newforms/fields.py:268 newforms/fields.py:724
+#: newforms/fields.py:262 newforms/fields.py:719
msgid "Enter a valid date."
msgstr "Introdueixi una data vàlida."
-#: newforms/fields.py:301 newforms/fields.py:725
+#: newforms/fields.py:295 newforms/fields.py:720
msgid "Enter a valid time."
msgstr "Introdueixi una hora vàlida."
-#: newforms/fields.py:340
+#: newforms/fields.py:334
msgid "Enter a valid date/time."
msgstr "Introdueixi una data/hora vàlides."
-#: newforms/fields.py:439
+#: newforms/fields.py:433
msgid "No file was submitted."
msgstr "No s'ha enviat cap fitxer."
-#: newforms/fields.py:440 oldforms/__init__.py:688
+#: newforms/fields.py:434 oldforms/__init__.py:689
msgid "The submitted file is empty."
msgstr "El fitxer enviat està buit."
-#: newforms/fields.py:498
+#: newforms/fields.py:492
msgid "Enter a valid URL."
msgstr "Introdueixi una URL vàlida."
-#: newforms/fields.py:499
+#: newforms/fields.py:493
msgid "This URL appears to be a broken link."
msgstr "Aquesta URL sembla ser un enllaç trencat."
-#: newforms/fields.py:560 newforms/models.py:194
+#: newforms/fields.py:555 newforms/models.py:155
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr ""
"Esculli una opció vàlida; Aquesta opció no és una de les opcions disponibles."
-#: newforms/fields.py:599
+#: newforms/fields.py:594
#, python-format
msgid "Select a valid choice. %(value)s is not one of the available choices."
msgstr "Esculli una opció vàlida. %(value)s no és una de les opcions vàlides."
-#: newforms/fields.py:600 newforms/fields.py:662 newforms/models.py:215
+#: newforms/fields.py:595 newforms/fields.py:657 newforms/models.py:215
msgid "Enter a list of values."
msgstr "Introdueixi una llista de valors."
-#: newforms/fields.py:753
+#: newforms/fields.py:748
msgid "Enter a valid IPv4 address."
msgstr "Introdueixi una adreça IPv4 vàlida."
-#: newforms/models.py:221
+#: newforms/models.py:216
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
msgstr "Esculli una opció vàlida; %s' no és una de les opcions vàlides."
-#: oldforms/__init__.py:408
+#: oldforms/__init__.py:409
#, python-format
msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Asseguris de que el seu texte té menys de %s caracter."
msgstr[1] "Asseguris de que el seu texte té menys de %s caracters."
-#: oldforms/__init__.py:413
+#: oldforms/__init__.py:414
msgid "Line breaks are not allowed here."
msgstr "No es permeten salts de línia."
-#: oldforms/__init__.py:511 oldforms/__init__.py:585 oldforms/__init__.py:624
+#: oldforms/__init__.py:512 oldforms/__init__.py:586 oldforms/__init__.py:625
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Esculli una opció vàlida; %(data)s' no està dintre de %(choices)s."
-#: oldforms/__init__.py:744
+#: oldforms/__init__.py:745
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Introdueixi un número enter entre -32,768 i 32,767."
-#: oldforms/__init__.py:754
+#: oldforms/__init__.py:755
msgid "Enter a positive number."
msgstr "Introdueixi un número positiu."
-#: oldforms/__init__.py:764
+#: oldforms/__init__.py:765
msgid "Enter a whole number between 0 and 32,767."
msgstr "Introdueixi un número entre 0 i 32,767."
-#: template/defaultfilters.py:555
+#: template/defaultfilters.py:658
msgid "yes,no,maybe"
msgstr "si,no,potser"
-#: template/defaultfilters.py:585
+#: template/defaultfilters.py:689
#, python-format
msgid "%(size)d byte"
msgid_plural "%(size)d bytes"
msgstr[0] "%(size)d byte"
msgstr[1] "%(size)d bytes"
-#: template/defaultfilters.py:587
+#: template/defaultfilters.py:691
#, python-format
msgid "%.1f KB"
msgstr "%.1f KB"
-#: template/defaultfilters.py:589
+#: template/defaultfilters.py:693
#, python-format
msgid "%.1f MB"
msgstr "%.1f MB"
-#: template/defaultfilters.py:590
+#: template/defaultfilters.py:694
#, python-format
msgid "%.1f GB"
msgstr "%.1f GB"
@@ -3890,23 +3934,23 @@ msgstr "%(number)d %(type)s"
msgid ", %(number)d %(type)s"
msgstr ", %(number)d %(type)s"
-#: utils/translation/trans_real.py:395
+#: utils/translation/trans_real.py:399
msgid "DATE_FORMAT"
msgstr "F j, Y"
-#: utils/translation/trans_real.py:396
+#: utils/translation/trans_real.py:400
msgid "DATETIME_FORMAT"
msgstr "F j, Y, H:i"
-#: utils/translation/trans_real.py:397
+#: utils/translation/trans_real.py:401
msgid "TIME_FORMAT"
msgstr "H:i"
-#: utils/translation/trans_real.py:413
+#: utils/translation/trans_real.py:417
msgid "YEAR_MONTH_FORMAT"
msgstr "j de/d' F del Y"
-#: utils/translation/trans_real.py:414
+#: utils/translation/trans_real.py:418
msgid "MONTH_DAY_FORMAT"
msgstr "j de/d' F del Y"
@@ -3924,43 +3968,3 @@ msgstr "El/La %(verbose_name)s s'ha actualtzat amb èxit."
#, python-format
msgid "The %(verbose_name)s was deleted."
msgstr "El %(verbose_name)s s'ha eliminat."
-
-#~ msgid ""
-#~ "This comment was posted by a user who has posted fewer than %(count)s "
-#~ "comment:\n"
-#~ "\n"
-#~ "%(text)sThis comment was posted by a user who has posted fewer than %"
-#~ "(count)s comments:\n"
-#~ "\n"
-#~ "%(text)s"
-#~ msgstr ""
-#~ "Aquest comentari el va enviar un usuari que ha enviat menys de %(count)s "
-#~ "comentari:\n"
-#~ "\n"
-#~ "%(text)sAquest comentari el va enviar un usuari que ha enviat menys de %"
-#~ "(count)s comentaris:\n"
-#~ "\n"
-#~ "%(text)s"
-
-#~ msgid "AnonymousUser"
-#~ msgstr "AnonymousUser"
-
-#~ msgid ""
-#~ "Please enter a valid decimal number with a whole part of at most %s digit."
-#~ "Please enter a valid decimal number with a whole part of at most %s "
-#~ "digits."
-#~ msgstr ""
-#~ "Si us plau, introdueixi un número decimal vàlid amb la part entera amb "
-#~ "com a màxim %s dígit.Si us plau, introdueixi un número decimal vàlid amb "
-#~ "la part entera amb com a màxim %s dígits."
-
-#~ msgid ""
-#~ "Please enter a valid decimal number with at most %s decimal place.Please "
-#~ "enter a valid decimal number with at most %s decimal places."
-#~ msgstr ""
-#~ "Si us plau, introdueixi un número decimal vàlid amb no més de %s dígit en "
-#~ "la part decimal.Si us plau, introdueixi un número decimal vàlid amb no "
-#~ "més de %s dígits en la part decimal."
-
-#~ msgid "%d milliseconds"
-#~ msgstr "%d milisegons"
diff --git a/django/conf/locale/nl/LC_MESSAGES/django.mo b/django/conf/locale/nl/LC_MESSAGES/django.mo
index 4c70c28ff4..b49be6a3e3 100644
--- a/django/conf/locale/nl/LC_MESSAGES/django.mo
+++ b/django/conf/locale/nl/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/nl/LC_MESSAGES/django.po b/django/conf/locale/nl/LC_MESSAGES/django.po
index 9aaeef8af9..b8c516b72d 100644
--- a/django/conf/locale/nl/LC_MESSAGES/django.po
+++ b/django/conf/locale/nl/LC_MESSAGES/django.po
@@ -1,17 +1,12 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the django package.
-# Johan C. Stöver <johan@nilling.nl>, 2005.
-# Rudolph Froger <rfroger@estrate.nl>, 2006.
-#
+
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-12-09 15:51+0100\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Johan C. Stöver <johan@nilling.nl>\n"
+"PO-Revision-Date: 2007-12-17 21:14+0100\n"
+"Last-Translator: I.S. van Oostveen\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
@@ -69,7 +64,7 @@ msgstr "De waarde moet een geheel getal zijn."
#: db/models/fields/__init__.py:381
msgid "This value must be either True or False."
-msgstr "De waarde moet of True (waar) of False (onwaar) zijn."
+msgstr "De waarde moet of True (Waar) of False (Onwaar) zijn."
#: db/models/fields/__init__.py:397
msgid "This field cannot be null."
@@ -279,7 +274,7 @@ msgstr "Alleen alfabetische karakters zijn toegestaan"
#: core/validators.py:139
msgid "Year must be 1900 or later."
-msgstr "Het jaartal moet 1900 of nieuwer zijn."
+msgstr "Het jaartal moet 1900 of later zijn."
#: core/validators.py:143
#, python-format
@@ -296,20 +291,20 @@ msgstr "Geef een geldig e-mailadres op."
#: core/validators.py:173 core/validators.py:442 forms/__init__.py:667
msgid "No file was submitted. Check the encoding type on the form."
-msgstr "Er was geen bestand verstuurd. Controleer de encoding van het formulier."
+msgstr "Er was geen bestand verstuurd. Controleer het coderings type van het formulier."
#: core/validators.py:177
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
-"Bestand ongeldig. Het bestand dat is gegeven is geen afbeelding of was "
+"Bestand ongeldig. Het bestand dat is gegeven is geen afbeelding of is "
"beschadigd."
#: core/validators.py:184
#, python-format
msgid "The URL %s does not point to a valid image."
-msgstr "De URL %s wijst niet naar een afbeelding."
+msgstr "De URL %s wijst niet naar een geldige afbeelding."
#: core/validators.py:188
#, python-format
@@ -321,7 +316,7 @@ msgstr ""
#: core/validators.py:196
#, python-format
msgid "The URL %s does not point to a valid QuickTime video."
-msgstr "De URL %s wijst niet naar een QuickTime video."
+msgstr "De URL %s wijst niet naar een geldige QuickTime video."
#: core/validators.py:200
msgid "A valid URL is required."
@@ -349,18 +344,18 @@ msgstr "Ongeldige URL: %s"
#: core/validators.py:243 core/validators.py:245
#, python-format
msgid "The URL %s is a broken link."
-msgstr "De URL %s is een niet werkende link."
+msgstr "De URL %s is niet een werkende link."
#: core/validators.py:251
msgid "Enter a valid U.S. state abbreviation."
-msgstr "Geef een geldige afkorting van een VS staat."
+msgstr "Geef een geldige afkorting van een staat in de VS."
#: core/validators.py:265
#, python-format
msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Pas op uw taalgebruik! Gebruik van %s niet toegestaan."
-msgstr[1] "Pas op uw taalgebruik! Gebruik van de woorden %s niet toegestaan."
+msgstr[1] "Pas op uw taalgebruik! Gebruik van de woorden %s is niet toegestaan."
#: core/validators.py:272
#, python-format
@@ -373,7 +368,7 @@ msgstr "Voer tenminste één veld in."
#: core/validators.py:300 core/validators.py:311
msgid "Please enter both fields or leave them both empty."
-msgstr "Voer waarden in in beide velden of laat beide leeg."
+msgstr "Voer waarden in beide velden in of laat beide leeg."
#: core/validators.py:318
#, python-format
@@ -450,7 +445,7 @@ msgstr "Zorg ervoor dat het bestand hoogstens %s bytes groot is."
#: core/validators.py:453
msgid "The format for this field is wrong."
-msgstr "Het formaat van dit veld is fout."
+msgstr "Het formaat van dit veld is foutief."
#: core/validators.py:468
msgid "This field is invalid."
@@ -536,7 +531,7 @@ msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in."
msgstr ""
-"Het lijkt erop dat uw browser geen cookies accepteerd. Om aan te melden "
+"Het lijkt erop dat uw browser geen cookies accepteert. Om aan te melden "
"moeten cookies worden geaccepteerd."
#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10
@@ -645,7 +640,7 @@ msgstr "supergebruiker status"
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
-msgstr "Bepaald dat deze gebruiker alle rechten heeft, zonder deze expliciet toe te wijzen."
+msgstr "Bepaalt dat deze gebruiker alle rechten heeft, zonder deze expliciet toe te wijzen."
#: contrib/auth/models.py:98
msgid "last login"
@@ -685,7 +680,7 @@ msgstr "Rechten"
#: contrib/auth/models.py:113
msgid "Important dates"
-msgstr "Belangrijke data"
+msgstr "Belangrijke datums"
#: contrib/auth/models.py:114
msgid "Groups"
@@ -783,7 +778,7 @@ msgid ""
"Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved."
msgstr ""
-"Uw sessie is verlopen, meldt u opnieuw aan. Maakt u geen zorgen: Uw bijdrage "
+"Uw sessie is verlopen, meld u opnieuw aan. Maakt u zich geen zorgen: Uw bijdrage "
"is opgeslagen."
#: contrib/admin/views/decorators.py:69
@@ -791,7 +786,7 @@ msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again."
msgstr ""
-"Het lijkt erop dat uw browser geen cookies accepteerd. Zet het gebruik van "
+"Het lijkt erop dat uw browser geen cookies accepteert. Zet het gebruik van "
"cookies aan in uw browser, laad deze pagina nogmaals en probeer het opnieuw."
#: contrib/admin/views/decorators.py:83
@@ -928,7 +923,7 @@ msgstr "Model %r niet gevonden in app %r"
#: contrib/admin/views/doc.py:183
#, python-format
msgid "the related `%s.%s` object"
-msgstr "the related `%s.%s` object"
+msgstr "het gerelateerde `%s.%s` object"
#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205
#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224
@@ -938,7 +933,7 @@ msgstr "model:"
#: contrib/admin/views/doc.py:214
#, python-format
msgid "related `%s.%s` objects"
-msgstr "related `%s.%s` objects"
+msgstr "de gerelateerde `%s.%s` objecten"
#: contrib/admin/views/doc.py:219
#, python-format
@@ -948,12 +943,12 @@ msgstr "alle %s"
#: contrib/admin/views/doc.py:224
#, python-format
msgid "number of %s"
-msgstr "nummer van %s"
+msgstr "aantal %s"
#: contrib/admin/views/doc.py:229
#, python-format
msgid "Fields on %s objects"
-msgstr "Velden van %s objects"
+msgstr "Velden van %s objecten"
#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301
#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309
@@ -1139,11 +1134,11 @@ msgid ""
"All of the following related items will be deleted:"
msgstr ""
"Weet u zeker dat u %(object_name)s \"%(escaped_object)s\" wilt verwijderen? Alle "
-"volgende opjecten worden verwijderd:"
+"volgende objecten worden verwijderd:"
#: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure"
-msgstr "Ja, Ik weet het zeker"
+msgstr "Ja, ik weet het zeker"
#: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8
@@ -1197,7 +1192,7 @@ msgstr "Opslaan en nieuw item"
#: contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing"
-msgstr "Opslaan en bewerk opnieuw"
+msgstr "Opslaan en opnieuw bewerken"
#: contrib/admin/templates/admin/submit_line.html:7
msgid "Save"
@@ -1224,7 +1219,7 @@ msgstr "Wijzigen"
#: contrib/admin/templates/admin/index.html:44
msgid "You don't have permission to edit anything."
-msgstr "U heeft geen rechten om iets te wijzigen"
+msgstr "U heeft geen rechten om iets te wijzigen."
#: contrib/admin/templates/admin/index.html:52
msgid "Recent Actions"
@@ -1380,7 +1375,7 @@ msgstr ""
"de bookmarklet vanuit elke pagina op de site worden gekozen. Let erop dat "
"het soms\n"
"noodzakelijk is dat de computer van waaruit de pagina wordt bekeken intern "
-"is\n"
+"is.\n"
"(Raadpleeg uw systeembeheerder of uw computer zich op het interne netwerk "
"bevind).<p>\n"
@@ -1393,7 +1388,7 @@ msgid ""
"Jumps you from any page to the documentation for the view that generates "
"that page."
msgstr ""
-"Spring vanuit elke pagina naar de documentatie voor de view die gegenereerd "
+"Springt vanuit elke pagina naar de documentatie voor de view die gegenereerd "
"wordt door die pagina"
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
@@ -1406,7 +1401,7 @@ msgid ""
"object."
msgstr ""
"Toont de content-type en unieke ID voor pagina's die een enkel object "
-"voorsteld."
+"voorstellen."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)"
@@ -1414,7 +1409,7 @@ msgstr "Bewerk dit object (huidig venster)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object."
-msgstr "Ga naar de beheerpagina voor pagina's die een enkel object weergeven."
+msgstr "Gaat naar de beheerpagina voor pagina's die een enkel object weergeven."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)"
@@ -1527,7 +1522,7 @@ msgid ""
"password twice so we can verify you typed it in correctly."
msgstr ""
"Vanwege de beveiliging moet u uw oude en twee keer een nieuw "
-"wachtwoordinvoeren, zodat we kunnen controleren of er geen typefouten zijn "
+"wachtwoord invoeren, zodat we kunnen controleren of er geen typefouten zijn "
"gemaakt."
#: contrib/admin/templates/registration/password_change_form.html:17
@@ -1597,7 +1592,7 @@ msgid ""
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
"will use 'flatpages/default.html'."
msgstr ""
-"Voorbeeld: 'flatpages/contact_page'. Als deze niet is opgegeven, dan wordt "
+"Voorbeeld: 'flatpages/contact_page.html'. Als deze niet is opgegeven, dan wordt "
"'flatpages/default.html' gebruikt."
#: contrib/flatpages/models.py:14
@@ -1894,7 +1889,7 @@ msgstr "Een of meerdere verplichte velden zijn niet ingevuld"
#: contrib/comments/views/comments.py:196
#: contrib/comments/views/comments.py:286
msgid "Somebody tampered with the comment form (security violation)"
-msgstr "Iemand heeft het opmerkingenformulier gewijzigd (Beveilingsinbreuk)"
+msgstr "Iemand heeft het opmerkingenformulier gewijzigd (beveilingsinbreuk)"
#: contrib/comments/views/comments.py:206
#: contrib/comments/views/comments.py:292
diff --git a/django/contrib/admin/media/js/urlify.js b/django/contrib/admin/media/js/urlify.js
index 74e6e57e6c..63e626d884 100644
--- a/django/contrib/admin/media/js/urlify.js
+++ b/django/contrib/admin/media/js/urlify.js
@@ -55,6 +55,12 @@ var POLISH_MAP = {
'Ź':'Z', 'Ż':'Z'
}
+var LATVIAN_MAP = {
+ 'ā':'a', 'č':'c', 'ē':'e', 'ģ':'g', 'ī':'i', 'ķ':'k', 'ļ':'l', 'ņ':'n',
+ 'š':'s', 'ū':'u', 'ž':'z', 'Ā':'A', 'Č':'C', 'Ē':'E', 'Ģ':'G', 'Ī':'i',
+ 'Ķ':'k', 'Ļ':'L', 'Ņ':'N', 'Š':'S', 'Ū':'u', 'Ž':'Z'
+}
+
var ALL_DOWNCODE_MAPS=new Array()
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
@@ -64,6 +70,7 @@ ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
+ALL_DOWNCODE_MAPS[8]=LATVIAN_MAP
var Downcoder = new Object();
Downcoder.Initialize = function()
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index a4e6269b6f..e45b6ed0bb 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -114,7 +114,7 @@ def result_headers(cl):
yield {"text": header,
"sortable": True,
"url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
- "class_attrib": (th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
+ "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
def _boolean_icon(field_val):
BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 33f92dc854..4b1590264b 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -322,7 +322,7 @@ class AnonymousUser(object):
id = None
username = ''
is_staff = False
- is_active = True
+ is_active = False
is_superuser = False
_groups = EmptyManager()
_user_permissions = EmptyManager()
diff --git a/django/contrib/auth/tests.py b/django/contrib/auth/tests.py
index 329049c546..d369ac524c 100644
--- a/django/contrib/auth/tests.py
+++ b/django/contrib/auth/tests.py
@@ -16,9 +16,21 @@ False
>>> u2 = User.objects.create_user('testuser2', 'test2@example.com')
>>> u2.has_usable_password()
False
+
+>>> u.is_authenticated()
+True
+>>> u.is_staff
+False
+>>> u.is_active
+True
+
>>> a = AnonymousUser()
+>>> a.is_authenticated()
+False
>>> a.is_staff
False
+>>> a.is_active
+False
>>> a.groups.all()
[]
>>> a.user_permissions.all()
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index 63c44ab285..8d32406965 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -16,18 +16,18 @@ class GenericForeignKey(object):
Provides a generic relation to any object through content-type/object-id
fields.
"""
-
+
def __init__(self, ct_field="content_type", fk_field="object_id"):
self.ct_field = ct_field
self.fk_field = fk_field
-
+
def contribute_to_class(self, cls, name):
- # Make sure the fields exist (these raise FieldDoesNotExist,
+ # Make sure the fields exist (these raise FieldDoesNotExist,
# which is a fine error to raise here)
self.name = name
self.model = cls
self.cache_attr = "_%s_cache" % name
-
+
# For some reason I don't totally understand, using weakrefs here doesn't work.
dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False)
@@ -35,18 +35,18 @@ class GenericForeignKey(object):
setattr(cls, name, self)
def instance_pre_init(self, signal, sender, args, kwargs):
- # Handle initalizing an object with the generic FK instaed of
- # content-type/object-id fields.
+ # Handle initalizing an object with the generic FK instaed of
+ # content-type/object-id fields.
if self.name in kwargs:
value = kwargs.pop(self.name)
kwargs[self.ct_field] = self.get_content_type(value)
kwargs[self.fk_field] = value._get_pk_val()
-
+
def get_content_type(self, obj):
# Convenience function using get_model avoids a circular import when using this model
ContentType = get_model("contenttypes", "contenttype")
return ContentType.objects.get_for_model(obj)
-
+
def __get__(self, instance, instance_type=None):
if instance is None:
raise AttributeError, u"%s must be accessed via instance" % self.name
@@ -77,21 +77,21 @@ class GenericForeignKey(object):
setattr(instance, self.ct_field, ct)
setattr(instance, self.fk_field, fk)
setattr(instance, self.cache_attr, value)
-
+
class GenericRelation(RelatedField, Field):
"""Provides an accessor to generic related objects (i.e. comments)"""
def __init__(self, to, **kwargs):
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
- kwargs['rel'] = GenericRel(to,
+ kwargs['rel'] = GenericRel(to,
related_name=kwargs.pop('related_name', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
symmetrical=kwargs.pop('symmetrical', True))
-
+
# Override content-type/object-id field names on the related class
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
- self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
-
+ self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
+
kwargs['blank'] = True
kwargs['editable'] = False
kwargs['serialize'] = False
@@ -116,9 +116,9 @@ class GenericRelation(RelatedField, Field):
def m2m_column_name(self):
return self.object_id_field_name
-
+
def m2m_reverse_name(self):
- return self.object_id_field_name
+ return self.model._meta.pk.column
def contribute_to_class(self, cls, name):
super(GenericRelation, self).contribute_to_class(cls, name)
@@ -131,7 +131,7 @@ class GenericRelation(RelatedField, Field):
def contribute_to_related_class(self, cls, related):
pass
-
+
def set_attributes_from_rel(self):
pass
@@ -142,7 +142,7 @@ class GenericRelation(RelatedField, Field):
# Since we're simulating a ManyToManyField, in effect, best return the
# same db_type as well.
return None
-
+
class ReverseGenericRelatedObjectsDescriptor(object):
"""
This class provides the functionality that makes the related-object
@@ -198,12 +198,12 @@ def create_generic_related_manager(superclass):
Factory function for a manager that subclasses 'superclass' (which is a
Manager) and adds behavior for generic related objects.
"""
-
+
class GenericRelatedObjectManager(superclass):
def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
join_table=None, source_col_name=None, target_col_name=None, content_type=None,
content_type_field_name=None, object_id_field_name=None):
-
+
super(GenericRelatedObjectManager, self).__init__()
self.core_filters = core_filters or {}
self.model = model
@@ -217,10 +217,10 @@ def create_generic_related_manager(superclass):
self.content_type_field_name = content_type_field_name
self.object_id_field_name = object_id_field_name
self.pk_val = self.instance._get_pk_val()
-
+
def get_query_set(self):
query = {
- '%s__pk' % self.content_type_field_name : self.content_type.id,
+ '%s__pk' % self.content_type_field_name : self.content_type.id,
'%s__exact' % self.object_id_field_name : self.pk_val,
}
return superclass.get_query_set(self).filter(**query)
diff --git a/django/contrib/databrowse/datastructures.py b/django/contrib/databrowse/datastructures.py
index 4b0947eb34..1b32ee2e2e 100644
--- a/django/contrib/databrowse/datastructures.py
+++ b/django/contrib/databrowse/datastructures.py
@@ -12,6 +12,7 @@ from django.utils.safestring import mark_safe
from django.db.models.query import QuerySet
EMPTY_VALUE = '(None)'
+DISPLAY_SIZE = 100
class EasyModel(object):
def __init__(self, site, model):
@@ -93,8 +94,8 @@ class EasyInstance(object):
def __unicode__(self):
val = smart_unicode(self.instance)
- if len(val) > 30:
- return val[:30] + u'...'
+ if len(val) > DISPLAY_SIZE:
+ return val[:DISPLAY_SIZE] + u'...'
return val
def __str__(self):
diff --git a/django/contrib/localflavor/ar/forms.py b/django/contrib/localflavor/ar/forms.py
index 6d86e4e676..6374a48c92 100644
--- a/django/contrib/localflavor/ar/forms.py
+++ b/django/contrib/localflavor/ar/forms.py
@@ -24,18 +24,20 @@ class ARPostalCodeField(RegexField):
See http://www.correoargentino.com.ar/consulta_cpa/home.php
"""
+ default_error_messages = {
+ 'invalid': ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
+ }
+
def __init__(self, *args, **kwargs):
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
- min_length=4, max_length=8,
- error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
- *args, **kwargs)
+ min_length=4, max_length=8, *args, **kwargs)
def clean(self, value):
value = super(ARPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
return u''
if len(value) not in (4, 8):
- raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA."))
+ raise ValidationError(self.error_messages['invalid'])
if len(value) == 8:
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
return value
@@ -44,6 +46,11 @@ class ARDNIField(CharField):
"""
A field that validates `Documento Nacional de Identidad (DNI) numbers.
"""
+ default_error_messages = {
+ 'invalid': ugettext("This field requires only numbers."),
+ 'max_digits': ugettext("This field requires 7 or 8 digits."),
+ }
+
def __init__(self, *args, **kwargs):
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
**kwargs)
@@ -58,10 +65,9 @@ class ARDNIField(CharField):
if not value.isdigit():
value = value.replace('.', '')
if not value.isdigit():
- raise ValidationError(ugettext("This field requires only numbers."))
+ raise ValidationError(self.error_messages['invalid'])
if len(value) not in (7, 8):
- raise ValidationError(
- ugettext("This field requires 7 or 8 digits."))
+ raise ValidationError(self.error_messages['max_digits'])
return value
@@ -70,9 +76,13 @@ class ARCUITField(RegexField):
This field validates a CUIT (Cdigo nico de Identificacin Tributaria). A
CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
+ 'checksum': ugettext("Invalid CUIT."),
+ }
+
def __init__(self, *args, **kwargs):
super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
- error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
*args, **kwargs)
def clean(self, value):
@@ -85,7 +95,7 @@ class ARCUITField(RegexField):
return u''
value, cd = self._canon(value)
if self._calc_cd(value) != cd:
- raise ValidationError(ugettext("Invalid CUIT."))
+ raise ValidationError(self.error_messages['checksum'])
return self._format(value, cd)
def _canon(self, cuit):
diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py
index 33e883511b..ada27b69b9 100644
--- a/django/contrib/localflavor/au/forms.py
+++ b/django/contrib/localflavor/au/forms.py
@@ -12,14 +12,20 @@ PHONE_DIGITS_RE = re.compile(r'^(\d{10})$')
class AUPostCodeField(RegexField):
"""Australian post code field."""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a 4 digit post code.'),
+ }
+
def __init__(self, *args, **kwargs):
super(AUPostCodeField, self).__init__(r'^\d{4}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a 4 digit post code.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class AUPhoneNumberField(Field):
"""Australian phone number field."""
+ default_error_messages = {
+ 'invalid': u'Phone numbers must contain 10 digits.',
+ }
+
def clean(self, value):
"""
Validate a phone number. Strips parentheses, whitespace and hyphens.
@@ -31,7 +37,7 @@ class AUPhoneNumberField(Field):
phone_match = PHONE_DIGITS_RE.search(value)
if phone_match:
return u'%s' % phone_match.group(1)
- raise ValidationError(u'Phone numbers must contain 10 digits.')
+ raise ValidationError(self.error_messages['invalid'])
class AUStateSelect(Select):
"""
diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py
index 58bf795292..aa7e3b23fd 100644
--- a/django/contrib/localflavor/br/forms.py
+++ b/django/contrib/localflavor/br/forms.py
@@ -17,13 +17,19 @@ except NameError:
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
class BRZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': _('Enter a zip code in the format XXXXX-XXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
- max_length=None, min_length=None,
- error_message=_('Enter a zip code in the format XXXXX-XXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class BRPhoneNumberField(Field):
+ default_error_messages = {
+ 'invalid': _('Phone numbers must be in XX-XXXX-XXXX format.'),
+ }
+
def clean(self, value):
super(BRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@@ -32,7 +38,7 @@ class BRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
- raise ValidationError(_('Phone numbers must be in XX-XXXX-XXXX format.'))
+ raise ValidationError(self.error_messages['invalid'])
class BRStateSelect(Select):
"""
@@ -48,6 +54,9 @@ class BRStateChoiceField(Field):
A choice field that uses a list of Brazilian states as its choices.
"""
widget = Select
+ default_error_messages = {
+ 'invalid': _(u'Select a valid brazilian state. That state is not one of the available states.'),
+ }
def __init__(self, required=True, widget=None, label=None,
initial=None, help_text=None):
@@ -65,9 +74,7 @@ class BRStateChoiceField(Field):
return value
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
if value not in valid_values:
- raise ValidationError(_(u'Select a valid brazilian state.'
- u' That state is not one'
- u' of the available states.'))
+ raise ValidationError(self.error_messages['invalid'])
return value
def DV_maker(v):
@@ -83,6 +90,12 @@ class BRCPFField(CharField):
More information:
http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
"""
+ default_error_messages = {
+ 'invalid': _("Invalid CPF number."),
+ 'max_digits': _("This field requires at most 11 digits or 14 characters."),
+ 'digits_only': _("This field requires only numbers."),
+ }
+
def __init__(self, *args, **kwargs):
super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
@@ -100,9 +113,9 @@ class BRCPFField(CharField):
try:
int(value)
except ValueError:
- raise ValidationError(_("This field requires only numbers."))
+ raise ValidationError(self.error_messages['digits_only'])
if len(value) != 11:
- raise ValidationError(_("This field requires at most 11 digits or 14 characters."))
+ raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
@@ -112,11 +125,17 @@ class BRCPFField(CharField):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
- raise ValidationError(_("Invalid CPF number."))
+ raise ValidationError(self.error_messages['invalid'])
return orig_value
class BRCNPJField(Field):
+ default_error_messages = {
+ 'invalid': _("Invalid CNPJ number."),
+ 'digits_only': _("This field requires only numbers."),
+ 'max_digits': _("This field requires at least 14 digits"),
+ }
+
def clean(self, value):
"""
Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
@@ -131,10 +150,9 @@ class BRCNPJField(Field):
try:
int(value)
except ValueError:
- raise ValidationError("This field requires only numbers.")
+ raise ValidationError(self.error_messages['digits_only'])
if len(value) != 14:
- raise ValidationError(
- _("This field requires at least 14 digits"))
+ raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:]
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
@@ -144,7 +162,6 @@ class BRCNPJField(Field):
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
- raise ValidationError(_("Invalid CNPJ number."))
+ raise ValidationError(self.error_messages['invalid'])
return orig_value
-
diff --git a/django/contrib/localflavor/ca/forms.py b/django/contrib/localflavor/ca/forms.py
index 98f65a5c6c..daeff58acf 100644
--- a/django/contrib/localflavor/ca/forms.py
+++ b/django/contrib/localflavor/ca/forms.py
@@ -1,37 +1,43 @@
-"""
-Canada-specific Form helpers
-"""
-
-from django.newforms import ValidationError
-from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.newforms.util import smart_unicode
+"""
+Canada-specific Form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.newforms.util import smart_unicode
from django.utils.translation import gettext, ugettext
-import re
-
+import re
+
phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
-
-class CAPostalCodeField(RegexField):
- """Canadian postal code field."""
- def __init__(self, *args, **kwargs):
- super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
- max_length=None, min_length=None,
- error_message=gettext(u'Enter a postal code in the format XXX XXX.'),
- *args, **kwargs)
-
-class CAPhoneNumberField(Field):
- """Canadian phone number field."""
- def clean(self, value):
- """Validate a phone number.
- """
- super(CAPhoneNumberField, self).clean(value)
+
+class CAPostalCodeField(RegexField):
+ """Canadian postal code field."""
+ default_error_messages = {
+ 'invalid': gettext(u'Enter a postal code in the format XXX XXX.'),
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
+ max_length=None, min_length=None, *args, **kwargs)
+
+class CAPhoneNumberField(Field):
+ """Canadian phone number field."""
+ default_error_messages = {
+ 'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
+ }
+
+ def clean(self, value):
+ """Validate a phone number.
+ """
+ super(CAPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
- raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
+ raise ValidationError(self.error_messages['invalid'])
class CAProvinceField(Field):
"""
@@ -39,6 +45,10 @@ class CAProvinceField(Field):
It normalizes the input to the standard two-leter postal service
abbreviation for the given province.
"""
+ default_error_messages = {
+ 'invalid': u'Enter a Canadian province or territory.',
+ }
+
def clean(self, value):
from ca_provinces import PROVINCES_NORMALIZED
super(CAProvinceField, self).clean(value)
@@ -53,17 +63,17 @@ class CAProvinceField(Field):
return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError:
pass
- raise ValidationError(u'Enter a Canadian province or territory.')
-
-class CAProvinceSelect(Select):
- """
- A Select widget that uses a list of Canadian provinces and
- territories as its choices.
- """
- def __init__(self, attrs=None):
- from ca_provinces import PROVINCE_CHOICES # relative import
+ raise ValidationError(self.error_messages['invalid'])
+
+class CAProvinceSelect(Select):
+ """
+ A Select widget that uses a list of Canadian provinces and
+ territories as its choices.
+ """
+ def __init__(self, attrs=None):
+ from ca_provinces import PROVINCE_CHOICES # relative import
super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
-
+
class CASocialInsuranceNumberField(Field):
"""
A Canadian Social Insurance Number (SIN).
@@ -74,24 +84,28 @@ class CASocialInsuranceNumberField(Field):
* Passes the check digit process "Luhn Algorithm"
See: http://en.wikipedia.org/wiki/Social_Insurance_Number
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.'),
+ }
+
def clean(self, value):
super(CASocialInsuranceNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
- msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.')
+
match = re.match(sin_re, value)
if not match:
- raise ValidationError(msg)
-
- number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
+ raise ValidationError(self.error_messages['invalid'])
+
+ number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
if not self.luhn_checksum_is_valid(check_number):
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
return number
-
+
def luhn_checksum_is_valid(self, number):
"""
- 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
"""
@@ -109,4 +123,4 @@ class CASocialInsuranceNumberField(Field):
sum = sum + digit
- return ( (sum % 10) == 0 ) \ No newline at end of file
+ return ( (sum % 10) == 0 )
diff --git a/django/contrib/localflavor/ch/forms.py b/django/contrib/localflavor/ch/forms.py
index 5e601f5d74..2158fba697 100644
--- a/django/contrib/localflavor/ch/forms.py
+++ b/django/contrib/localflavor/ch/forms.py
@@ -12,11 +12,13 @@ id_re = re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$
phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
class CHZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(CHZipCodeField, self).__init__(r'^\d{4}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class CHPhoneNumberField(Field):
"""
@@ -25,6 +27,10 @@ class CHPhoneNumberField(Field):
'0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0XX XXX XX XX'.
"""
+ default_error_messages = {
+ 'invalid': 'Phone numbers must be in 0XX XXX XX XX format.',
+ }
+
def clean(self, value):
super(CHPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@@ -33,7 +39,7 @@ class CHPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
- raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.')
+ raise ValidationError(self.error_messages['invalid'])
class CHStateSelect(Select):
"""
@@ -54,6 +60,10 @@ class CHIdentityCardNumberField(Field):
Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.'),
+ }
+
def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1]
new_number = given_number
@@ -87,23 +97,22 @@ class CHIdentityCardNumberField(Field):
def clean(self, value):
super(CHIdentityCardNumberField, self).clean(value)
- error_msg = ugettext('Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.')
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
if not match:
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
idnumber, pos9, checksum = match.groupdict()['idnumber'], match.groupdict()['pos9'], match.groupdict()['checksum']
if idnumber == '00000000' or \
idnumber == 'A0000000':
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
all_digits = "%s%s%s" % (idnumber, pos9, checksum)
if not self.has_valid_checksum(all_digits):
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
return u'%s%s%s' % (idnumber, pos9, checksum)
diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py
index d2d37a3712..2f5ac29b39 100644
--- a/django/contrib/localflavor/cl/forms.py
+++ b/django/contrib/localflavor/cl/forms.py
@@ -25,16 +25,21 @@ class CLRutField(RegexField):
Samples for testing are available from
https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid Chilean RUT.'),
+ 'strict': ugettext('Enter a valid Chilean RUT. The format is XX.XXX.XXX-X.'),
+ 'checksum': ugettext('The Chilean RUT is not valid.'),
+ }
+
def __init__(self, *args, **kwargs):
if 'strict' in kwargs:
del kwargs['strict']
super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$',
- error_message=ugettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'),
- *args, **kwargs)
+ error_message=self.default_error_messages['strict'], *args, **kwargs)
else:
# In non-strict mode, accept RUTs that validate but do not exist in
# the real world.
- super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=ugettext('Enter valid a Chilean RUT'), *args, **kwargs)
+ super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', *args, **kwargs)
def clean(self, value):
"""
@@ -47,7 +52,7 @@ class CLRutField(RegexField):
if self._algorithm(rut) == verificador:
return self._format(rut, verificador)
else:
- raise ValidationError(u'The Chilean RUT is not valid.')
+ raise ValidationError(self.error_messages['checksum'])
def _algorithm(self, rut):
"""
diff --git a/django/contrib/localflavor/de/forms.py b/django/contrib/localflavor/de/forms.py
index 1a0b8587a6..76ce215dca 100644
--- a/django/contrib/localflavor/de/forms.py
+++ b/django/contrib/localflavor/de/forms.py
@@ -10,11 +10,12 @@ import re
id_re = re.compile(r"^(?P<residence>\d{10})(?P<origin>\w{1,3})[-\ ]?(?P<birthday>\d{7})[-\ ]?(?P<validity>\d{7})[-\ ]?(?P<checksum>\d{1})$")
class DEZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXXX.'),
+ }
def __init__(self, *args, **kwargs):
super(DEZipCodeField, self).__init__(r'^\d{5}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class DEStateSelect(Select):
"""
@@ -36,6 +37,10 @@ class DEIdentityCardNumberField(Field):
Algorithm is documented at http://de.wikipedia.org/wiki/Personalausweis
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'),
+ }
+
def has_valid_checksum(self, number):
given_number, given_checksum = number[:-1], number[-1]
calculated_checksum = 0
@@ -57,23 +62,22 @@ class DEIdentityCardNumberField(Field):
def clean(self, value):
super(DEIdentityCardNumberField, self).clean(value)
- error_msg = ugettext('Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.')
if value in EMPTY_VALUES:
return u''
match = re.match(id_re, value)
if not match:
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
gd = match.groupdict()
residence, origin = gd['residence'], gd['origin']
birthday, validity, checksum = gd['birthday'], gd['validity'], gd['checksum']
if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
- raise ValidationError(error_msg)
+ raise ValidationError(self.error_messages['invalid'])
return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
diff --git a/django/contrib/localflavor/es/forms.py b/django/contrib/localflavor/es/forms.py
index 29b41828f6..81186f8b3d 100644
--- a/django/contrib/localflavor/es/forms.py
+++ b/django/contrib/localflavor/es/forms.py
@@ -15,12 +15,14 @@ class ESPostalCodeField(RegexField):
Spanish postal code is a five digits string, with two first digits
between 01 and 52, assigned to provinces code.
"""
+ default_error_messages = {
+ 'invalid': _('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(ESPostalCodeField, self).__init__(
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
- max_length=None, min_length=None,
- error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class ESPhoneNumberField(RegexField):
"""
@@ -33,11 +35,13 @@ class ESPhoneNumberField(RegexField):
TODO: accept and strip characters like dot, hyphen... in phone number
"""
+ default_error_messages = {
+ 'invalid': _('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
- max_length=None, min_length=None,
- error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class ESIdentityCardNumberField(RegexField):
"""
@@ -58,19 +62,23 @@ class ESIdentityCardNumberField(RegexField):
public, and different authors have different opinions on which ones allows
letters, so both validations are assumed true for all types.
"""
+ default_error_messages = {
+ 'invalid': _('Please enter a valid NIF, NIE, or CIF.'),
+ 'invalid_only_nif': _('Please enter a valid NIF or NIE.'),
+ 'invalid_nif': _('Invalid checksum for NIF.'),
+ 'invalid_nie': _('Invalid checksum for NIE.'),
+ 'invalid_cif': _('Invalid checksum for CIF.'),
+ }
+
def __init__(self, only_nif=False, *args, **kwargs):
self.only_nif = only_nif
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
self.cif_control = 'JABCDEFGHI'
self.cif_types = 'ABCDEFGHKLMNPQS'
self.nie_types = 'XT'
- if self.only_nif:
- self.id_types = 'NIF or NIE'
- else:
- self.id_types = 'NIF, NIE, or CIF'
super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()),
max_length=None, min_length=None,
- error_message=_('Please enter a valid %s.' % self.id_types),
+ error_message=self.default_error_messages['invalid%s' % (self.only_nif and '_only_nif' or '')],
*args, **kwargs)
def clean(self, value):
@@ -88,13 +96,13 @@ class ESIdentityCardNumberField(RegexField):
if letter2 == nif_get_checksum(number):
return value
else:
- raise ValidationError, _('Invalid checksum for NIF.')
+ raise ValidationError, self.error_messages['invalid_nif']
elif letter1 in self.nie_types and letter2:
# NIE
if letter2 == nif_get_checksum(number):
return value
else:
- raise ValidationError, _('Invalid checksum for NIE.')
+ raise ValidationError, self.error_messages['invalid_nie']
elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]:
# CIF
if not letter2:
@@ -103,9 +111,9 @@ class ESIdentityCardNumberField(RegexField):
if letter2 in [checksum, self.cif_control[checksum]]:
return value
else:
- raise ValidationError, _('Invalid checksum for CIF.')
+ raise ValidationError, self.error_messages['invalid_cif']
else:
- raise ValidationError, _('Please enter a valid %s.' % self.id_types)
+ raise ValidationError, self.error_messages['invalid']
class ESCCCField(RegexField):
"""
@@ -130,11 +138,14 @@ class ESCCCField(RegexField):
TODO: allow IBAN validation too
"""
+ default_error_messages = {
+ 'invalid': _('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
+ 'checksum': _('Invalid checksum for bank account number.'),
+ }
+
def __init__(self, *args, **kwargs):
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
- max_length=None, min_length=None,
- error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
super(ESCCCField, self).clean(value)
@@ -147,7 +158,7 @@ class ESCCCField(RegexField):
if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
return value
else:
- raise ValidationError, _('Invalid checksum for bank account number.')
+ raise ValidationError, self.error_messages['checksum']
class ESRegionSelect(Select):
"""
diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py
index 82e024f7b1..a0274da44c 100644
--- a/django/contrib/localflavor/fi/forms.py
+++ b/django/contrib/localflavor/fi/forms.py
@@ -8,11 +8,12 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext
class FIZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXXX.'),
+ }
def __init__(self, *args, **kwargs):
super(FIZipCodeField, self).__init__(r'^\d{5}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class FIMunicipalitySelect(Select):
"""
@@ -23,6 +24,10 @@ class FIMunicipalitySelect(Select):
super(FIMunicipalitySelect, self).__init__(attrs, choices=MUNICIPALITY_CHOICES)
class FISocialSecurityNumber(Field):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid Finnish social security number.'),
+ }
+
def clean(self, value):
super(FISocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
@@ -37,9 +42,9 @@ class FISocialSecurityNumber(Field):
(?P<serial>(\d{3}))
(?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
if not result:
- raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
+ raise ValidationError(self.error_messages['invalid'])
gd = result.groupdict()
checksum = int(gd['date'] + gd['serial'])
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
return u'%s' % value.upper()
- raise ValidationError(ugettext('Enter a valid Finnish social security number.'))
+ raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/fr/forms.py b/django/contrib/localflavor/fr/forms.py
index cc0a5db259..635b62edd5 100644
--- a/django/contrib/localflavor/fr/forms.py
+++ b/django/contrib/localflavor/fr/forms.py
@@ -11,11 +11,13 @@ import re
phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
class FRZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(FRZipCodeField, self).__init__(r'^\d{5}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class FRPhoneNumberField(Field):
"""
@@ -24,6 +26,10 @@ class FRPhoneNumberField(Field):
'0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
'0X XX XX XX XX'.
"""
+ default_error_messages = {
+ 'invalid': u'Phone numbers must be in 0X XX XX XX XX format.',
+ }
+
def clean(self, value):
super(FRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@@ -32,7 +38,7 @@ class FRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
- raise ValidationError(u'Phone numbers must be in 0X XX XX XX XX format.')
+ raise ValidationError(self.error_messages['invalid'])
class FRDepartmentSelect(Select):
"""
diff --git a/django/contrib/localflavor/in_/forms.py b/django/contrib/localflavor/in_/forms.py
index 5febc40e67..1cb303d772 100644
--- a/django/contrib/localflavor/in_/forms.py
+++ b/django/contrib/localflavor/in_/forms.py
@@ -10,11 +10,13 @@ import re
class INZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': gettext(u'Enter a zip code in the format XXXXXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(INZipCodeField, self).__init__(r'^\d{6}$',
- max_length=None, min_length=None,
- error_message=gettext(u'Enter a zip code in the format XXXXXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class INStateField(Field):
"""
@@ -22,6 +24,10 @@ class INStateField(Field):
abbreviation. It normalizes the input to the standard two-letter vehicle
registration abbreviation for the given state or union territory
"""
+ default_error_messages = {
+ 'invalid': u'Enter a Indian state or territory.',
+ }
+
def clean(self, value):
from in_states import STATES_NORMALIZED
super(INStateField, self).clean(value)
@@ -36,7 +42,7 @@ class INStateField(Field):
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
except KeyError:
pass
- raise ValidationError(u'Enter a Indian state or territory.')
+ raise ValidationError(self.error_messages['invalid'])
class INStateSelect(Select):
"""
diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py
index ef8799e29c..ea7a1e00c3 100644
--- a/django/contrib/localflavor/is_/forms.py
+++ b/django/contrib/localflavor/is_/forms.py
@@ -13,10 +13,14 @@ class ISIdNumberField(RegexField):
Icelandic identification number (kennitala). This is a number every citizen
of Iceland has.
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.'),
+ 'checksum': ugettext(u'The Icelandic identification number is not valid.'),
+ }
+
def __init__(self, *args, **kwargs):
- error_msg = ugettext('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.')
kwargs['min_length'],kwargs['max_length'] = 10,11
- super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs)
+ super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', *args, **kwargs)
def clean(self, value):
value = super(ISIdNumberField, self).clean(value)
@@ -28,7 +32,7 @@ class ISIdNumberField(RegexField):
if self._validate(value):
return self._format(value)
else:
- raise ValidationError(ugettext(u'The Icelandic identification number is not valid.'))
+ raise ValidationError(self.error_messages['checksum'])
def _canonify(self, value):
"""
diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py
index 0b6eecec45..88e65734e4 100644
--- a/django/contrib/localflavor/it/forms.py
+++ b/django/contrib/localflavor/it/forms.py
@@ -10,11 +10,12 @@ from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check
import re
class ITZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid zip code.'),
+ }
def __init__(self, *args, **kwargs):
super(ITZipCodeField, self).__init__(r'^\d{5}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a valid zip code.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class ITRegionSelect(Select):
"""
@@ -38,11 +39,13 @@ class ITSocialSecurityNumberField(RegexField):
For reference see http://www.agenziaentrate.it/ and search for
'Informazioni sulla codificazione delle persone fisiche'.
"""
- err_msg = ugettext(u'Enter a valid Social Security number.')
+ default_error_messages = {
+ 'invalid': ugettext(u'Enter a valid Social Security number.'),
+ }
+
def __init__(self, *args, **kwargs):
super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$',
- max_length=None, min_length=None, error_message=self.err_msg,
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
value = super(ITSocialSecurityNumberField, self).clean(value)
@@ -52,26 +55,29 @@ class ITSocialSecurityNumberField(RegexField):
try:
check_digit = ssn_check_digit(value)
except ValueError:
- raise ValidationError(self.err_msg)
+ raise ValidationError(self.error_messages['invalid'])
if not value[15] == check_digit:
- raise ValidationError(self.err_msg)
+ raise ValidationError(self.error_messages['invalid'])
return value
class ITVatNumberField(Field):
"""
A form field that validates Italian VAT numbers (partita IVA).
"""
+ default_error_messages = {
+ 'invalid': ugettext(u'Enter a valid VAT number.'),
+ }
+
def clean(self, value):
value = super(ITVatNumberField, self).clean(value)
if value == u'':
return value
- err_msg = ugettext(u'Enter a valid VAT number.')
try:
vat_number = int(value)
except ValueError:
- raise ValidationError(err_msg)
+ raise ValidationError(self.error_messages['invalid'])
vat_number = str(vat_number).zfill(11)
check_digit = vat_number_check_digit(vat_number[0:10])
if not vat_number[10] == check_digit:
- raise ValidationError(err_msg)
+ raise ValidationError(self.error_messages['invalid'])
return smart_unicode(vat_number)
diff --git a/django/contrib/localflavor/jp/forms.py b/django/contrib/localflavor/jp/forms.py
index 682ffb8c31..13083aab6e 100644
--- a/django/contrib/localflavor/jp/forms.py
+++ b/django/contrib/localflavor/jp/forms.py
@@ -15,11 +15,13 @@ class JPPostalCodeField(RegexField):
Accepts 7 digits, with or without a hyphen.
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
"""
diff --git a/django/contrib/localflavor/nl/forms.py b/django/contrib/localflavor/nl/forms.py
index e202ab0595..748484926e 100644
--- a/django/contrib/localflavor/nl/forms.py
+++ b/django/contrib/localflavor/nl/forms.py
@@ -17,24 +17,27 @@ class NLZipCodeField(Field):
"""
A Dutch postal code field.
"""
+ default_error_messages = {
+ 'invalid': _('Enter a valid postal code'),
+ }
+
def clean(self, value):
super(NLZipCodeField, self).clean(value)
if value in EMPTY_VALUES:
return u''
-
- msg = _('Enter a valid postal code')
+
value = value.strip().upper().replace(' ', '')
if not pc_re.search(value):
- raise ValidationError(msg)
-
+ raise ValidationError(self.error_messages['invalid'])
+
if int(value[:4]) < 1000:
- raise ValidationError(msg)
-
+ raise ValidationError(self.error_messages['invalid'])
+
return u'%s %s' % (value[:4], value[4:])
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.
"""
def __init__(self, attrs=None):
@@ -45,48 +48,53 @@ class NLPhoneNumberField(Field):
"""
A Dutch telephone number field.
"""
+ default_error_messages = {
+ 'invalid': _('Enter a valid phone number'),
+ }
+
def clean(self, value):
super(NLPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
-
- msg = _('Enter a valid phone number')
+
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
-
+
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
return value
-
+
if phone_nr[:3] == '+31' and len(phone_nr) == 12 and \
numeric_re.search(phone_nr[3:]):
return value
-
- raise ValidationError(msg)
+
+ raise ValidationError(self.error_messages['invalid'])
class NLSoFiNumberField(Field):
"""
A Dutch social security number (SoFi/BSN) field.
-
+
http://nl.wikipedia.org/wiki/Sofinummer
"""
+ default_error_messages = {
+ 'invalid': _('Enter a valid SoFi number'),
+ }
+
def clean(self, value):
super(NLSoFiNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
-
- msg = _('Enter a valid SoFi number')
-
+
if not sofi_re.search(value):
- raise ValidationError(msg)
-
+ raise ValidationError(self.error_messages['invalid'])
+
if int(value) == 0:
- raise ValidationError(msg)
-
+ raise ValidationError(self.error_messages['invalid'])
+
checksum = 0
for i in range(9, 1, -1):
checksum += int(value[9-i]) * i
checksum -= int(value[-1])
-
+
if checksum % 11 != 0:
- raise ValidationError(msg)
-
+ raise ValidationError(self.error_messages['invalid'])
+
return value
diff --git a/django/contrib/localflavor/no/forms.py b/django/contrib/localflavor/no/forms.py
index 2de3df14d8..8dc001955d 100644
--- a/django/contrib/localflavor/no/forms.py
+++ b/django/contrib/localflavor/no/forms.py
@@ -8,11 +8,13 @@ from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import ugettext
class NOZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(NOZipCodeField, self).__init__(r'^\d{4}$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class NOMunicipalitySelect(Select):
"""
@@ -27,14 +29,17 @@ class NOSocialSecurityNumber(Field):
"""
Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer
"""
+ default_error_messages = {
+ 'invalid': ugettext(u'Enter a valid Norwegian social security number.'),
+ }
+
def clean(self, value):
super(NOSocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
return u''
- msg = ugettext(u'Enter a valid Norwegian social security number.')
if not re.match(r'^\d{11}$', value):
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
day = int(value[:2])
month = int(value[2:4])
@@ -52,7 +57,7 @@ class NOSocialSecurityNumber(Field):
if 900 <= inum < 1000 and year2 > 39:
self.birthday = datetime.date(1900+year2, month, day)
except ValueError:
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
sexnum = int(value[8])
if sexnum % 2 == 0:
@@ -68,9 +73,9 @@ class NOSocialSecurityNumber(Field):
return sum([(a * b) for (a, b) in zip(aval, bval)])
if multiply_reduce(digits, weight_1) % 11 != 0:
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
if multiply_reduce(digits, weight_2) % 11 != 0:
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
return value
diff --git a/django/contrib/localflavor/pe/forms.py b/django/contrib/localflavor/pe/forms.py
index b1ae215417..57c9d441f7 100644
--- a/django/contrib/localflavor/pe/forms.py
+++ b/django/contrib/localflavor/pe/forms.py
@@ -19,6 +19,11 @@ class PEDNIField(CharField):
"""
A field that validates `Documento Nacional de IdentidadŽ (DNI) numbers.
"""
+ default_error_messages = {
+ 'invalid': ugettext("This field requires only numbers."),
+ 'max_digits': ugettext("This field requires 8 digits."),
+ }
+
def __init__(self, *args, **kwargs):
super(PEDNIField, self).__init__(max_length=8, min_length=8, *args,
**kwargs)
@@ -31,9 +36,9 @@ class PEDNIField(CharField):
if value in EMPTY_VALUES:
return u''
if not value.isdigit():
- raise ValidationError(ugettext("This field requires only numbers."))
+ raise ValidationError(self.error_messages['invalid'])
if len(value) != 8:
- raise ValidationError(ugettext("This field requires 8 digits."))
+ raise ValidationError(self.error_messages['max_digits'])
return value
@@ -42,6 +47,11 @@ class PERUCField(RegexField):
This field validates a RUC (Registro Unico de Contribuyentes). A RUC is of
the form XXXXXXXXXXX.
"""
+ default_error_messages = {
+ 'invalid': ugettext("This field requires only numbers."),
+ 'max_digits': ugettext("This field requires 11 digits."),
+ }
+
def __init__(self, *args, **kwargs):
super(PERUCField, self).__init__(max_length=11, min_length=11, *args,
**kwargs)
@@ -54,8 +64,8 @@ class PERUCField(RegexField):
if value in EMPTY_VALUES:
return u''
if not value.isdigit():
- raise ValidationError(ugettext("This field requires only numbers."))
+ raise ValidationError(self.error_messages['invalid'])
if len(value) != 11:
- raise ValidationError(ugettext("This field requires 11 digits."))
+ raise ValidationError(self.error_messages['max_digits'])
return value
diff --git a/django/contrib/localflavor/pl/forms.py b/django/contrib/localflavor/pl/forms.py
index 3d1c4234d3..b02dad7025 100644
--- a/django/contrib/localflavor/pl/forms.py
+++ b/django/contrib/localflavor/pl/forms.py
@@ -35,16 +35,19 @@ class PLNationalIdentificationNumberField(RegexField):
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
"""
+ default_error_messages = {
+ 'invalid': _(u'National Identification Number consists of 11 digits.'),
+ 'checksum': _(u'Wrong checksum for the National Identification Number.'),
+ }
def __init__(self, *args, **kwargs):
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
- max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLNationalIdentificationNumberField, self).clean(value)
if not self.has_valid_checksum(value):
- raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
+ raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@@ -65,17 +68,20 @@ class PLTaxNumberField(RegexField):
Checksum algorithm based on documentation at
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
"""
+ default_error_messages = {
+ 'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'),
+ 'checksum': _(u'Wrong checksum for the Tax Number (NIP).'),
+ }
def __init__(self, *args, **kwargs):
super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
- max_length=None, min_length=None,
- error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLTaxNumberField, self).clean(value)
value = re.sub("[-]", "", value)
if not self.has_valid_checksum(value):
- raise ValidationError(_(u'Wrong checksum for the Tax Number (NIP).'))
+ raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@@ -102,15 +108,19 @@ class PLNationalBusinessRegisterField(RegexField):
The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
"""
+ default_error_messages = {
+ 'invalid': _(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
+ 'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'),
+ }
+
def __init__(self, *args, **kwargs):
super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',
- max_length=None, min_length=None, error_message=_(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self,value):
super(PLNationalBusinessRegisterField, self).clean(value)
if not self.has_valid_checksum(value):
- raise ValidationError(_(u'Wrong checksum for the National Business Register Number (REGON).'))
+ raise ValidationError(self.error_messages['checksum'])
return u'%s' % value
def has_valid_checksum(self, number):
@@ -142,9 +152,10 @@ class PLPostalCodeField(RegexField):
A form field that validates as Polish postal code.
Valid code is XX-XXX where X is digit.
"""
+ default_error_messages = {
+ 'invalid': _(u'Enter a postal code in the format XX-XXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
- max_length=None, min_length=None,
- error_message=_(u'Enter a postal code in the format XX-XXX.'),
- *args, **kwargs)
-
+ max_length=None, min_length=None, *args, **kwargs)
diff --git a/django/contrib/localflavor/sk/forms.py b/django/contrib/localflavor/sk/forms.py
index 0aa000a0a5..711d70fc2b 100644
--- a/django/contrib/localflavor/sk/forms.py
+++ b/django/contrib/localflavor/sk/forms.py
@@ -26,11 +26,13 @@ class SKPostalCodeField(RegexField):
A form field that validates its input as Slovak postal code.
Valid form is XXXXX or XXX XX, where X represents integer.
"""
+ default_error_messages = {
+ 'invalid': ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
- max_length=None, min_length=None,
- error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
def clean(self, value):
"""
diff --git a/django/contrib/localflavor/uk/forms.py b/django/contrib/localflavor/uk/forms.py
index 2b162230de..52cd7ad232 100644
--- a/django/contrib/localflavor/uk/forms.py
+++ b/django/contrib/localflavor/uk/forms.py
@@ -2,21 +2,39 @@
UK-specific Form helpers
"""
-from django.newforms.fields import RegexField, Select
+import re
+
+from django.newforms.fields import CharField, Select
+from django.newforms import ValidationError
from django.utils.translation import ugettext
-class UKPostcodeField(RegexField):
+class UKPostcodeField(CharField):
"""
A form field that validates its input is a UK postcode.
The regular expression used is sourced from the schema for British Standard
BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
+
+ The value is uppercased and a space added in the correct place, if required.
"""
- def __init__(self, *args, **kwargs):
- super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$',
- max_length=None, min_length=None,
- error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
- *args, **kwargs)
+ default_error_messages = {
+ 'invalid': ugettext(u'Enter a valid postcode.'),
+ }
+ outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
+ incode_pattern = '[0-9][ABD-HJLNP-UW-Z]{2}'
+ postcode_regex = re.compile(r'^(GIR 0AA|%s %s)$' % (outcode_pattern, incode_pattern))
+ space_regex = re.compile(r' *(%s)$' % incode_pattern)
+
+ def clean(self, value):
+ value = super(UKPostcodeField, self).clean(value)
+ if value == u'':
+ return value
+ postcode = value.upper().strip()
+ # Put a single space before the incode (second part).
+ postcode = self.space_regex.sub(r' \1', postcode)
+ if not self.postcode_regex.search(postcode):
+ raise ValidationError(self.default_error_messages['invalid'])
+ return postcode
class UKCountySelect(Select):
"""
diff --git a/django/contrib/localflavor/us/forms.py b/django/contrib/localflavor/us/forms.py
index 259a7f7058..d6aa684cba 100644
--- a/django/contrib/localflavor/us/forms.py
+++ b/django/contrib/localflavor/us/forms.py
@@ -12,13 +12,19 @@ phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$")
class USZipCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
+ }
+
def __init__(self, *args, **kwargs):
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
- max_length=None, min_length=None,
- error_message=ugettext('Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
- *args, **kwargs)
+ max_length=None, min_length=None, *args, **kwargs)
class USPhoneNumberField(Field):
+ default_error_messages = {
+ 'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
+ }
+
def clean(self, value):
super(USPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
@@ -27,7 +33,7 @@ class USPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
- raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
+ raise ValidationError(self.error_messages['invalid'])
class USSocialSecurityNumberField(Field):
"""
@@ -44,28 +50,31 @@ class USSocialSecurityNumberField(Field):
promotional use or distribution (e.g., the Woolworth's number or the
1962 promotional number).
"""
+ default_error_messages = {
+ 'invalid': ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.'),
+ }
+
def clean(self, value):
super(USSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
return u''
- msg = ugettext('Enter a valid U.S. Social Security number in XXX-XX-XXXX format.')
match = re.match(ssn_re, value)
if not match:
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
# First pass: no blocks of all zeroes.
if area == '000' or \
group == '00' or \
serial == '0000':
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
# Second pass: promotional and otherwise permanently invalid numbers.
if area == '666' or \
(area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \
value == '078-05-1120' or \
value == '219-09-9999':
- raise ValidationError(msg)
+ raise ValidationError(self.error_messages['invalid'])
return u'%s-%s-%s' % (area, group, serial)
class USStateField(Field):
@@ -74,6 +83,10 @@ class USStateField(Field):
It normalizes the input to the standard two-leter postal service
abbreviation for the given state.
"""
+ default_error_messages = {
+ 'invalid': u'Enter a U.S. state or territory.',
+ }
+
def clean(self, value):
from us_states import STATES_NORMALIZED
super(USStateField, self).clean(value)
@@ -88,7 +101,7 @@ class USStateField(Field):
return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError:
pass
- raise ValidationError(u'Enter a U.S. state or territory.')
+ raise ValidationError(self.error_messages['invalid'])
class USStateSelect(Select):
"""
diff --git a/django/contrib/localflavor/za/forms.py b/django/contrib/localflavor/za/forms.py
index b04b7cf6ab..b3613b507d 100644
--- a/django/contrib/localflavor/za/forms.py
+++ b/django/contrib/localflavor/za/forms.py
@@ -16,10 +16,9 @@ class ZAIDField(Field):
using the Luhn checksum, and uses a simlistic (read: not entirely accurate)
check for the birthdate
"""
-
- def __init__(self, *args, **kwargs):
- super(ZAIDField, self).__init__()
- self.error_message = _(u'Enter a valid South African ID number')
+ default_error_messages = {
+ 'invalid': _(u'Enter a valid South African ID number'),
+ }
def clean(self, value):
# strip spaces and dashes
@@ -31,9 +30,9 @@ class ZAIDField(Field):
return u''
match = re.match(id_re, value)
-
+
if not match:
- raise ValidationError(self.error_message)
+ raise ValidationError(self.error_messages['invalid'])
g = match.groupdict()
@@ -43,15 +42,18 @@ class ZAIDField(Field):
# There is no way to guess the century of a ZA ID number
d = date(int(g['yy']) + 2000, int(g['mm']), int(g['dd']))
except ValueError:
- raise ValidationError(self.error_message)
+ raise ValidationError(self.error_messages['invalid'])
if not luhn(value):
- raise ValidationError(self.error_message)
+ raise ValidationError(self.error_messages['invalid'])
return value
class ZAPostCodeField(RegexField):
+ default_error_messages = {
+ 'invalid': _(u'Enter a valid South African postal code'),
+ }
+
def __init__(self, *args, **kwargs):
super(ZAPostCodeField, self).__init__(r'^\d{4}$',
- max_length=None, min_length=None,
- error_message=_(u'Enter a valid South African postal code'))
+ max_length=None, min_length=None)
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index 221db5cc60..a8c3c69b10 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -1,14 +1,23 @@
import os
+import tempfile
from django.conf import settings
from django.contrib.sessions.backends.base import SessionBase
-from django.core.exceptions import SuspiciousOperation
+from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
class SessionStore(SessionBase):
"""
Implements a file based session store.
"""
def __init__(self, session_key=None):
- self.storage_path = settings.SESSION_FILE_PATH
+ self.storage_path = getattr(settings, "SESSION_FILE_PATH", tempfile.gettempdir())
+
+ # Make sure the storage path is valid.
+ if not os.path.isdir(self.storage_path):
+ raise ImproperlyConfigured("The session storage path %r doesn't exist. "\
+ "Please set your SESSION_FILE_PATH setting "\
+ "to an existing directory in which Django "\
+ "can store session data." % self.storage_path)
+
self.file_prefix = settings.SESSION_COOKIE_NAME
super(SessionStore, self).__init__(session_key)
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 10bec9668b..b2c664ce7b 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -1,5 +1,6 @@
r"""
+>>> from django.conf import settings
>>> from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
>>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession
>>> from django.contrib.sessions.backends.file import SessionStore as FileSession
@@ -39,6 +40,13 @@ True
>>> file_session.exists(file_session.session_key)
False
+# Make sure the file backend checks for a good storage dir
+>>> settings.SESSION_FILE_PATH = "/if/this/directory/exists/you/have/a/weird/computer"
+>>> FileSession()
+Traceback (innermost last):
+ ...
+ImproperlyConfigured: The session storage path '/if/this/directory/exists/you/have/a/weird/computer' doesn't exist. Please set your SESSION_FILE_PATH setting to an existing directory in which Django can store session data.
+
>>> cache_session = CacheSession()
>>> cache_session.modified
False
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index 72cb877f6f..c1277bf20c 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -1,12 +1,12 @@
"File-based cache backend"
+import md5
import os, time
try:
import cPickle as pickle
except ImportError:
import pickle
from django.core.cache.backends.base import BaseCache
-from django.utils.http import urlquote_plus
class CacheClass(BaseCache):
def __init__(self, dir, params):
@@ -29,24 +29,10 @@ class CacheClass(BaseCache):
self._createdir()
def add(self, key, value, timeout=None):
- fname = self._key_to_file(key)
- if timeout is None:
- timeout = self.default_timeout
- try:
- filelist = os.listdir(self._dir)
- except (IOError, OSError):
- self._createdir()
- filelist = []
- if len(filelist) > self._max_entries:
- self._cull(filelist)
- if os.path.basename(fname) not in filelist:
- try:
- f = open(fname, 'wb')
- now = time.time()
- pickle.dump(now + timeout, f, 2)
- pickle.dump(value, f, 2)
- except (IOError, OSError):
- pass
+ if self.has_key(key):
+ return None
+
+ self.set(key, value, timeout)
def get(self, key, default=None):
fname = self._key_to_file(key)
@@ -56,7 +42,7 @@ class CacheClass(BaseCache):
now = time.time()
if exp < now:
f.close()
- os.remove(fname)
+ self._delete(fname)
else:
return pickle.load(f)
except (IOError, OSError, EOFError, pickle.PickleError):
@@ -65,40 +51,74 @@ class CacheClass(BaseCache):
def set(self, key, value, timeout=None):
fname = self._key_to_file(key)
+ dirname = os.path.dirname(fname)
+
if timeout is None:
timeout = self.default_timeout
+
+ self._cull()
+
try:
- filelist = os.listdir(self._dir)
- except (IOError, OSError):
- self._createdir()
- filelist = []
- if len(filelist) > self._max_entries:
- self._cull(filelist)
- try:
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
f = open(fname, 'wb')
now = time.time()
- pickle.dump(now + timeout, f, 2)
- pickle.dump(value, f, 2)
+ pickle.dump(now + timeout, f, pickle.HIGHEST_PROTOCOL)
+ pickle.dump(value, f, pickle.HIGHEST_PROTOCOL)
except (IOError, OSError):
pass
def delete(self, key):
try:
- os.remove(self._key_to_file(key))
+ self._delete(self._key_to_file(key))
+ except (IOError, OSError):
+ pass
+
+ def _delete(self, fname):
+ os.remove(fname)
+ try:
+ # Remove the 2 subdirs if they're empty
+ dirname = os.path.dirname(fname)
+ os.rmdir(dirname)
+ os.rmdir(os.path.dirname(dirname))
except (IOError, OSError):
pass
def has_key(self, key):
- return os.path.exists(self._key_to_file(key))
+ fname = self._key_to_file(key)
+ try:
+ f = open(fname, 'rb')
+ exp = pickle.load(f)
+ now = time.time()
+ if exp < now:
+ f.close()
+ self._delete(fname)
+ return False
+ else:
+ return True
+ except (IOError, OSError, EOFError, pickle.PickleError):
+ return False
- def _cull(self, filelist):
+ def _cull(self):
+ if int(self._num_entries) < self._max_entries:
+ return
+
+ try:
+ filelist = os.listdir(self._dir)
+ except (IOError, OSError):
+ return
+
if self._cull_frequency == 0:
doomed = filelist
else:
- doomed = [k for (i, k) in enumerate(filelist) if i % self._cull_frequency == 0]
- for fname in doomed:
+ doomed = [os.path.join(self._dir, k) for (i, k) in enumerate(filelist) if i % self._cull_frequency == 0]
+
+ for topdir in doomed:
try:
- os.remove(os.path.join(self._dir, fname))
+ for root, _, files in os.walk(topdir):
+ for f in files:
+ self._delete(os.path.join(root, f))
except (IOError, OSError):
pass
@@ -109,4 +129,22 @@ class CacheClass(BaseCache):
raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir
def _key_to_file(self, key):
- return os.path.join(self._dir, urlquote_plus(key))
+ """
+ Convert the filename into an md5 string. We'll turn the first couple
+ bits of the path into directory prefixes to be nice to filesystems
+ that have problems with large numbers of files in a directory.
+
+ Thus, a cache key of "foo" gets turnned into a file named
+ ``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
+ """
+ path = md5.new(key.encode('utf-8')).hexdigest()
+ path = os.path.join(path[:2], path[2:4], path[4:])
+ return os.path.join(self._dir, path)
+
+ def _get_num_entries(self):
+ count = 0
+ for _,_,files in os.walk(self._dir):
+ count += len(files)
+ return count
+ _num_entries = property(_get_num_entries)
+
diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
index 2734cef86a..e8e1e0d450 100644
--- a/django/core/cache/backends/locmem.py
+++ b/django/core/cache/backends/locmem.py
@@ -29,51 +29,38 @@ class CacheClass(BaseCache):
self._lock = RWLock()
- def _add(self, key, value, timeout=None):
- if len(self._cache) >= self._max_entries:
- self._cull()
- if timeout is None:
- timeout = self.default_timeout
- if key not in self._cache.keys():
- self._cache[key] = value
- self._expire_info[key] = time.time() + timeout
-
def add(self, key, value, timeout=None):
self._lock.writer_enters()
- # Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try:
- try:
- self._add(key, pickle.dumps(value), timeout)
- except pickle.PickleError:
- pass
+ exp = self._expire_info.get(key)
+ if exp is None or exp <= time.time():
+ try:
+ self._set(key, pickle.dumps(value), timeout)
+ except pickle.PickleError:
+ pass
finally:
self._lock.writer_leaves()
def get(self, key, default=None):
- should_delete = False
self._lock.reader_enters()
try:
- now = time.time()
exp = self._expire_info.get(key)
if exp is None:
return default
- elif exp < now:
- should_delete = True
- else:
+ elif exp > time.time():
try:
return pickle.loads(self._cache[key])
except pickle.PickleError:
return default
finally:
self._lock.reader_leaves()
- if should_delete:
- self._lock.writer_enters()
- try:
- del self._cache[key]
- del self._expire_info[key]
- return default
- finally:
- self._lock.writer_leaves()
+ self._lock.writer_enters()
+ try:
+ del self._cache[key]
+ del self._expire_info[key]
+ return default
+ finally:
+ self._lock.writer_leaves()
def _set(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries:
@@ -95,7 +82,23 @@ class CacheClass(BaseCache):
self._lock.writer_leaves()
def has_key(self, key):
- return key in self._cache
+ self._lock.reader_enters()
+ try:
+ exp = self._expire_info.get(key)
+ if exp is None:
+ return False
+ elif exp > time.time():
+ return True
+ finally:
+ self._lock.reader_leaves()
+
+ self._lock.writer_enters()
+ try:
+ del self._cache[key]
+ del self._expire_info[key]
+ return False
+ finally:
+ self._lock.writer_leaves()
def _cull(self):
if self._cull_frequency == 0:
diff --git a/django/core/mail.py b/django/core/mail.py
index 77ab8007e6..e408393d96 100644
--- a/django/core/mail.py
+++ b/django/core/mail.py
@@ -209,8 +209,14 @@ class EmailMessage(object):
bytestrings). The SafeMIMEText class will handle any necessary encoding
conversions.
"""
- self.to = to or []
- self.bcc = bcc or []
+ if to:
+ self.to = list(to)
+ else:
+ self.to = []
+ if bcc:
+ self.bcc = list(bcc)
+ else:
+ self.bcc = []
self.from_email = from_email or settings.DEFAULT_FROM_EMAIL
self.subject = subject
self.body = body
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index ee0eb6fda8..d78e2eda0b 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -10,7 +10,7 @@ from django.core.management.base import BaseCommand, CommandError, handle_defaul
get_version = django.get_version
# A cache of loaded commands, so that call_command
-# doesn't have to reload every time it is called
+# doesn't have to reload every time it's called.
_commands = None
def find_commands(management_dir):
@@ -29,8 +29,8 @@ def find_commands(management_dir):
def find_management_module(app_name):
"""
- Determines the path to the management module for the application named,
- without acutally importing the application or the management module.
+ Determines the path to the management module for the given app_name,
+ without actually importing the application or the management module.
Raises ImportError if the management module cannot be found for any reason.
"""
@@ -46,19 +46,19 @@ def find_management_module(app_name):
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns the Command
- class instance. All errors raised by the importation process
+ class instance. All errors raised by the import process
(ImportError, AttributeError) are allowed to propagate.
"""
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
{}, {}, ['Command']), 'Command')()
-def get_commands():
+def get_commands(load_user_commands=True, project_directory=None):
"""
- Returns a dictionary of commands against the application in which
- those commands can be found. This works by looking for a
- management.commands package in django.core, and in each installed
- application -- if a commands package exists, all commands in that
- package are registered.
+ Returns a dictionary mapping command names to their callback applications.
+
+ This works by looking for a management.commands package in django.core, and
+ in each installed application -- if a commands package exists, all commands
+ in that package are registered.
Core commands are always included. If a settings module has been
specified, user-defined commands will also be included, the
@@ -73,34 +73,22 @@ def get_commands():
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
- The dictionary is cached on the first call, and reused on subsequent
+ The dictionary is cached on the first call and reused on subsequent
calls.
"""
global _commands
if _commands is None:
- _commands = dict([(name, 'django.core')
- for name in find_commands(__path__[0])])
- # Get commands from all installed apps.
- try:
- from django.conf import settings
- apps = settings.INSTALLED_APPS
- except (AttributeError, ImportError):
- apps = []
+ _commands = dict([(name, 'django.core') for name in find_commands(__path__[0])])
- for app_name in apps:
- try:
- path = find_management_module(app_name)
- _commands.update(dict([(name, app_name)
- for name in find_commands(path)]))
- except ImportError:
- pass # No management module - ignore this app
-
- # Try to determine the project directory
- try:
+ if load_user_commands:
+ # Get commands from all installed apps.
from django.conf import settings
- project_directory = setup_environ(__import__(settings.SETTINGS_MODULE))
- except (AttributeError, ImportError):
- project_directory = None
+ for app_name in settings.INSTALLED_APPS:
+ try:
+ path = find_management_module(app_name)
+ _commands.update(dict([(name, app_name) for name in find_commands(path)]))
+ except ImportError:
+ pass # No management module -- ignore this app.
if project_directory:
# Remove the "startproject" command from self.commands, because
@@ -157,18 +145,18 @@ class ManagementUtility(object):
def __init__(self, argv=None):
self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0])
+ self.project_directory = None
+ self.user_commands = False
def main_help_text(self):
"""
Returns the script's main help text, as a string.
"""
usage = ['%s <subcommand> [options] [args]' % self.prog_name]
- usage.append('Django command line tool,'
- ' version %s' % django.get_version())
- usage.append("Type '%s help <subcommand>' for help on a specific"
- " subcommand." % self.prog_name)
+ usage.append('Django command line tool, version %s' % django.get_version())
+ usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name)
usage.append('Available subcommands:')
- commands = get_commands().keys()
+ commands = get_commands(self.user_commands, self.project_directory).keys()
commands.sort()
for cmd in commands:
usage.append(' %s' % cmd)
@@ -178,18 +166,18 @@ class ManagementUtility(object):
"""
Tries to fetch the given subcommand, printing a message with the
appropriate command called from the command line (usually
- django-admin.py or manage.py) if it can't be found.
+ "django-admin.py" or "manage.py") if it can't be found.
"""
try:
- app_name = get_commands()[subcommand]
+ app_name = get_commands(self.user_commands, self.project_directory)[subcommand]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
else:
klass = load_command_class(app_name, subcommand)
except KeyError:
- sys.stderr.write("Unknown command: %r\nType '%s help' for"
- " usage.\n" % (subcommand, self.prog_name))
+ sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % \
+ (subcommand, self.prog_name))
sys.exit(1)
return klass
@@ -201,8 +189,7 @@ class ManagementUtility(object):
# Preprocess options to extract --settings and --pythonpath.
# These options could affect the commands that are available, so they
# must be processed early.
- parser = LaxOptionParser(version=get_version(),
- option_list=BaseCommand.option_list)
+ parser = LaxOptionParser(version=get_version(), option_list=BaseCommand.option_list)
try:
options, args = parser.parse_args(self.argv)
handle_default_options(options)
@@ -242,6 +229,8 @@ class ProjectManagementUtility(ManagementUtility):
"""
def __init__(self, argv, project_directory):
super(ProjectManagementUtility, self).__init__(argv)
+ self.project_directory = project_directory
+ self.user_commands = True
def setup_environ(settings_mod):
"""
@@ -263,8 +252,7 @@ def setup_environ(settings_mod):
sys.path.pop()
# Set DJANGO_SETTINGS_MODULE appropriately.
- os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name,
- settings_name)
+ os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
return project_directory
def execute_from_command_line(argv=None):
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 31c2849075..7b8a3e987f 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -27,6 +27,8 @@ class BaseCommand(object):
help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.'),
make_option('--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
+ make_option('--traceback', action='store_true',
+ help='Print traceback on exception'),
)
help = ''
args = ''
diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py
index 7bdcc4271f..2642ae925e 100644
--- a/django/core/management/commands/dumpdata.py
+++ b/django/core/management/commands/dumpdata.py
@@ -1,11 +1,12 @@
from django.core.management.base import BaseCommand, CommandError
+from django.core import serializers
from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--format', default='json', dest='format',
- help='Specifies the output serialization format for fixtures'),
+ help='Specifies the output serialization format for fixtures.'),
make_option('--indent', default=None, dest='indent', type='int',
help='Specifies the indent level to use when pretty-printing output'),
)
@@ -14,10 +15,10 @@ class Command(BaseCommand):
def handle(self, *app_labels, **options):
from django.db.models import get_app, get_apps, get_models
- from django.core import serializers
format = options.get('format', 'json')
indent = options.get('indent', None)
+ show_traceback = options.get('traceback', False)
if len(app_labels) == 0:
app_list = get_apps()
@@ -26,6 +27,9 @@ class Command(BaseCommand):
# Check that the serialization format exists; this is a shortcut to
# avoid collating all the objects and _then_ failing.
+ if format not in serializers.get_public_serializer_formats():
+ raise CommandError("Unknown serialization format: %s" % format)
+
try:
serializers.get_serializer(format)
except KeyError:
@@ -34,8 +38,10 @@ class Command(BaseCommand):
objects = []
for app in app_list:
for model in get_models(app):
- objects.extend(model.objects.all())
+ objects.extend(model._default_manager.all())
try:
return serializers.serialize(format, objects, indent=indent)
except Exception, e:
+ if show_traceback:
+ raise
raise CommandError("Unable to serialize database: %s" % e)
diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
index 83fc9b8ac9..fb0325906d 100644
--- a/django/core/management/commands/loaddata.py
+++ b/django/core/management/commands/loaddata.py
@@ -27,6 +27,7 @@ class Command(BaseCommand):
self.style = no_style()
verbosity = int(options.get('verbosity', 1))
+ show_traceback = options.get('traceback', False)
# Keep a count of the installed objects and fixtures
count = [0, 0]
@@ -50,15 +51,15 @@ class Command(BaseCommand):
parts = fixture_label.split('.')
if len(parts) == 1:
fixture_name = fixture_label
- formats = serializers.get_serializer_formats()
+ formats = serializers.get_public_serializer_formats()
else:
fixture_name, format = '.'.join(parts[:-1]), parts[-1]
- if format in serializers.get_serializer_formats():
+ if format in serializers.get_public_serializer_formats():
formats = [format]
else:
formats = []
- if verbosity > 0:
+ if verbosity > 2:
if formats:
print "Loading '%s' fixtures..." % fixture_name
else:
@@ -98,15 +99,17 @@ class Command(BaseCommand):
label_found = True
except Exception, e:
fixture.close()
+ transaction.rollback()
+ transaction.leave_transaction_management()
+ if show_traceback:
+ raise
sys.stderr.write(
self.style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, str(e))))
- transaction.rollback()
- transaction.leave_transaction_management()
return
fixture.close()
except:
- if verbosity > 1:
+ if verbosity > 2:
print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir))
@@ -122,7 +125,7 @@ class Command(BaseCommand):
transaction.leave_transaction_management()
if count[0] == 0:
- if verbosity > 0:
+ if verbosity > 2:
print "No fixtures found."
else:
if verbosity > 0:
diff --git a/django/core/management/sql.py b/django/core/management/sql.py
index 43918ef1c2..767a2dbbfb 100644
--- a/django/core/management/sql.py
+++ b/django/core/management/sql.py
@@ -116,6 +116,7 @@ def sql_delete(app, style):
"Returns a list of the DROP TABLE SQL statements for the given app."
from django.db import connection, models, get_introspection_module
from django.db.backends.util import truncate_name
+ from django.contrib.contenttypes import generic
introspection = get_introspection_module()
# This should work even if a connection isn't available
@@ -179,6 +180,8 @@ def sql_delete(app, style):
for model in app_models:
opts = model._meta
for f in opts.many_to_many:
+ if isinstance(f.rel, generic.GenericRel):
+ continue
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(qn(f.m2m_db_table()))))
diff --git a/django/core/serializers/__init__.py b/django/core/serializers/__init__.py
index 1e24e2bd22..47dfb0c87a 100644
--- a/django/core/serializers/__init__.py
+++ b/django/core/serializers/__init__.py
@@ -53,6 +53,11 @@ def get_serializer_formats():
_load_serializers()
return _serializers.keys()
+def get_public_serializer_formats():
+ if not _serializers:
+ _load_serializers()
+ return [k for k, v in _serializers.iteritems() if not v.Serializer.internal_use_only]
+
def get_deserializer(format):
if not _serializers:
_load_serializers()
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index ee9e4dd621..3c7dcfa02e 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -22,6 +22,10 @@ class Serializer(object):
Abstract serializer base class.
"""
+ # Indicates if the implemented serializer is only available for
+ # internal Django use.
+ internal_use_only = False
+
def serialize(self, queryset, **options):
"""
Serialize a queryset.
diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py
index fa2dca7295..e17b821f52 100644
--- a/django/core/serializers/json.py
+++ b/django/core/serializers/json.py
@@ -20,6 +20,8 @@ class Serializer(PythonSerializer):
"""
Convert a queryset to JSON.
"""
+ internal_use_only = False
+
def end_serialization(self):
self.options.pop('stream', None)
self.options.pop('fields', None)
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index 6fc13d76b5..cedab06be9 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -13,7 +13,9 @@ class Serializer(base.Serializer):
"""
Serializes a QuerySet to basic Python objects.
"""
-
+
+ internal_use_only = True
+
def start_serialization(self):
self._current = None
self.objects = []
diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py
index 92159dbbe3..4c32a9686f 100644
--- a/django/core/serializers/pyyaml.py
+++ b/django/core/serializers/pyyaml.py
@@ -5,6 +5,7 @@ Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
"""
import datetime
+from django.db import models
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
try:
@@ -17,10 +18,25 @@ class Serializer(PythonSerializer):
"""
Convert a queryset to YAML.
"""
+
+ internal_use_only = False
+
+ def handle_field(self, obj, field):
+ # A nasty special case: base YAML doesn't support serialization of time
+ # types (as opposed to dates or datetimes, which it does support). Since
+ # we want to use the "safe" serializer for better interoperability, we
+ # need to do something with those pesky times. Converting 'em to strings
+ # isn't perfect, but it's better than a "!!python/time" type which would
+ # halt deserialization under any other language.
+ if isinstance(field, models.TimeField) and getattr(obj, field.name) is not None:
+ self._current[field.name] = str(getattr(obj, field.name))
+ else:
+ super(Serializer, self).handle_field(obj, field)
+
def end_serialization(self):
self.options.pop('stream', None)
self.options.pop('fields', None)
- yaml.dump(self.objects, self.stream, **self.options)
+ yaml.safe_dump(self.objects, self.stream, **self.options)
def getvalue(self):
return self.stream.getvalue()
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index e98957da2c..05f8756655 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -398,8 +398,20 @@ class ServerHandler(object):
self.bytes_sent += len(data)
# 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):
"""Platform-specific file transmission
diff --git a/django/db/__init__.py b/django/db/__init__.py
index e16de07416..95dd36822e 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -36,8 +36,8 @@ except ImportError, e:
raise # If there's some other error, this must be an error in Django itself.
def _import_database_module(import_path='', module_name=''):
- """Lazyily import a database module when requested."""
- return __import__('%s%s.%s' % (_import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])
+ """Lazily import a database module when requested."""
+ return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])
# We don't want to import the introspect module unless someone asks for it, so
# lazily load it on demmand.
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 24fda78427..cd830413fc 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -455,6 +455,23 @@ class FormatStylePlaceholderCursor(Database.Cursor):
else:
return tuple([smart_str(p, self.charset, True) for p in params])
+ def _guess_input_sizes(self, params_list):
+ # Mark any string parameter greater than 4000 characters as an NCLOB.
+ if isinstance(params_list[0], dict):
+ sizes = {}
+ iterators = [params.iteritems() for params in params_list]
+ else:
+ sizes = [None] * len(params_list[0])
+ iterators = [enumerate(params) for params in params_list]
+ for iterator in iterators:
+ for key, value in iterator:
+ if isinstance(value, basestring) and len(value) > 4000:
+ sizes[key] = Database.NCLOB
+ if isinstance(sizes, dict):
+ self.setinputsizes(**sizes)
+ else:
+ self.setinputsizes(*sizes)
+
def execute(self, query, params=None):
if params is None:
params = []
@@ -468,6 +485,7 @@ class FormatStylePlaceholderCursor(Database.Cursor):
if query.endswith(';') or query.endswith('/'):
query = query[:-1]
query = smart_str(query, self.charset) % tuple(args)
+ self._guess_input_sizes([params])
return Database.Cursor.execute(self, query, params)
def executemany(self, query, params=None):
@@ -484,6 +502,7 @@ class FormatStylePlaceholderCursor(Database.Cursor):
query = query[:-1]
query = smart_str(query, self.charset) % tuple(args)
new_param_list = [self._format_params(i) for i in params]
+ self._guess_input_sizes(new_param_list)
return Database.Cursor.executemany(self, query, new_param_list)
def fetchone(self):
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index ca92d8ae73..84537bf2dc 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -717,7 +717,7 @@ class EmailField(CharField):
class FileField(Field):
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
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)
def get_db_prep_save(self, value):
@@ -913,6 +913,11 @@ class NullBooleanField(Field):
def get_manipulator_field_objs(self):
return [oldforms.NullBooleanField]
+ def formfield(self, **kwargs):
+ defaults = {'form_class': forms.NullBooleanField}
+ defaults.update(kwargs)
+ return super(NullBooleanField, self).formfield(**defaults)
+
class PhoneNumberField(IntegerField):
def get_manipulator_field_objs(self):
return [oldforms.PhoneNumberField]
@@ -929,11 +934,11 @@ class PhoneNumberField(IntegerField):
class PositiveIntegerField(IntegerField):
def get_manipulator_field_objs(self):
return [oldforms.PositiveIntegerField]
-
+
def formfield(self, **kwargs):
defaults = {'min_value': 0}
defaults.update(kwargs)
- return super(PositiveIntegerField, self).formfield(**defaults)
+ return super(PositiveIntegerField, self).formfield(**defaults)
class PositiveSmallIntegerField(IntegerField):
def get_manipulator_field_objs(self):
@@ -942,7 +947,7 @@ class PositiveSmallIntegerField(IntegerField):
def formfield(self, **kwargs):
defaults = {'min_value': 0}
defaults.update(kwargs)
- return super(PositiveSmallIntegerField, self).formfield(**defaults)
+ return super(PositiveSmallIntegerField, self).formfield(**defaults)
class SlugField(CharField):
def __init__(self, *args, **kwargs):
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 47f9736ce2..69e9d51204 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -277,7 +277,20 @@ class HttpResponse(object):
for key, value in self._headers.values()]) \
+ '\n\n' + self.content
+ def _convert_to_ascii(self, *values):
+ "Convert all values to ascii strings"
+ for value in values:
+ if isinstance(value, unicode):
+ try:
+ yield value.encode('us-ascii')
+ except UnicodeError, e:
+ e.reason += ', HTTP response headers must be in US-ASCII format'
+ raise
+ else:
+ yield str(value)
+
def __setitem__(self, header, value):
+ header, value = self._convert_to_ascii(header, value)
self._headers[header.lower()] = (header, value)
def __delitem__(self, header):
@@ -331,7 +344,7 @@ class HttpResponse(object):
chunk = self._iterator.next()
if isinstance(chunk, unicode):
chunk = chunk.encode(self._charset)
- return chunk
+ return str(chunk)
def close(self):
if hasattr(self._container, 'close'):
diff --git a/django/newforms/fields.py b/django/newforms/fields.py
index 58f65ffde5..3b8f4195b0 100644
--- a/django/newforms/fields.py
+++ b/django/newforms/fields.py
@@ -533,8 +533,8 @@ class BooleanField(Field):
"""Returns a Python boolean object."""
super(BooleanField, self).clean(value)
# Explicitly check for the string 'False', which is what a hidden field
- # will submit for False (since bool("True") == True we don't need to
- # handle that explicitly).
+ # will submit for False. Because bool("True") == True, we don't need to
+ # handle that explicitly.
if value == 'False':
return False
return bool(value)
diff --git a/django/newforms/models.py b/django/newforms/models.py
index 4eb61761a1..fd0087a3b1 100644
--- a/django/newforms/models.py
+++ b/django/newforms/models.py
@@ -84,9 +84,8 @@ def form_for_model(model, form=BaseForm, fields=None,
determining the formfield for a given database field. It's a callable that
takes a database Field instance and returns a form Field instance.
"""
- warn("form_for_model is deprecated, use ModelForm instead.",
- PendingDeprecationWarning,
- stacklevel=3)
+ warn("form_for_model is deprecated. Use ModelForm instead.",
+ PendingDeprecationWarning, stacklevel=3)
opts = model._meta
field_list = []
for f in opts.fields + opts.many_to_many:
@@ -114,9 +113,8 @@ def form_for_instance(instance, form=BaseForm, fields=None,
takes a database Field instance, plus **kwargs, and returns a form Field
instance with the given kwargs (i.e. 'initial').
"""
- warn("form_for_instance is deprecated, use ModelForm instead.",
- PendingDeprecationWarning,
- stacklevel=3)
+ warn("form_for_instance is deprecated. Use ModelForm instead.",
+ PendingDeprecationWarning, stacklevel=3)
model = instance.__class__
opts = model._meta
field_list = []
@@ -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
a Form's ``initial`` keyword argument.
-
+
``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned dict.
-
+
``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
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 will be included in the returned fields.
-
+
``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
in the ``fields`` argument.
@@ -214,9 +212,8 @@ class ModelFormOptions(object):
self.exclude = getattr(options, 'exclude', None)
class ModelFormMetaclass(type):
- def __new__(cls, name, bases, attrs):
- # TODO: no way to specify formfield_callback yet, do we need one, or
- # should it be a special case for the admin?
+ def __new__(cls, name, bases, attrs,
+ formfield_callback=lambda f: f.formfield()):
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
@@ -245,15 +242,16 @@ class ModelFormMetaclass(type):
# If a model is defined, extract form fields from it and add them to base_fields
if attrs['_meta'].model is not None:
- # Don't allow a subclass to define a Meta model if a parent class has.
- # Technically the right fields would be generated, but the save
- # method will not deal with more than one model.
+ # Don't allow a subclass to define a different Meta model than a
+ # parent class has. Technically the right fields would be generated,
+ # but the save method will not deal with more than one model.
for base in bases:
base_opts = getattr(base, '_meta', None)
base_model = getattr(base_opts, 'model', None)
- if base_model is not None:
- raise ImproperlyConfigured('%s defines more than one model.' % name)
- model_fields = fields_for_model(opts.model, opts.fields, opts.exclude)
+ if base_model and base_model is not opts.model:
+ raise ImproperlyConfigured('%s defines a different model than its parent.' % name)
+ model_fields = fields_for_model(opts.model, opts.fields,
+ opts.exclude, formfield_callback)
# fields declared in base classes override fields from the model
model_fields.update(declared_fields)
attrs['base_fields'] = model_fields
@@ -262,11 +260,16 @@ class ModelFormMetaclass(type):
return type.__new__(cls, name, bases, attrs)
class BaseModelForm(BaseForm):
- def __init__(self, instance, data=None, files=None, auto_id='id_%s', prefix=None,
- initial=None, error_class=ErrorList, label_suffix=':'):
- self.instance = instance
+ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
+ initial=None, error_class=ErrorList, label_suffix=':', instance=None):
opts = self._meta
- object_data = model_to_dict(instance, opts.fields, opts.exclude)
+ if instance is None:
+ # if we didn't get an instance, instantiate a new one
+ self.instance = opts.model()
+ object_data = {}
+ else:
+ self.instance = instance
+ object_data = model_to_dict(instance, opts.fields, opts.exclude)
# if initial was provided, it should override the values from instance
if initial is not None:
object_data.update(initial)
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index ac92bef6cf..5cee0ab244 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -43,7 +43,11 @@ def stringfilter(func):
def addslashes(value):
- """Adds slashes - useful for passing strings to JavaScript, for example."""
+ """
+ Adds slashes before quotes. Useful for escaping strings in CSV, for
+ example. Less useful for escaping JavaScript; use the ``escapejs``
+ filter instead.
+ """
return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
addslashes.is_safe = True
addslashes = stringfilter(addslashes)
@@ -54,6 +58,25 @@ def capfirst(value):
capfirst.is_safe=True
capfirst = stringfilter(capfirst)
+_js_escapes = (
+ ('\\', '\\\\'),
+ ('"', '\\"'),
+ ("'", "\\'"),
+ ('\n', '\\n'),
+ ('\r', '\\r'),
+ ('\b', '\\b'),
+ ('\f', '\\f'),
+ ('\t', '\\t'),
+ ('\v', '\\v'),
+ ('</', '<\\/'),
+)
+def escapejs(value):
+ """Backslash-escapes characters for use in JavaScript strings."""
+ for bad, good in _js_escapes:
+ value = value.replace(bad, good)
+ return value
+escapejs = stringfilter(escapejs)
+
def fix_ampersands(value):
"""Replaces ampersands with ``&amp;`` entities."""
from django.utils.html import fix_ampersands
@@ -231,7 +254,7 @@ urlize.is_safe=True
urlize.needs_autoescape = True
urlize = stringfilter(urlize)
-def urlizetrunc(value, limit):
+def urlizetrunc(value, limit, autoescape=None):
"""
Converts URLs into clickable links, truncating URLs to the given character
limit, and adding 'rel=nofollow' attribute to discourage spamming.
@@ -239,8 +262,10 @@ def urlizetrunc(value, limit):
Argument: Length to truncate URLs to.
"""
from django.utils.html import urlize
- return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True))
+ return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True,
+ autoescape=autoescape))
urlizetrunc.is_safe = True
+urlizetrunc.needs_autoescape = True
urlizetrunc = stringfilter(urlizetrunc)
def wordcount(value):
@@ -766,6 +791,7 @@ register.filter(dictsort)
register.filter(dictsortreversed)
register.filter(divisibleby)
register.filter(escape)
+register.filter(escapejs)
register.filter(filesizeformat)
register.filter(first)
register.filter(fix_ampersands)
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index d91e30bbb5..813e5dbed6 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -814,7 +814,7 @@ def ssi(parser, token):
Outputs the contents of a given file into the page.
Like a simple "include" tag, the ``ssi`` tag includes the contents
- of another file -- which must be specified using an absolute page --
+ of another file -- which must be specified using an absolute path --
in the current page::
{% ssi /home/html/ljworld.com/includes/right_generic.html %}
diff --git a/django/test/utils.py b/django/test/utils.py
index 51ca37e2f0..b1c528873c 100644
--- a/django/test/utils.py
+++ b/django/test/utils.py
@@ -1,4 +1,4 @@
-import sys, time
+import sys, time, os
from django.conf import settings
from django.db import connection, get_creation_module
from django.core import mail
@@ -106,9 +106,32 @@ def create_test_db(verbosity=1, autoclobber=False):
if verbosity >= 1:
print "Creating test database..."
# If we're using SQLite, it's more convenient to test against an
- # in-memory database.
+ # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose
+ # to run on a physical database.
if settings.DATABASE_ENGINE == "sqlite3":
- 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:
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)
return
- # Unless we're using SQLite, remove the test database to clean up after
- # ourselves. Connect to the previous database (not the test database)
- # to do so, because it's not allowed to delete a database while being
- # connected to it.
if verbosity >= 1:
print "Destroying test database..."
connection.close()
TEST_DATABASE_NAME = settings.DATABASE_NAME
settings.DATABASE_NAME = old_database_name
-
- if settings.DATABASE_ENGINE != "sqlite3":
+ if settings.DATABASE_ENGINE == "sqlite3":
+ if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":
+ # Remove the SQLite database file
+ os.remove(TEST_DATABASE_NAME)
+ else:
+ # Remove the test database to clean up after
+ # ourselves. Connect to the previous database (not the test database)
+ # to do so, because it's not allowed to delete a database while being
+ # connected to it.
cursor = connection.cursor()
_set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors.
diff --git a/django/utils/html.py b/django/utils/html.py
index 34bbf7357f..33e2ee3856 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -1,4 +1,4 @@
-"HTML utilities suitable for global use."
+"""HTML utilities suitable for global use."""
import re
import string
@@ -8,11 +8,11 @@ from django.utils.encoding import force_unicode
from django.utils.functional import allow_lazy
from django.utils.http import urlquote
-# Configuration for urlize() function
+# Configuration for urlize() function.
LEADING_PUNCTUATION = ['(', '<', '&lt;']
TRAILING_PUNCTUATION = ['.', ',', ')', '>', '\n', '&gt;']
-# list of possible strings used for bullets in bulleted lists
+# List of possible strings used for bullets in bulleted lists.
DOTS = ['&middot;', '*', '\xe2\x80\xa2', '&#149;', '&bull;', '&#8226;']
unencoded_ampersands_re = re.compile(r'&(?!(\w+|#\d+);)')
@@ -28,7 +28,7 @@ trailing_empty_content_re = re.compile(r'(?:<p>(?:&nbsp;|\s|<br \/>)*?</p>\s*)+\
del x # Temporary variable
def escape(html):
- "Return the given HTML with ampersands, quotes and carets encoded."
+ """Returns the given HTML with ampersands, quotes and carets encoded."""
return mark_safe(force_unicode(html).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))
escape = allow_lazy(escape, unicode)
@@ -42,7 +42,7 @@ def conditional_escape(html):
return escape(html)
def linebreaks(value, autoescape=False):
- "Converts newlines into <p> and <br />s"
+ """Converts newlines into <p> and <br />s."""
value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines
paras = re.split('\n{2,}', value)
if autoescape:
@@ -50,31 +50,31 @@ def linebreaks(value, autoescape=False):
else:
paras = [u'<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
return u'\n\n'.join(paras)
-linebreaks = allow_lazy(linebreaks, unicode)
+linebreaks = allow_lazy(linebreaks, unicode)
def strip_tags(value):
- "Return the given HTML with all tags stripped."
+ """Returns the given HTML with all tags stripped."""
return re.sub(r'<[^>]*?>', '', force_unicode(value))
strip_tags = allow_lazy(strip_tags)
def strip_spaces_between_tags(value):
- "Return the given HTML with spaces between tags removed."
+ """Returns the given HTML with spaces between tags removed."""
return re.sub(r'>\s+<', '><', force_unicode(value))
strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, unicode)
def strip_entities(value):
- "Return the given HTML with all entities (&something;) stripped."
+ """Returns the given HTML with all entities (&something;) stripped."""
return re.sub(r'&(?:\w+|#\d+);', '', force_unicode(value))
strip_entities = allow_lazy(strip_entities, unicode)
def fix_ampersands(value):
- "Return the given HTML with all unencoded ampersands encoded correctly."
+ """Returns the given HTML with all unencoded ampersands encoded correctly."""
return unencoded_ampersands_re.sub('&amp;', force_unicode(value))
fix_ampersands = allow_lazy(fix_ampersands, unicode)
def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
"""
- Convert any URLs in text into clickable links.
+ Converts any URLs in text into clickable links.
Works on http://, https://, and www. links. Links can have trailing
punctuation (periods, commas, close-parens) and leading punctuation
diff --git a/django/utils/maxlength.py b/django/utils/maxlength.py
index 1df6a3e93e..a616541f85 100644
--- a/django/utils/maxlength.py
+++ b/django/utils/maxlength.py
@@ -1,6 +1,6 @@
"""
Utilities for providing backwards compatibility for the maxlength argument,
-which has been replaced by max_length, see ticket #2101.
+which has been replaced by max_length. See ticket #2101.
"""
from warnings import warn
@@ -15,17 +15,15 @@ def legacy_maxlength(max_length, maxlength):
"""
Consolidates max_length and maxlength, providing backwards compatibilty
for the legacy "maxlength" argument.
+
If one of max_length or maxlength is given, then that value is returned.
- If both are given, a TypeError is raised.
- If maxlength is used at all, a deprecation warning is issued.
+ If both are given, a TypeError is raised. If maxlength is used at all, a
+ deprecation warning is issued.
"""
if maxlength is not None:
- warn("maxlength is deprecated, use max_length instead.",
- DeprecationWarning,
- stacklevel=3)
+ warn("maxlength is deprecated. Use max_length instead.", DeprecationWarning, stacklevel=3)
if max_length is not None:
- raise TypeError("field can not take both the max_length"
- " argument and the legacy maxlength argument.")
+ raise TypeError("Field cannot take both the max_length argument and the legacy maxlength argument.")
max_length = maxlength
return max_length
@@ -33,7 +31,8 @@ def remove_maxlength(func):
"""
A decorator to be used on a class's __init__ that provides backwards
compatibilty for the legacy "maxlength" keyword argument, i.e.
- name = models.CharField(maxlength=20)
+ name = models.CharField(maxlength=20)
+
It does this by changing the passed "maxlength" keyword argument
(if it exists) into a "max_length" keyword argument.
"""
@@ -58,7 +57,6 @@ class LegacyMaxlength(type):
Metaclass for providing backwards compatibility support for the
"maxlength" keyword argument.
"""
-
def __init__(cls, name, bases, attrs):
super(LegacyMaxlength, cls).__init__(name, bases, attrs)
# Decorate the class's __init__ to remove any maxlength keyword.
diff --git a/django/views/debug.py b/django/views/debug.py
index fba43912bb..18a396d3a6 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -1,9 +1,12 @@
+import os
+import re
+import sys
+
from django.conf import settings
from django.template import Template, Context, TemplateDoesNotExist
from django.utils.html import escape
from django.http import HttpResponseServerError, HttpResponseNotFound
from django.utils.encoding import smart_unicode
-import os, re, sys
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
@@ -142,9 +145,10 @@ def technical_500_response(request, exc_type, exc_value, tb):
'request': request,
'request_protocol': request.is_secure() and "https" or "http",
'settings': get_safe_settings(),
- 'sys_executable' : sys.executable,
- 'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3],
- 'django_version_info' : get_version(),
+ 'sys_executable': sys.executable,
+ 'sys_version_info': '%d.%d.%d' % sys.version_info[0:3],
+ 'django_version_info': get_version(),
+ 'sys_path' : sys.path,
'template_info': template_info,
'template_does_not_exist': template_does_not_exist,
'loader_debug_info': loader_debug_info,
@@ -230,8 +234,8 @@ TECHNICAL_500_TEMPLATE = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
- <meta name="robots" content="NONE,NOARCHIVE" />
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="robots" content="NONE,NOARCHIVE">
<title>{{ exception_type }} at {{ request.path|escape }}</title>
<style type="text/css">
html * { padding:0; margin:0; }
@@ -368,6 +372,10 @@ TECHNICAL_500_TEMPLATE = """
<th>Python Version:</th>
<td>{{ sys_version_info }}</td>
</tr>
+ <tr>
+ <th>Python Path:</th>
+ <td>{{ sys_path }}</td>
+ </tr>
</table>
</div>
{% if unicode_hint %}
@@ -460,10 +468,10 @@ TECHNICAL_500_TEMPLATE = """
{% endautoescape %}
<form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post">
<div id="pastebinTraceback" class="pastebin">
- <input type="hidden" name="language" value="PythonConsole" />
- <input type="hidden" name="title" value="{{ exception_type|escape }} at {{ request.path|escape }}" />
- <input type="hidden" name="source" value="Django Dpaste Agent" />
- <input type="hidden" name="poster" value="Django" />
+ <input type="hidden" name="language" value="PythonConsole">
+ <input type="hidden" name="title" value="{{ exception_type|escape }} at {{ request.path|escape }}">
+ <input type="hidden" name="source" value="Django Dpaste Agent">
+ <input type="hidden" name="poster" value="Django">
<textarea name="content" id="traceback_area" cols="140" rows="25">
Environment:
@@ -471,10 +479,10 @@ Request Method: {{ request.META.REQUEST_METHOD }}
Request URL: {{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
Django Version: {{ django_version_info }}
Python Version: {{ sys_version_info }}
-Installed Applications:
- {{ settings.INSTALLED_APPS|pprint }}
-Installed Middleware:
- {{ settings.MIDDLEWARE_CLASSES|pprint }}
+Installed Applications:
+{{ settings.INSTALLED_APPS|pprint }}
+Installed Middleware:
+{{ settings.MIDDLEWARE_CLASSES|pprint }}
{% if template_does_not_exist %}Template Loader Error:
{% if loader_debug_info %}Django tried loading these templates, in this order:
@@ -498,9 +506,9 @@ Traceback:
Exception Type: {{ exception_type|escape }} at {{ request.path|escape }}
Exception Value: {{ exception_value|escape }}
</textarea>
- <br/><br/>
+ <br><br>
+ <input type="submit" value="Share this traceback on public Web site">
</div>
-<input type="submit" value="Send to DPaste">
</form>
</div>
@@ -627,9 +635,9 @@ TECHNICAL_404_TEMPLATE = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Page not found at {{ request.path|escape }}</title>
- <meta name="robots" content="NONE,NOARCHIVE" />
+ <meta name="robots" content="NONE,NOARCHIVE">
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
diff --git a/django/views/static.py b/django/views/static.py
index 8095fc9231..5a4d3ab55c 100644
--- a/django/views/static.py
+++ b/django/views/static.py
@@ -59,10 +59,11 @@ def serve(request, path, document_root=None, show_indexes=False):
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
return HttpResponseNotModified()
- mimetype = mimetypes.guess_type(fullpath)[0]
+ mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream'
contents = open(fullpath, 'rb').read()
response = HttpResponse(contents, mimetype=mimetype)
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
+ response["Content-Length"] = len(contents)
return response
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """