summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-03-20 19:56:44 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-03-20 19:56:44 +0000
commit334279f8dd3abd98aa527a1658cb3ff5c3973ec7 (patch)
treef440439fc9f79a39cfb90c16bf5c2df0106b14ee
parent04da22633fcda983cb9ee69e63b2ebe99301b717 (diff)
downloaddjango-334279f8dd3abd98aa527a1658cb3ff5c3973ec7.tar.gz
queryset-refactor: Merged from trunk up to [7338].
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7341 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS6
-rw-r--r--django/conf/global_settings.py2
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.mobin46481 -> 48100 bytes
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.po947
-rw-r--r--django/contrib/admin/templates/admin_doc/index.html54
-rw-r--r--django/contrib/admin/templates/admin_doc/view_index.html84
-rw-r--r--django/contrib/formtools/wizard.py492
-rw-r--r--django/contrib/sessions/backends/file.py4
-rw-r--r--django/contrib/syndication/feeds.py22
-rw-r--r--django/core/management/__init__.py2
-rw-r--r--django/core/management/commands/startproject.py9
-rw-r--r--django/core/paginator.py204
-rw-r--r--django/core/serializers/base.py6
-rw-r--r--django/core/servers/fastcgi.py14
-rw-r--r--django/db/models/fields/__init__.py10
-rw-r--r--django/db/models/fields/related.py7
-rw-r--r--django/db/models/query.py16
-rw-r--r--django/http/__init__.py3
-rw-r--r--django/newforms/extras/widgets.py28
-rw-r--r--django/newforms/fields.py30
-rw-r--r--django/newforms/models.py43
-rw-r--r--django/template/defaultfilters.py5
-rw-r--r--django/test/client.py5
-rw-r--r--django/utils/daemonize.py6
-rw-r--r--django/views/debug.py17
-rw-r--r--django/views/generic/list_detail.py50
-rw-r--r--docs/custom_model_fields.txt4
-rw-r--r--docs/generic_views.txt17
-rw-r--r--docs/install.txt14
-rw-r--r--docs/model-api.txt20
-rw-r--r--docs/modelforms.txt10
-rw-r--r--docs/newforms.txt82
-rw-r--r--docs/pagination.txt133
-rw-r--r--docs/request_response.txt27
-rw-r--r--docs/sessions.txt8
-rw-r--r--docs/settings.txt11
-rw-r--r--docs/syndication_feeds.txt7
-rw-r--r--docs/templates.txt8
-rw-r--r--docs/tutorial04.txt6
-rw-r--r--docs/url_dispatch.txt8
-rw-r--r--tests/modeltests/custom_pk/models.py5
-rw-r--r--tests/modeltests/lookup/models.py7
-rw-r--r--tests/modeltests/manipulators/models.py28
-rw-r--r--tests/modeltests/model_forms/models.py73
-rw-r--r--tests/modeltests/pagination/models.py199
-rw-r--r--tests/modeltests/validation/models.py24
-rw-r--r--tests/regressiontests/forms/extra.py83
-rw-r--r--tests/regressiontests/forms/fields.py27
-rw-r--r--tests/regressiontests/forms/forms.py159
-rw-r--r--tests/regressiontests/model_fields/models.py24
-rw-r--r--tests/regressiontests/syndication/__init__.py0
-rw-r--r--tests/regressiontests/syndication/models.py0
-rw-r--r--tests/regressiontests/syndication/tests.py14
-rw-r--r--tests/regressiontests/syndication/urls.py18
-rw-r--r--tests/regressiontests/test_client_regress/models.py30
-rw-r--r--tests/regressiontests/test_client_regress/urls.py1
-rw-r--r--tests/regressiontests/test_client_regress/views.py16
-rw-r--r--tests/urls.py3
58 files changed, 2126 insertions, 1006 deletions
diff --git a/AUTHORS b/AUTHORS
index 6c9a7d40db..2329c8b86b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -59,6 +59,7 @@ answer newbie questions, and generally made Django that much better:
Arthur <avandorp@gmail.com>
David Avsajanishvili <avsd05@gmail.com>
axiak@mit.edu
+ Niran Babalola <niran@niran.org>
Morten Bagai <m@bagai.com>
Mikaël Barbero <mikael.barbero nospam at nospam free.fr>
Jiri Barton
@@ -145,6 +146,7 @@ answer newbie questions, and generally made Django that much better:
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info
Marc Garcia <marc.garcia@accopensys.com>
+ Alex Gaynor <alex.gaynor@gmail.com>
Andy Gayton <andy-django@thecablelounge.com>
Baishampayan Ghose
Dimitris Glezos <dimitris@glezos.com>
@@ -243,6 +245,7 @@ answer newbie questions, and generally made Django that much better:
michael.mcewan@gmail.com
michal@plovarna.cz
Mikko Hellsing <mikko@sorl.net>
+ Daniel Lindsley <polarcowz@gmail.com>
Orestis Markou <orestis@orestis.gr>
Slawek Mikula <slawek dot mikula at gmail dot com>
mitakummaa@gmail.com
@@ -256,6 +259,7 @@ answer newbie questions, and generally made Django that much better:
Robin Munn <http://www.geekforgod.com/>
Robert Myers <myer0052@gmail.com>
Nebojša Dorđević
+ Doug Napoleone <doug@dougma.com>
Gopal Narayanan <gopastro@gmail.com>
Fraser Nevett <mail@nevett.org>
Sam Newman <http://www.magpiebrain.com/>
@@ -269,6 +273,7 @@ answer newbie questions, and generally made Django that much better:
Barry Pederson <bp@barryp.org>
permonik@mesias.brnonet.cz
petr.marhoun@gmail.com
+ peter@mymart.com
pgross@thoughtworks.com
phaedo <http://phaedo.cx/>
phil@produxion.net
@@ -307,6 +312,7 @@ answer newbie questions, and generally made Django that much better:
serbaut@gmail.com
John Shaffer <jshaffer2112@gmail.com>
Pete Shinners <pete@shinners.org>
+ Leo Shklovskii
jason.sidabras@gmail.com
Jozko Skrablin <jozko.skrablin@gmail.com>
Ben Slavin <benjamin.slavin@gmail.com>
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 6be789a853..3917d40943 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -287,7 +287,7 @@ SESSION_COOKIE_PATH = '/' # The path of the sessio
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
-SESSION_FILE_PATH = '/tmp/' # Directory to store session files if using the file session module
+SESSION_FILE_PATH = None # Directory to store session files if using the file session module. If set to None the backend will use a sensible default.
#########
# CACHE #
diff --git a/django/conf/locale/de/LC_MESSAGES/django.mo b/django/conf/locale/de/LC_MESSAGES/django.mo
index 683848a50d..226c64c560 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.mo
+++ b/django/conf/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/de/LC_MESSAGES/django.po b/django/conf/locale/de/LC_MESSAGES/django.po
index 1601d2c3b2..754c840de0 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.po
+++ b/django/conf/locale/de/LC_MESSAGES/django.po
@@ -7,9 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-03 15:46+0100\n"
+"POT-Creation-Date: 2008-03-18 15:10-0500\n"
"PO-Revision-Date: 2008-03-03 16:10+0100\n"
-"Last-Translator: Michael Radziej <mir@noris.de>\n"
+"Last-Translator: Jannis Leidel <jannis@leidel.info>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -18,7 +18,6 @@ msgstr ""
"X-Poedit-Country: GERMANY\n"
"X-Poedit-SourceCharset: utf-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-"X-Generator: KBabel 1.11.4\n"
#: conf/global_settings.py:39
msgid "Arabic"
@@ -217,10 +216,8 @@ msgstr ""
"<h3>Nach %s:</h3>\n"
"<ul>\n"
-#: contrib/admin/filterspecs.py:74
-#: contrib/admin/filterspecs.py:92
-#: contrib/admin/filterspecs.py:147
-#: contrib/admin/filterspecs.py:173
+#: contrib/admin/filterspecs.py:74 contrib/admin/filterspecs.py:92
+#: contrib/admin/filterspecs.py:147 contrib/admin/filterspecs.py:173
msgid "All"
msgstr "Alle"
@@ -244,20 +241,17 @@ msgstr "Diesen Monat"
msgid "This year"
msgstr "Dieses Jahr"
-#: contrib/admin/filterspecs.py:147
-#: newforms/widgets.py:231
+#: contrib/admin/filterspecs.py:147 newforms/widgets.py:231
#: oldforms/__init__.py:592
msgid "Yes"
msgstr "Ja"
-#: contrib/admin/filterspecs.py:147
-#: newforms/widgets.py:231
+#: contrib/admin/filterspecs.py:147 newforms/widgets.py:231
#: oldforms/__init__.py:592
msgid "No"
msgstr "Nein"
-#: contrib/admin/filterspecs.py:154
-#: newforms/widgets.py:231
+#: contrib/admin/filterspecs.py:154 newforms/widgets.py:231
#: oldforms/__init__.py:592
msgid "Unknown"
msgstr "Unbekannt"
@@ -297,7 +291,8 @@ msgstr "Seite nicht gefunden"
#: contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found."
-msgstr "Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
+msgstr ""
+"Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden."
#: contrib/admin/templates/admin/500.html:4
#: contrib/admin/templates/admin/base.html:37
@@ -329,8 +324,13 @@ msgid "Server Error <em>(500)</em>"
msgstr "Serverfehler <em>(500)</em>"
#: contrib/admin/templates/admin/500.html:10
-msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
-msgstr "Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-Mail weitergegeben und sollte bald behoben sein. Vielen Dank für Ihr Verständnis."
+msgid ""
+"There's been an error. It's been reported to the site administrators via e-"
+"mail and should be fixed shortly. Thanks for your patience."
+msgstr ""
+"Ein Fehler ist aufgetreten. Dieser Fehler wurde an die Serververwalter per E-"
+"Mail weitergegeben und sollte bald behoben sein. Vielen Dank für Ihr "
+"Verständnis."
#: contrib/admin/templates/admin/base.html:26
msgid "Welcome,"
@@ -401,13 +401,23 @@ msgstr "Löschen"
#: contrib/admin/templates/admin/delete_confirmation.html:13
#, python-format
-msgid "Deleting the %(object_name)s '%(escaped_object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
-msgstr "Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von abhängigen Daten zur Folge, aber Sie haben nicht die nötigen Rechte um die folgenden abhängigen Daten zu löschen:"
+msgid ""
+"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
+"related objects, but your account doesn't have permission to delete the "
+"following types of objects:"
+msgstr ""
+"Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von "
+"abhängigen Daten zur Folge, aber Sie haben nicht die nötigen Rechte um die "
+"folgenden abhängigen Daten zu löschen:"
#: contrib/admin/templates/admin/delete_confirmation.html:20
#, python-format
-msgid "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? All of the following related items will be deleted:"
-msgstr "Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen wollen? Es werden zusätzlich die folgenden abhängigen Daten mit gelöscht:"
+msgid ""
+"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
+"All of the following related items will be deleted:"
+msgstr ""
+"Sind Sie sicher, dass Sie %(object_name)s \"%(escaped_object)s\" löschen "
+"wollen? Es werden zusätzlich die folgenden abhängigen Daten mit gelöscht:"
#: contrib/admin/templates/admin/delete_confirmation.html:25
msgid "Yes, I'm sure"
@@ -438,7 +448,7 @@ msgstr "Ändern"
#: contrib/admin/templates/admin/index.html:44
msgid "You don't have permission to edit anything."
-msgstr "Sie haben keine Berechtigung irgendwas zu ändern."
+msgstr "Sie haben keine Berechtigung, irgendetwas zu ändern."
#: contrib/admin/templates/admin/index.html:52
msgid "Recent Actions"
@@ -453,8 +463,14 @@ msgid "None available"
msgstr "Keine vorhanden"
#: contrib/admin/templates/admin/invalid_setup.html:8
-msgid "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user."
-msgstr "Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass die richtigen Datenbanktabellen angelegt wurden und die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist."
+msgid ""
+"Something's wrong with your database installation. Make sure the appropriate "
+"database tables have been created, and make sure the database is readable by "
+"the appropriate user."
+msgstr ""
+"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
+"die richtigen Datenbanktabellen angelegt wurden und die Datenbank vom "
+"verwendeten Datenbankbenutzer auch lesbar ist."
#: contrib/admin/templates/admin/login.html:17
#: contrib/comments/templates/comments/form.html:6
@@ -489,8 +505,12 @@ msgid "DATE_WITH_TIME_FULL"
msgstr "j. N Y, H:i"
#: contrib/admin/templates/admin/object_history.html:35
-msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
-msgstr "Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht über diese Verwaltungsseiten angelegt."
+msgid ""
+"This object doesn't have a change history. It probably wasn't added via this "
+"admin site."
+msgstr ""
+"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
+"über diese Verwaltungsseiten angelegt."
#: contrib/admin/templates/admin/pagination.html:10
msgid "Show all"
@@ -529,8 +549,12 @@ msgid "Save"
msgstr "Sichern"
#: contrib/admin/templates/admin/auth/user/add_form.html:6
-msgid "First, enter a username and password. Then, you'll be able to edit more user options."
-msgstr "Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere Optionen für den Benutzer geändert werden."
+msgid ""
+"First, enter a username and password. Then, you'll be able to edit more user "
+"options."
+msgstr ""
+"Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere "
+"Optionen für den Benutzer geändert werden."
#: contrib/admin/templates/admin/auth/user/add_form.html:12
msgid "Username"
@@ -554,7 +578,9 @@ msgstr "Bitte das gleiche Passwort zur Überprüfung nochmal eingeben."
#: contrib/admin/templates/admin/auth/user/change_password.html:27
#, python-format
msgid "Enter a new password for the user <strong>%(username)s</strong>."
-msgstr "Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</strong> ein."
+msgstr ""
+"Bitte geben Sie ein neues Passwort für den Benutzer <strong>%(username)s</"
+"strong> ein."
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets"
@@ -575,9 +601,12 @@ msgid ""
"your computer is \"internal\").</p>\n"
msgstr ""
"\n"
-"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in die\n"
-"Browser-Werkzeugleiste gezogen werden, oder mittels rechter Maustaste in die\n"
-"Bookmarks gespeichert werden. Danach können die Bookmarklets von jeder Seite\n"
+"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in "
+"die\n"
+"Browser-Werkzeugleiste gezogen werden, oder mittels rechter Maustaste in "
+"die\n"
+"Bookmarks gespeichert werden. Danach können die Bookmarklets von jeder "
+"Seite\n"
"aufgerufen werden. Einige Bookmarklets sind für den Zugriff von 'internen'\n"
"Rechnern eingeschränkt. Falls nicht klar ist, ob ein Rechner als 'intern'\n"
"bewertet wird, bitte den Administrator fragen.</p>\n"
@@ -587,16 +616,24 @@ msgid "Documentation for this page"
msgstr "Dokumentation für diese Seite"
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
-msgid "Jumps you from any page to the documentation for the view that generates that page."
-msgstr "Springt von jeder Seite zu der Dokumentation für den View der diese Seite erzeugt."
+msgid ""
+"Jumps you from any page to the documentation for the view that generates "
+"that page."
+msgstr ""
+"Springt von jeder Seite zu der Dokumentation für den View der diese Seite "
+"erzeugt."
#: contrib/admin/templates/admin_doc/bookmarklets.html:21
msgid "Show object ID"
msgstr "Objekt-ID anzeigen"
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
-msgid "Shows the content-type and unique ID for pages that represent a single object."
-msgstr "Zeigt den Content-Type und die eindeutige ID für Seiten die ein einzelnes Objekt repräsentieren."
+msgid ""
+"Shows the content-type and unique ID for pages that represent a single "
+"object."
+msgstr ""
+"Zeigt den Content-Type und die eindeutige ID für Seiten die ein einzelnes "
+"Objekt repräsentieren."
#: contrib/admin/templates/admin_doc/bookmarklets.html:24
msgid "Edit this object (current window)"
@@ -604,7 +641,9 @@ msgstr "Dieses Objekt im aktuellen Fenster ändern."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Jumps to the admin page for pages that represent a single object."
-msgstr "Springt zu der Administrationsseite für dieses Objekt, wenn diese Seite ein Objekt repräsentiert."
+msgstr ""
+"Springt zu der Administrationsseite für dieses Objekt, wenn diese Seite ein "
+"Objekt repräsentiert."
#: contrib/admin/templates/admin_doc/bookmarklets.html:27
msgid "Edit this object (new window)"
@@ -612,7 +651,8 @@ msgstr "Dieses Objekt in einem neuen Fenster ändern."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "As above, but opens the admin page in a new window."
-msgstr "Wie zuvor, aber öffnet die Administrationsseite in einem neuen Fenster."
+msgstr ""
+"Wie zuvor, aber öffnet die Administrationsseite in einem neuen Fenster."
#: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
@@ -639,8 +679,13 @@ msgid "Your password was changed."
msgstr "Ihr Passwort wurde geändert."
#: contrib/admin/templates/registration/password_change_form.html:11
-msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
-msgstr "Bitte geben Sie aus Sicherheitsgründen erst Ihr altes Passwort und darunter dann zweimal (um sicherzustellen, dass Sie es korrekt eingegeben haben) das neue Kennwort ein."
+msgid ""
+"Please enter your old password, for security's sake, and then enter your new "
+"password twice so we can verify you typed it in correctly."
+msgstr ""
+"Bitte geben Sie aus Sicherheitsgründen erst Ihr altes Passwort und darunter "
+"dann zweimal (um sicherzustellen, dass Sie es korrekt eingegeben haben) das "
+"neue Kennwort ein."
#: contrib/admin/templates/registration/password_change_form.html:16
msgid "Old password:"
@@ -671,8 +716,12 @@ msgid "Password reset successful"
msgstr "Passwort wurde erfolgreich zurückgesetzt"
#: contrib/admin/templates/registration/password_reset_done.html:12
-msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
-msgstr "Wir haben ein neues Passwort an die von Ihnen angegebene E-Mail-Adresse geschickt. Sie sollten es in Kürze erhalten."
+msgid ""
+"We've e-mailed a new password to the e-mail address you submitted. You "
+"should be receiving it shortly."
+msgstr ""
+"Wir haben ein neues Passwort an die von Ihnen angegebene E-Mail-Adresse "
+"geschickt. Sie sollten es in Kürze erhalten."
#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
@@ -706,8 +755,12 @@ msgid "The %(site_name)s team"
msgstr "Das Team von %(site_name)s"
#: contrib/admin/templates/registration/password_reset_form.html:12
-msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
-msgstr "Passwort vergessen? Einfach die E-Mail-Adresse eingeben und wir setzen das Passwort zurück und lassen es Ihnen per E-Mail zukommen."
+msgid ""
+"Forgotten your password? Enter your e-mail address below, and we'll reset "
+"your password and e-mail the new one to you."
+msgstr ""
+"Passwort vergessen? Einfach die E-Mail-Adresse eingeben und wir setzen das "
+"Passwort zurück und lassen es Ihnen per E-Mail zukommen."
#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
@@ -737,14 +790,12 @@ msgstr "Ändern:"
msgid "All dates"
msgstr "Alle Tage"
-#: contrib/admin/views/auth.py:20
-#: contrib/admin/views/main.py:267
+#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:267
#, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" wurde erfolgreich hinzugefügt."
-#: contrib/admin/views/auth.py:25
-#: contrib/admin/views/main.py:271
+#: 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 "Das Element kann jetzt weiter bearbeitet werden."
@@ -762,18 +813,29 @@ msgstr "Passwort erfolgreich geändert."
msgid "Change password: %s"
msgstr "Passwort ändern: %s"
-#: contrib/admin/views/decorators.py:17
-#: contrib/auth/forms.py:60
-msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
-msgstr "Bitte einen gültigen Benutzernamen und ein Passwort eingeben. Beide Felder berücksichtigen die Groß-/Kleinschreibung."
+#: contrib/admin/views/decorators.py:17 contrib/auth/forms.py:60
+msgid ""
+"Please enter a correct username and password. Note that both fields are case-"
+"sensitive."
+msgstr ""
+"Bitte einen gültigen Benutzernamen und ein Passwort eingeben. Beide Felder "
+"berücksichtigen die Groß-/Kleinschreibung."
#: contrib/admin/views/decorators.py:69
-msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
-msgstr "Bitte neu anmelden, da die Session ausgelaufen ist. Keine Angst, die Beiträge wurden gesichert."
+msgid ""
+"Please log in again, because your session has expired. Don't worry: Your "
+"submission has been saved."
+msgstr ""
+"Bitte neu anmelden, da die Session ausgelaufen ist. Keine Angst, die "
+"Beiträge wurden gesichert."
#: contrib/admin/views/decorators.py:76
-msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
-msgstr "Es sieht danach aus, dass der Browser keine Cookies akzeptiert. Bitte im Browser Cookies aktivieren und diese Seite neu laden."
+msgid ""
+"Looks like your browser isn't configured to accept cookies. Please enable "
+"cookies, reload this page, and try again."
+msgstr ""
+"Es sieht danach aus, dass der Browser keine Cookies akzeptiert. Bitte im "
+"Browser Cookies aktivieren und diese Seite neu laden."
#: contrib/admin/views/decorators.py:90
msgid "Usernames cannot contain the '@' character."
@@ -782,22 +844,21 @@ msgstr "Benutzernamen dürfen das Zeichen '@' nicht enthalten."
#: contrib/admin/views/decorators.py:92
#, python-format
msgid "Your e-mail address is not your username. Try '%s' instead."
-msgstr "Die E-Mail-Adresse entspricht nicht Ihrem Benutzernamen. Bitte stattdessen '%s' versuchen."
+msgstr ""
+"Die E-Mail-Adresse entspricht nicht Ihrem Benutzernamen. Bitte stattdessen "
+"'%s' versuchen."
-#: contrib/admin/views/doc.py:48
-#: contrib/admin/views/doc.py:50
+#: contrib/admin/views/doc.py:48 contrib/admin/views/doc.py:50
#: contrib/admin/views/doc.py:52
msgid "tag:"
msgstr "Schlagwort:"
-#: contrib/admin/views/doc.py:79
-#: contrib/admin/views/doc.py:81
+#: contrib/admin/views/doc.py:79 contrib/admin/views/doc.py:81
#: contrib/admin/views/doc.py:83
msgid "filter:"
msgstr "Filter:"
-#: contrib/admin/views/doc.py:137
-#: contrib/admin/views/doc.py:139
+#: contrib/admin/views/doc.py:137 contrib/admin/views/doc.py:139
#: contrib/admin/views/doc.py:141
msgid "view:"
msgstr "Ansicht:"
@@ -817,10 +878,8 @@ msgstr "Modell %(name)r wurde nicht in Anwendung %(label)r gefunden"
msgid "the related `%(label)s.%(type)s` object"
msgstr "Das verknüpfte `%(label)s.%(type)s` Objekt"
-#: contrib/admin/views/doc.py:185
-#: contrib/admin/views/doc.py:207
-#: contrib/admin/views/doc.py:221
-#: contrib/admin/views/doc.py:226
+#: 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 "Modell:"
@@ -844,12 +903,9 @@ msgstr "Anzahl von %s"
msgid "Fields on %s objects"
msgstr "Felder am %s Objekt"
-#: 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
+#: 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 "Ganzzahl"
@@ -857,8 +913,7 @@ msgstr "Ganzzahl"
msgid "Boolean (Either True or False)"
msgstr "Boolscher Wert (True oder False)"
-#: contrib/admin/views/doc.py:295
-#: contrib/admin/views/doc.py:314
+#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:314
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "Zeichenkette (bis zu %(max_length)s Zeichen)"
@@ -883,8 +938,7 @@ msgstr "Dezimalzahl"
msgid "E-mail address"
msgstr "E-Mail-Adresse"
-#: contrib/admin/views/doc.py:301
-#: contrib/admin/views/doc.py:302
+#: contrib/admin/views/doc.py:301 contrib/admin/views/doc.py:302
#: contrib/admin/views/doc.py:305
msgid "File path"
msgstr "Dateipfad"
@@ -893,8 +947,7 @@ msgstr "Dateipfad"
msgid "Floating point number"
msgstr "Fließkommazahl"
-#: contrib/admin/views/doc.py:307
-#: contrib/comments/models.py:89
+#: contrib/admin/views/doc.py:307 contrib/comments/models.py:89
msgid "IP address"
msgstr "IP-Adresse"
@@ -918,8 +971,7 @@ msgstr "Text"
msgid "Time"
msgstr "Zeit"
-#: contrib/admin/views/doc.py:318
-#: contrib/flatpages/models.py:7
+#: contrib/admin/views/doc.py:318 contrib/flatpages/models.py:7
msgid "URL"
msgstr "Adresse (URL)"
@@ -940,8 +992,7 @@ msgstr "%s ist scheinbar kein urlpattern Objekt"
msgid "Site administration"
msgstr "Website-Verwaltung"
-#: contrib/admin/views/main.py:280
-#: contrib/admin/views/main.py:365
+#: contrib/admin/views/main.py:280 contrib/admin/views/main.py:365
#, python-format
msgid "You may add another %s below."
msgstr "Jetzt kann ein weiteres Element vom Typ %s angelegt werden."
@@ -956,10 +1007,8 @@ msgstr "%s hinzufügen"
msgid "Added %s."
msgstr "%s hinzugefügt."
-#: contrib/admin/views/main.py:344
-#: contrib/admin/views/main.py:346
-#: contrib/admin/views/main.py:348
-#: 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 "und"
@@ -985,8 +1034,11 @@ msgstr "%(name)s \"%(obj)s\" wurde erfolgreich geändert."
#: contrib/admin/views/main.py:362
#, python-format
-msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
-msgstr "%(name)s \"%(obj)s\" wurde erfolgreich hinzugefügt. Das Element kann jetzt geändert werden."
+msgid ""
+"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
+msgstr ""
+"%(name)s \"%(obj)s\" wurde erfolgreich hinzugefügt. Das Element kann jetzt "
+"geändert werden."
#: contrib/admin/views/main.py:400
#, python-format
@@ -1031,8 +1083,7 @@ msgstr "%s zur Änderung auswählen"
msgid "Database error"
msgstr "Datenbankfehler"
-#: contrib/auth/forms.py:17
-#: contrib/auth/forms.py:138
+#: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match."
msgstr "Die beiden Passwörter sind nicht identisch."
@@ -1041,16 +1092,24 @@ msgid "A user with that username already exists."
msgstr "Ein Benutzer mit diesem Namen existiert bereits."
#: contrib/auth/forms.py:53
-msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
-msgstr "Der Webbrowser scheint keine Cookies aktiviert zu haben. Cookies sind für die Anmeldung zwingend erforderlich."
+msgid ""
+"Your Web browser doesn't appear to have cookies enabled. Cookies are "
+"required for logging in."
+msgstr ""
+"Der Webbrowser scheint keine Cookies aktiviert zu haben. Cookies sind für "
+"die Anmeldung zwingend erforderlich."
#: contrib/auth/forms.py:62
msgid "This account is inactive."
msgstr "Dieser Benutzer ist inaktiv."
#: contrib/auth/forms.py:84
-msgid "That e-mail address doesn't have an associated user account. Are you sure you've registered?"
-msgstr "Zu dieser E-Mail-Adresse existiert kein Benutzer. Sicher, dass Sie sich mit dieser Adresse angemeldet haben?"
+msgid ""
+"That e-mail address doesn't have an associated user account. Are you sure "
+"you've registered?"
+msgstr ""
+"Zu dieser E-Mail-Adresse existiert kein Benutzer. Sicher, dass Sie sich mit "
+"dieser Adresse angemeldet haben?"
#: contrib/auth/forms.py:107
#, python-format
@@ -1065,8 +1124,7 @@ msgstr "Die beiden neuen Passwörter sind nicht identisch."
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr "Das alte Passwort war falsch. Bitte neu eingeben."
-#: contrib/auth/models.py:73
-#: contrib/auth/models.py:93
+#: contrib/auth/models.py:73 contrib/auth/models.py:93
msgid "name"
msgstr "Name"
@@ -1078,8 +1136,7 @@ msgstr "Codename"
msgid "permission"
msgstr "Berechtigung"
-#: contrib/auth/models.py:79
-#: contrib/auth/models.py:94
+#: contrib/auth/models.py:79 contrib/auth/models.py:94
msgid "permissions"
msgstr "Berechtigungen"
@@ -1087,8 +1144,7 @@ msgstr "Berechtigungen"
msgid "group"
msgstr "Gruppe"
-#: contrib/auth/models.py:98
-#: contrib/auth/models.py:141
+#: contrib/auth/models.py:98 contrib/auth/models.py:141
msgid "groups"
msgstr "Gruppen"
@@ -1097,8 +1153,12 @@ msgid "username"
msgstr "Benutzername"
#: contrib/auth/models.py:131
-msgid "Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."
-msgstr "Erforderlich. 30 Zeichen oder weniger. Alphanumerische Zeichen (Buchstaben, Ziffern und Unterstriche sind erlaubt)."
+msgid ""
+"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
+"digits and underscores)."
+msgstr ""
+"Erforderlich. 30 Zeichen oder weniger. Alphanumerische Zeichen (Buchstaben, "
+"Ziffern und Unterstriche sind erlaubt)."
#: contrib/auth/models.py:132
msgid "first name"
@@ -1117,8 +1177,12 @@ msgid "password"
msgstr "Passwort"
#: contrib/auth/models.py:135
-msgid "Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."
-msgstr "Die Form '[algo]$[salt]$[hexdigest]' verwenden, oder das <a href=\"password/\">Passwort ändern Formular</a> benutzen."
+msgid ""
+"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
+"password form</a>."
+msgstr ""
+"Die Form '[algo]$[salt]$[hexdigest]' verwenden, oder das <a href=\"password/"
+"\">Passwort ändern Formular</a> benutzen."
#: contrib/auth/models.py:136
msgid "staff status"
@@ -1126,23 +1190,33 @@ msgstr "Administrator"
#: contrib/auth/models.py:136
msgid "Designates whether the user can log into this admin site."
-msgstr "Legt fest, ob sich der Benutzer an der Administrationsseite anmelden kann."
+msgstr ""
+"Legt fest, ob sich der Benutzer an der Administrationsseite anmelden kann."
#: contrib/auth/models.py:137
msgid "active"
msgstr "Aktiv"
#: contrib/auth/models.py:137
-msgid "Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."
-msgstr "Legt fest, ob sich der Benutzer an der Administrationsseite anmelden kann. Anstatt einen Benutzer zu löschen, kann er hier auch einfach deaktiviert werden."
+msgid ""
+"Designates whether this user can log into the Django admin. Unselect this "
+"instead of deleting accounts."
+msgstr ""
+"Legt fest, ob sich der Benutzer an der Administrationsseite anmelden kann. "
+"Anstatt einen Benutzer zu löschen, kann er hier auch einfach deaktiviert "
+"werden."
#: contrib/auth/models.py:138
msgid "superuser status"
msgstr "Hauptadmin."
#: contrib/auth/models.py:138
-msgid "Designates that this user has all permissions without explicitly assigning them."
-msgstr "Legt fest, dass der Benutzer alle Berechtigungen hat, ohne diese einzeln zuweisen zu müssen."
+msgid ""
+"Designates that this user has all permissions without explicitly assigning "
+"them."
+msgstr ""
+"Legt fest, dass der Benutzer alle Berechtigungen hat, ohne diese einzeln "
+"zuweisen zu müssen."
#: contrib/auth/models.py:139
msgid "last login"
@@ -1153,8 +1227,12 @@ msgid "date joined"
msgstr "Mitglied seit"
#: contrib/auth/models.py:142
-msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
-msgstr "Zusätzlich zu den manuell angelegten Rechten erhält dieser Benutzer auch alle Rechte, die seine zugewiesenen Gruppen haben."
+msgid ""
+"In addition to the permissions manually assigned, this user will also get "
+"all permissions granted to each group he/she is in."
+msgstr ""
+"Zusätzlich zu den manuell angelegten Rechten erhält dieser Benutzer auch "
+"alle Rechte, die seine zugewiesenen Gruppen haben."
#: contrib/auth/models.py:143
msgid "user permissions"
@@ -1192,8 +1270,7 @@ msgstr "Mitteilung"
msgid "Logged out"
msgstr "Abgemeldet"
-#: contrib/comments/models.py:71
-#: contrib/comments/models.py:176
+#: contrib/comments/models.py:71 contrib/comments/models.py:176
msgid "object ID"
msgstr "Objekt-ID"
@@ -1201,8 +1278,7 @@ msgstr "Objekt-ID"
msgid "headline"
msgstr "Überschrift"
-#: contrib/comments/models.py:73
-#: contrib/comments/models.py:95
+#: contrib/comments/models.py:73 contrib/comments/models.py:95
#: contrib/comments/models.py:177
msgid "comment"
msgstr "Kommentar"
@@ -1243,13 +1319,11 @@ msgstr "Bewertung #8"
msgid "is valid rating"
msgstr "ist eine Bewertung"
-#: contrib/comments/models.py:87
-#: contrib/comments/models.py:179
+#: contrib/comments/models.py:87 contrib/comments/models.py:179
msgid "date/time submitted"
msgstr "Datum/Zeit Erstellung"
-#: contrib/comments/models.py:88
-#: contrib/comments/models.py:180
+#: contrib/comments/models.py:88 contrib/comments/models.py:180
msgid "is public"
msgstr "ist öffentlich"
@@ -1258,15 +1332,18 @@ msgid "is removed"
msgstr "ist gelöscht"
#: contrib/comments/models.py:90
-msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead."
-msgstr "Hier einen Haken setzen, wenn der Kommentar unpassend ist. Stattdessen wird dann \"Dieser Kommentar wurde entfernt\" Meldung angezeigt."
+msgid ""
+"Check this box if the comment is inappropriate. A \"This comment has been "
+"removed\" message will be displayed instead."
+msgstr ""
+"Hier einen Haken setzen, wenn der Kommentar unpassend ist. Stattdessen wird "
+"dann \"Dieser Kommentar wurde entfernt\" Meldung angezeigt."
#: contrib/comments/models.py:96
msgid "comments"
msgstr "Kommentare"
-#: contrib/comments/models.py:140
-#: contrib/comments/models.py:222
+#: contrib/comments/models.py:140 contrib/comments/models.py:222
msgid "Content object"
msgstr "Inhaltsobjekt"
@@ -1408,25 +1485,32 @@ msgid "Your name:"
msgstr "Ihr Name:"
#: contrib/comments/views/comments.py:28
-msgid "This rating is required because you've entered at least one other rating."
-msgstr "Diese Abstimmung ist zwingend erforderlich, da Sie an mindestens einer weiteren Abstimmung teilnehmen."
+msgid ""
+"This rating is required because you've entered at least one other rating."
+msgstr ""
+"Diese Abstimmung ist zwingend erforderlich, da Sie an mindestens einer "
+"weiteren Abstimmung teilnehmen."
#: contrib/comments/views/comments.py:112
#, python-format
msgid ""
-"This comment was posted by a user who has posted fewer than %(count)s comment:\n"
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comment:\n"
"\n"
"%(text)s"
msgid_plural ""
-"This comment was posted by a user who has posted fewer than %(count)s comments:\n"
+"This comment was posted by a user who has posted fewer than %(count)s "
+"comments:\n"
"\n"
"%(text)s"
msgstr[0] ""
-"Dieser Kommentar ist von einem Benutzer mit weniger als %(count)s Kommentar:\n"
+"Dieser Kommentar ist von einem Benutzer mit weniger als %(count)s "
+"Kommentar:\n"
"\n"
"%(text)s"
msgstr[1] ""
-"Dieser Kommentar ist von einem Benutzer mit weniger als %(count)s Kommentaren:\n"
+"Dieser Kommentar ist von einem Benutzer mit weniger als %(count)s "
+"Kommentaren:\n"
"\n"
"%(text)s"
@@ -1454,17 +1538,23 @@ msgstr "Eines oder mehrere der erforderlichen Felder fehlen"
#: contrib/comments/views/comments.py:198
#: contrib/comments/views/comments.py:289
msgid "Somebody tampered with the comment form (security violation)"
-msgstr "Jemand hat mit dem Kommentarformular herumgespielt (Sicherheitsverletzung)"
+msgstr ""
+"Jemand hat mit dem Kommentarformular herumgespielt (Sicherheitsverletzung)"
#: contrib/comments/views/comments.py:208
#: contrib/comments/views/comments.py:295
-msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
-msgstr "Das Kommentarformular hatte einen falschen 'target' Parameter -- die Objekt-ID ist ungültig."
+msgid ""
+"The comment form had an invalid 'target' parameter -- the object ID was "
+"invalid"
+msgstr ""
+"Das Kommentarformular hatte einen falschen 'target' Parameter -- die Objekt-"
+"ID ist ungültig."
#: contrib/comments/views/comments.py:259
#: contrib/comments/views/comments.py:324
msgid "The comment form didn't provide either 'preview' or 'post'"
-msgstr "Das Kommentarformular wurde nicht mit 'preview' oder 'post' abgeschickt"
+msgstr ""
+"Das Kommentarformular wurde nicht mit 'preview' oder 'post' abgeschickt"
#: contrib/comments/views/karma.py:21
msgid "Anonymous users cannot vote"
@@ -1478,21 +1568,23 @@ msgstr "Ungültige Kommentar-ID"
msgid "No voting for yourself"
msgstr "Keine Abstimmung für dich selbst"
-#: contrib/contenttypes/models.py:37
+#: contrib/contenttypes/models.py:67
msgid "python model class name"
msgstr "Python Model-Klassenname"
-#: contrib/contenttypes/models.py:40
+#: contrib/contenttypes/models.py:71
msgid "content type"
msgstr "Inhaltstyp"
-#: contrib/contenttypes/models.py:41
+#: contrib/contenttypes/models.py:72
msgid "content types"
msgstr "Inhaltstypen"
#: contrib/flatpages/models.py:8
-msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
-msgstr "Beispiel: '/about/contact/'. Wichtig: vorne und hinten muss ein / stehen."
+msgid ""
+"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
+msgstr ""
+"Beispiel: '/about/contact/'. Wichtig: Am Anfang und Ende muss ein / stehen."
#: contrib/flatpages/models.py:9
msgid "title"
@@ -1511,8 +1603,12 @@ msgid "template name"
msgstr "Name der Vorlage"
#: contrib/flatpages/models.py:13
-msgid "Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."
-msgstr "Beispiel: 'flatpages/contact_page.html'. Wenn dieses Feld nicht gefüllt ist, wird 'flatpages/default.html' als Standard gewählt."
+msgid ""
+"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
+"will use 'flatpages/default.html'."
+msgstr ""
+"Beispiel: 'flatpages/contact_page.html'. Wenn dieses Feld nicht gefüllt ist, "
+"wird 'flatpages/default.html' als Standard gewählt."
#: contrib/flatpages/models.py:14
msgid "registration required"
@@ -1520,7 +1616,9 @@ msgstr "Registrierung erforderlich"
#: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page."
-msgstr "Wenn hier ein Haken gesetzt ist, können nur angemeldete Benutzer diese Seite sehen."
+msgstr ""
+"Wenn hier ein Haken gesetzt ist, können nur angemeldete Benutzer diese Seite "
+"sehen."
#: contrib/flatpages/models.py:18
msgid "flat page"
@@ -1618,31 +1716,31 @@ msgstr "gestern"
#: contrib/localflavor/ar/forms.py:27
#, fuzzy
msgid "Enter a postal code in the format NNNN or ANNNNAAA."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige Postleitzahl im Format NNNN oder ANNNNAAA eingeben."
-#: contrib/localflavor/ar/forms.py:49
-#: contrib/localflavor/br/forms.py:96
-#: contrib/localflavor/br/forms.py:135
-#: contrib/localflavor/pe/forms.py:23
+#: contrib/localflavor/ar/forms.py:49 contrib/localflavor/br/forms.py:96
+#: contrib/localflavor/br/forms.py:135 contrib/localflavor/pe/forms.py:23
#: contrib/localflavor/pe/forms.py:51
#, fuzzy
msgid "This field requires only numbers."
-msgstr "Dieses Feld ist zwingend erforderlich."
+msgstr "Dieses Feld darf nur Ziffern enthalten."
#: contrib/localflavor/ar/forms.py:50
#, fuzzy
msgid "This field requires 7 or 8 digits."
-msgstr "Dieses Feld ist zwingend erforderlich."
+msgstr "Dieses Feld benötigt 7 oder 8 Ziffern."
#: contrib/localflavor/ar/forms.py:79
#, fuzzy
msgid "Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format."
-msgstr "Bitte eine gültige deutsche Personalausweisnummer im Format XXXXXXXXXXX-XXXXXXX-XXXXXXX-X eingeben."
+msgstr ""
+"Bitte eine gültige CUIT im Format XX-XXXXXXXX-X oder XXXXXXXXXXXX eingeben."
#: contrib/localflavor/ar/forms.py:80
#, fuzzy
msgid "Invalid CUIT."
-msgstr "Ungültige URL: %s"
+msgstr "Ungültige CUIT."
#: contrib/localflavor/au/forms.py:16
msgid "Enter a 4 digit post code."
@@ -1654,30 +1752,32 @@ msgstr "Bitte eine gültige Postleitzahl im Format XXXXX-XXX eingeben."
#: contrib/localflavor/br/forms.py:30
msgid "Phone numbers must be in XX-XXXX-XXXX format."
-msgstr "Telefonnummern müssen das Format XXX-XXX-XXXX haben."
+msgstr "Telefonnummern müssen das Format XX-XXXX-XXXX haben."
#: contrib/localflavor/br/forms.py:58
#, fuzzy
-msgid "Select a valid brazilian state. That state is not one of the available states."
-msgstr "Bitte eine gültige Auswahl treffen."
+msgid ""
+"Select a valid brazilian state. That state is not one of the available "
+"states."
+msgstr "Bitte einen gültigen brasilianischen Bundesstaat auswählen."
#: contrib/localflavor/br/forms.py:94
msgid "Invalid CPF number."
-msgstr ""
+msgstr "Ungültige CPF-Nummer."
#: contrib/localflavor/br/forms.py:95
#, fuzzy
msgid "This field requires at most 11 digits or 14 characters."
-msgstr "Bitte sicherstellen, dass der Text maximal %d Zeichen hat."
+msgstr "Dieses Feld benötigt mindestens 11 Ziffern oder 14 Zeichen."
#: contrib/localflavor/br/forms.py:134
msgid "Invalid CNPJ number."
-msgstr ""
+msgstr "Ungültige CNPJ-Nummer."
#: contrib/localflavor/br/forms.py:136
#, fuzzy
msgid "This field requires at least 14 digits"
-msgstr "Dieses Feld ist zwingend erforderlich."
+msgstr "Dieses Feld benötigt mindestens 14 Ziffern."
#: contrib/localflavor/ca/forms.py:17
#, fuzzy
@@ -1687,7 +1787,9 @@ msgstr "Bitte eine gültige Postleitzahl im Format XXXXX eingeben."
#: contrib/localflavor/ca/forms.py:88
#, fuzzy
msgid "Enter a valid Canadian Social Insurance number in XXX-XXX-XXX format."
-msgstr "Bitte eine gültige US-amerikanische Sozialversicherungsnummer im Format XXX-XX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige kanadische Sozialversicherungsnummer im Format XXX-"
+"XXX-XXX eingeben."
#: contrib/localflavor/ch/ch_states.py:5
msgid "Aargau"
@@ -1712,15 +1814,15 @@ msgstr ""
#: contrib/localflavor/ch/ch_states.py:10
#, fuzzy
msgid "Berne"
-msgstr "Berlin"
+msgstr "Bern"
#: contrib/localflavor/ch/ch_states.py:11
msgid "Fribourg"
-msgstr ""
+msgstr "Freiburg"
#: contrib/localflavor/ch/ch_states.py:12
msgid "Geneva"
-msgstr ""
+msgstr "Genf"
#: contrib/localflavor/ch/ch_states.py:13
#, fuzzy
@@ -1771,7 +1873,7 @@ msgstr ""
#: contrib/localflavor/ch/ch_states.py:24
#, fuzzy
msgid "Thurgau"
-msgstr "Thüringen"
+msgstr ""
#: contrib/localflavor/ch/ch_states.py:25
msgid "Ticino"
@@ -1780,7 +1882,7 @@ msgstr ""
#: contrib/localflavor/ch/ch_states.py:26
#, fuzzy
msgid "Uri"
-msgstr "Fr"
+msgstr ""
#: contrib/localflavor/ch/ch_states.py:27
msgid "Valais"
@@ -1793,31 +1895,34 @@ msgstr ""
#: contrib/localflavor/ch/ch_states.py:29
#, fuzzy
msgid "Zug"
-msgstr "Aug"
+msgstr ""
#: contrib/localflavor/ch/ch_states.py:30
#, fuzzy
msgid "Zurich"
-msgstr "Türkisch"
+msgstr "Zürich"
-#: contrib/localflavor/ch/forms.py:16
-#: contrib/localflavor/no/forms.py:12
+#: contrib/localflavor/ch/forms.py:16 contrib/localflavor/no/forms.py:12
msgid "Enter a zip code in the format XXXX."
msgstr "Bitte eine gültige Postleitzahl im Format XXXX eingeben."
#: contrib/localflavor/ch/forms.py:64
-msgid "Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format."
+msgid ""
+"Enter a valid Swiss identity or passport card number in X1234567<0 or "
+"1234567890 format."
msgstr ""
+"Bitte eine gültige Schweizer Identifikations- oder Reisepassnummer im Format"
+"X1234567<0 oder 1234567890 eingeben."
#: contrib/localflavor/cl/forms.py:29
#, fuzzy
msgid "Enter a valid Chilean RUT."
-msgstr "Bitte einen gültigen Dateinamen eingeben."
+msgstr "Bitte einen gültige chilenische RUT eingeben."
#: contrib/localflavor/cl/forms.py:30
#, fuzzy
msgid "Enter a valid Chilean RUT. The format is XX.XXX.XXX-X."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXX-XXX eingeben."
+msgstr "Bitte eine chilenische RUT im Format XX.XXX.XXX-X eingeben."
#: contrib/localflavor/cl/forms.py:31
#, fuzzy
@@ -1888,15 +1993,18 @@ msgstr "Schleswig-Holstein"
msgid "Thuringia"
msgstr "Thüringen"
-#: contrib/localflavor/de/forms.py:14
-#: contrib/localflavor/fi/forms.py:12
+#: contrib/localflavor/de/forms.py:14 contrib/localflavor/fi/forms.py:12
#: contrib/localflavor/fr/forms.py:15
msgid "Enter a zip code in the format XXXXX."
msgstr "Bitte eine gültige Postleitzahl im Format XXXXX eingeben."
#: contrib/localflavor/de/forms.py:41
-msgid "Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format."
-msgstr "Bitte eine gültige deutsche Personalausweisnummer im Format XXXXXXXXXXX-XXXXXXX-XXXXXXX-X eingeben."
+msgid ""
+"Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X "
+"format."
+msgstr ""
+"Bitte eine gültige deutsche Personalausweisnummer im Format XXXXXXXXXXX-"
+"XXXXXXX-XXXXXXX-X eingeben."
#: contrib/localflavor/es/es_provinces.py:5
msgid "Arava"
@@ -1917,7 +2025,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:9
#, fuzzy
msgid "Avila"
-msgstr "April"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:10
msgid "Badajoz"
@@ -1930,7 +2038,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:12
#, fuzzy
msgid "Barcelona"
-msgstr "Mazedonisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:13
msgid "Burgos"
@@ -1971,7 +2079,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:22
#, fuzzy
msgid "Granada"
-msgstr "Kannada"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:23
msgid "Guadalajara"
@@ -1988,17 +2096,17 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:26
#, fuzzy
msgid "Huesca"
-msgstr "Dienstag"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:27
#, fuzzy
msgid "Jaen"
-msgstr "Jan."
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:28
#, fuzzy
msgid "Leon"
-msgstr "Anmelden"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:29
msgid "Lleida"
@@ -2041,7 +2149,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:38
#, fuzzy
msgid "Palencia"
-msgstr "Galicisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:39
msgid "Las Palmas"
@@ -2063,12 +2171,12 @@ msgstr ""
#: contrib/localflavor/es/es_regions.py:11
#, fuzzy
msgid "Cantabria"
-msgstr "Katalanisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:44
#, fuzzy
msgid "Segovia"
-msgstr "Slowenisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:45
msgid "Seville"
@@ -2077,7 +2185,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:46
#, fuzzy
msgid "Soria"
-msgstr "Serbisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:47
msgid "Tarragona"
@@ -2086,7 +2194,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:48
#, fuzzy
msgid "Teruel"
-msgstr "Di"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:49
msgid "Toledo"
@@ -2095,7 +2203,7 @@ msgstr ""
#: contrib/localflavor/es/es_provinces.py:50
#, fuzzy
msgid "Valencia"
-msgstr "Galicisch"
+msgstr ""
#: contrib/localflavor/es/es_provinces.py:51
msgid "Valladolid"
@@ -2144,7 +2252,7 @@ msgstr ""
#: contrib/localflavor/es/es_regions.py:10
#, fuzzy
msgid "Canary Islands"
-msgstr "Saarland"
+msgstr ""
#: contrib/localflavor/es/es_regions.py:12
msgid "Castile-La Mancha"
@@ -2157,7 +2265,7 @@ msgstr ""
#: contrib/localflavor/es/es_regions.py:14
#, fuzzy
msgid "Catalonia"
-msgstr "Katalanisch"
+msgstr ""
#: contrib/localflavor/es/es_regions.py:15
msgid "Extremadura"
@@ -2166,7 +2274,7 @@ msgstr ""
#: contrib/localflavor/es/es_regions.py:16
#, fuzzy
msgid "Galicia"
-msgstr "Galicisch"
+msgstr "Galicien"
#: contrib/localflavor/es/es_regions.py:19
msgid "Region of Murcia"
@@ -2183,43 +2291,50 @@ msgstr ""
#: contrib/localflavor/es/forms.py:19
#, fuzzy
msgid "Enter a valid postal code in the range and format 01XXX - 52XXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige Postleitzahl im Format 01XXX bis 52XXX eingeben."
#: contrib/localflavor/es/forms.py:39
#, fuzzy
-msgid "Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgid ""
+"Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or "
+"9XXXXXXXX."
+msgstr ""
+"Bitte eine gültige Telefonnummer in einem der folgenden Formate eingeben "
+"6XXXXXXXX, 8XXXXXXXX oder 9XXXXXXXX."
#: contrib/localflavor/es/forms.py:66
#, fuzzy
msgid "Please enter a valid NIF, NIE, or CIF."
-msgstr "Bitte eine gültige IP-Adresse eingeben."
+msgstr "Bitte eine gültige NIF, NIE oder CIF eingeben."
#: contrib/localflavor/es/forms.py:67
#, fuzzy
msgid "Please enter a valid NIF or NIE."
-msgstr "Bitte ein gültiges '%s' eingeben."
+msgstr "Bitte eine gültige NIF oder NIE eingeben."
#: contrib/localflavor/es/forms.py:68
msgid "Invalid checksum for NIF."
-msgstr ""
+msgstr "Ungültige Prüfsumme für NIF."
#: contrib/localflavor/es/forms.py:69
msgid "Invalid checksum for NIE."
-msgstr ""
+msgstr "Ungültige Prüfsumme für NIE."
#: contrib/localflavor/es/forms.py:70
msgid "Invalid checksum for CIF."
-msgstr ""
+msgstr "Ungültige Prüfsumme für CIF."
#: contrib/localflavor/es/forms.py:142
#, fuzzy
-msgid "Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX."
-msgstr "Bitte eine gültige deutsche Personalausweisnummer im Format XXXXXXXXXXX-XXXXXXX-XXXXXXX-X eingeben."
+msgid ""
+"Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX."
+msgstr ""
+"Bitte eine gültige Kontonummer im Format XXXX-XXXX-XX-XXXXXXXXXX eingeben."
#: contrib/localflavor/es/forms.py:143
msgid "Invalid checksum for bank account number."
-msgstr ""
+msgstr "Ungültige Prüfsumme für Kontonummer."
#: contrib/localflavor/fi/forms.py:28
msgid "Enter a valid Finnish social security number."
@@ -2228,35 +2343,39 @@ msgstr "Bitte eine gültige finnische Sozialversicherungsnummer eingeben."
#: contrib/localflavor/in_/forms.py:14
#, fuzzy
msgid "Enter a zip code in the format XXXXXXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXX-XXX eingeben."
+msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX eingeben."
#: contrib/localflavor/is_/forms.py:17
#, fuzzy
-msgid "Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXX-XXX eingeben."
+msgid ""
+"Enter a valid Icelandic identification number. The format is XXXXXX-XXXX."
+msgstr ""
+"Bitte eine gültige isländische Identifikationsnummer im Format XXXXXX-XXXX "
+"eingeben."
#: contrib/localflavor/is_/forms.py:18
msgid "The Icelandic identification number is not valid."
-msgstr ""
+msgstr "Die isländische Identifikationsnummer ist nicht gültig."
#: contrib/localflavor/it/forms.py:14
#, fuzzy
msgid "Enter a valid zip code."
-msgstr "Bitte ein gültiges Datum eingeben."
+msgstr "Bitte eine Postleitzahl eingeben."
#: contrib/localflavor/it/forms.py:43
#, fuzzy
msgid "Enter a valid Social Security number."
-msgstr "Bitte eine gültige finnische Sozialversicherungsnummer eingeben."
+msgstr "Bitte eine gültige Sozialversicherungsnummer eingeben."
#: contrib/localflavor/it/forms.py:68
#, fuzzy
msgid "Enter a valid VAT number."
-msgstr "Bitte eine gültige Uhrzeit eingeben."
+msgstr "Bitte eine gültige Umsatzsteuernummer eingeben."
#: contrib/localflavor/jp/forms.py:17
msgid "Enter a postal code in the format XXXXXXX or XXX-XXXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
#: contrib/localflavor/jp/jp_prefectures.py:4
msgid "Hokkaido"
@@ -2408,7 +2527,7 @@ msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:41
msgid "Ehime"
-msgstr "Zeit"
+msgstr ""
#: contrib/localflavor/jp/jp_prefectures.py:42
msgid "Kochi"
@@ -2461,7 +2580,7 @@ msgstr ""
#: contrib/localflavor/mx/mx_states.py:15
#, fuzzy
msgid "Campeche"
-msgstr "Tschechisch"
+msgstr ""
#: contrib/localflavor/mx/mx_states.py:16
msgid "Chihuahua"
@@ -2490,7 +2609,7 @@ msgstr ""
#: contrib/localflavor/mx/mx_states.py:22
#, fuzzy
msgid "Guerrero"
-msgstr "Serverfehler"
+msgstr ""
#: contrib/localflavor/mx/mx_states.py:23
msgid "Guanajuato"
@@ -2543,7 +2662,7 @@ msgstr ""
#: contrib/localflavor/mx/mx_states.py:35
#, fuzzy
msgid "Sinaloa"
-msgstr "Slowakisch"
+msgstr ""
#: contrib/localflavor/mx/mx_states.py:36
msgid "San Luis Potosí"
@@ -2580,22 +2699,22 @@ msgstr ""
#: contrib/localflavor/nl/forms.py:21
#, fuzzy
msgid "Enter a valid postal code"
-msgstr "Bitte einen gültigen Wert eingeben."
+msgstr "Bitte eine gültige Postleitzahl eingeben."
#: contrib/localflavor/nl/forms.py:52
#, fuzzy
msgid "Enter a valid phone number"
-msgstr "Bitte eine ganze Zahl eingeben."
+msgstr "Bitte eine gültige Telefonnummer eingeben."
#: contrib/localflavor/nl/forms.py:78
#, fuzzy
msgid "Enter a valid SoFi number"
-msgstr "Bitte eine gültige Uhrzeit eingeben."
+msgstr "Bitte eine gültige SoFi-Nummer eingeben."
#: contrib/localflavor/nl/nl_provinces.py:4
#, fuzzy
msgid "Drente"
-msgstr "Löschen"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:5
msgid "Flevoland"
@@ -2608,17 +2727,17 @@ msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:7
#, fuzzy
msgid "Gelderland"
-msgstr "Deutsch"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:8
#, fuzzy
msgid "Groningen"
-msgstr "neun"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:9
#, fuzzy
msgid "Limburg"
-msgstr "Hamburg"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:10
msgid "Noord-Brabant"
@@ -2635,12 +2754,12 @@ msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:13
#, fuzzy
msgid "Utrecht"
-msgstr "Französisch"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:14
#, fuzzy
msgid "Zeeland"
-msgstr "Isländisch"
+msgstr ""
#: contrib/localflavor/nl/nl_provinces.py:15
msgid "Zuid-Holland"
@@ -2653,47 +2772,52 @@ msgstr "Bitte eine gültige norwegische Sozialversicherungsnummer eingeben."
#: contrib/localflavor/pe/forms.py:24
#, fuzzy
msgid "This field requires 8 digits."
-msgstr "Dieses Feld ist zwingend erforderlich."
+msgstr "Dieses Feld benötigt 8 Zeichen."
#: contrib/localflavor/pe/forms.py:52
#, fuzzy
msgid "This field requires 11 digits."
-msgstr "Dieses Feld ist zwingend erforderlich."
+msgstr "Dieses Feld benötigt 11 Zeichen."
#: contrib/localflavor/pl/forms.py:39
msgid "National Identification Number consists of 11 digits."
-msgstr ""
+msgstr "Nationale Identifikationsnummer besteht aus 11 Ziffern."
#: contrib/localflavor/pl/forms.py:40
msgid "Wrong checksum for the National Identification Number."
-msgstr ""
+msgstr "Falsche Prüfsumme für die nationale Identifikationsnummer."
#: contrib/localflavor/pl/forms.py:72
#, fuzzy
-msgid "Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgid ""
+"Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX."
+msgstr ""
+"Bitte eine Steuernummer (NIP) im Format XXX-XXX-XX-XX oder XX-XX-XXX-XXX "
+"eingeben."
#: contrib/localflavor/pl/forms.py:73
msgid "Wrong checksum for the Tax Number (NIP)."
-msgstr ""
+msgstr "Falsche Prüfsumme für die Steuernummer (NIP)."
#: contrib/localflavor/pl/forms.py:112
msgid "National Business Register Number (REGON) consists of 7 or 9 digits."
-msgstr ""
+msgstr "Nationale Geschäftsregistrierungsnummer (REGON) besteht aus 7 oder "
+"9 Zeichen."
#: contrib/localflavor/pl/forms.py:113
msgid "Wrong checksum for the National Business Register Number (REGON)."
-msgstr ""
+msgstr "Falsche Prüfsumme für die nationale Geschäftsregistrierungsnummer "
+"(REGON)."
#: contrib/localflavor/pl/forms.py:156
#, fuzzy
msgid "Enter a postal code in the format XX-XXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXX eingeben."
+msgstr "Bitte eine gültige Postleitzahl im Format XX-XXX eingeben."
#: contrib/localflavor/pl/pl_voivodeships.py:8
#, fuzzy
msgid "Lower Silesia"
-msgstr "Niedersachsen"
+msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:9
msgid "Kuyavia-Pomerania"
@@ -2722,7 +2846,7 @@ msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:15
#, fuzzy
msgid "Opole"
-msgstr "Optional"
+msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:16
msgid "Subcarpatia"
@@ -2735,12 +2859,12 @@ msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:18
#, fuzzy
msgid "Pomerania"
-msgstr "Rumänisch"
+msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:19
#, fuzzy
msgid "Silesia"
-msgstr "Slowenisch"
+msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:20
msgid "Swietokrzyskie"
@@ -2757,12 +2881,13 @@ msgstr ""
#: contrib/localflavor/pl/pl_voivodeships.py:23
#, fuzzy
msgid "West Pomerania"
-msgstr "Mecklenburg-Vorpommern"
+msgstr ""
#: contrib/localflavor/sk/forms.py:30
#, fuzzy
msgid "Enter a postal code in the format XXXXX or XXX XX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXXXX oder XXX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige Postleitzahl im Format XXXXX oder XXX XX eingeben."
#: contrib/localflavor/sk/sk_districts.py:8
msgid "Banska Bystrica"
@@ -2783,7 +2908,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:12
#, fuzzy
msgid "Brezno"
-msgstr "Bremen"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:13
msgid "Bratislava I"
@@ -2828,12 +2953,12 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:23
#, fuzzy
msgid "Galanta"
-msgstr "Galicisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:24
#, fuzzy
msgid "Gelnica"
-msgstr "Galicisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:25
msgid "Hlohovec"
@@ -2854,7 +2979,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:29
#, fuzzy
msgid "Komarno"
-msgstr "Koreanisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:30
msgid "Kosice I"
@@ -2903,12 +3028,12 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:41
#, fuzzy
msgid "Malacky"
-msgstr "Mai"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:42
#, fuzzy
msgid "Martin"
-msgstr "Lettisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:43
msgid "Medzilaborce"
@@ -2949,7 +3074,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:52
#, fuzzy
msgid "Piestany"
-msgstr "Persisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:53
msgid "Poltar"
@@ -2994,7 +3119,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:63
#, fuzzy
msgid "Sabinov"
-msgstr "Nov"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:64
msgid "Senec"
@@ -3003,17 +3128,17 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:65
#, fuzzy
msgid "Senica"
-msgstr "Slowenisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:66
#, fuzzy
msgid "Skalica"
-msgstr "Galicisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:67
#, fuzzy
msgid "Snina"
-msgstr "neun"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:68
msgid "Sobrance"
@@ -3038,7 +3163,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:73
#, fuzzy
msgid "Sala"
-msgstr "Saarland"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:74
msgid "Topolcany"
@@ -3051,7 +3176,7 @@ msgstr ""
#: contrib/localflavor/sk/sk_districts.py:76
#, fuzzy
msgid "Trencin"
-msgstr "Französisch"
+msgstr ""
#: contrib/localflavor/sk/sk_districts.py:77
msgid "Trnava"
@@ -3128,7 +3253,7 @@ msgstr ""
#: contrib/localflavor/uk/forms.py:21
#, fuzzy
msgid "Enter a valid postcode."
-msgstr "Bitte ein gültiges Datum eingeben."
+msgstr "Bitte eine gültige Postleitzahl eingeben."
#: contrib/localflavor/uk/uk_regions.py:11
msgid "Bedfordshire"
@@ -3157,7 +3282,7 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:18
#, fuzzy
msgid "Devon"
-msgstr "sieben"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:19
msgid "Dorset"
@@ -3198,7 +3323,7 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:28
#, fuzzy
msgid "Kent"
-msgstr "Koreanisch"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:29
msgid "Lancashire"
@@ -3352,7 +3477,7 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:75
#, fuzzy
msgid "Borders"
-msgstr "Reihenfolge:"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:76
msgid "Central Scotland"
@@ -3365,12 +3490,12 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:78
#, fuzzy
msgid "Fife"
-msgstr "Filter"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:79
#, fuzzy
msgid "Grampian"
-msgstr "Deutsch"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:80
msgid "Highland"
@@ -3379,7 +3504,7 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:81
#, fuzzy
msgid "Lothian"
-msgstr "Lettisch"
+msgstr ""
#: contrib/localflavor/uk/uk_regions.py:82
msgid "Orkney Islands"
@@ -3404,54 +3529,57 @@ msgstr ""
#: contrib/localflavor/uk/uk_regions.py:90
#, fuzzy
msgid "England"
-msgstr "und"
+msgstr "England"
#: contrib/localflavor/uk/uk_regions.py:91
msgid "Northern Ireland"
-msgstr ""
+msgstr "Nordirland"
#: contrib/localflavor/uk/uk_regions.py:92
#, fuzzy
msgid "Scotland"
-msgstr "Saarland"
+msgstr "Schottland"
#: contrib/localflavor/uk/uk_regions.py:93
#, fuzzy
msgid "Wales"
-msgstr "Walisisch"
+msgstr "Wales"
#: contrib/localflavor/us/forms.py:16
msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
-msgstr "Bitte eine gültige Postleitzahl im Format XXXXX oder XXXXX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige Postleitzahl im Format XXXXX oder XXXXX-XXXX eingeben."
#: contrib/localflavor/us/forms.py:54
msgid "Enter a valid U.S. Social Security number in XXX-XX-XXXX format."
-msgstr "Bitte eine gültige US-amerikanische Sozialversicherungsnummer im Format XXX-XX-XXXX eingeben."
+msgstr ""
+"Bitte eine gültige US-amerikanische Sozialversicherungsnummer im Format XXX-"
+"XX-XXXX eingeben."
#: contrib/localflavor/za/forms.py:20
#, fuzzy
msgid "Enter a valid South African ID number"
-msgstr "Bitte eine gültige norwegische Sozialversicherungsnummer eingeben."
+msgstr "Bitte eine gültige südafrikanische Sozialversicherungsnummer eingeben."
#: contrib/localflavor/za/forms.py:54
#, fuzzy
msgid "Enter a valid South African postal code"
-msgstr "Bitte eine gültige vierstellige Postleitzahl eingeben."
+msgstr "Bitte eine gültige südafrikanische Postleitzahl eingeben."
#: contrib/localflavor/za/za_provinces.py:4
#, fuzzy
msgid "Eastern Cape"
-msgstr "Benutzername"
+msgstr ""
#: contrib/localflavor/za/za_provinces.py:5
#, fuzzy
msgid "Free State"
-msgstr "Bewertungsdatum"
+msgstr ""
#: contrib/localflavor/za/za_provinces.py:6
#, fuzzy
msgid "Gauteng"
-msgstr "Aug"
+msgstr ""
#: contrib/localflavor/za/za_provinces.py:7
msgid "KwaZulu-Natal"
@@ -3472,28 +3600,36 @@ msgstr ""
#: contrib/localflavor/za/za_provinces.py:11
#, fuzzy
msgid "North West"
-msgstr "Nordrhein-Westfalen"
+msgstr ""
#: contrib/localflavor/za/za_provinces.py:12
#, fuzzy
msgid "Western Cape"
-msgstr "Benutzername"
+msgstr ""
#: contrib/redirects/models.py:7
msgid "redirect from"
msgstr "Umleitung von"
#: contrib/redirects/models.py:8
-msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
-msgstr "Hier sollte ein absoluter Pfad stehen, ohne den Domainnamen. Beispiel: '/events/search/'."
+msgid ""
+"This should be an absolute path, excluding the domain name. Example: '/"
+"events/search/'."
+msgstr ""
+"Hier sollte ein absoluter Pfad stehen, ohne den Domainnamen. Beispiel: '/"
+"events/search/'."
#: contrib/redirects/models.py:9
msgid "redirect to"
msgstr "Umleitung zu"
#: contrib/redirects/models.py:10
-msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
-msgstr "Hier muss entweder ein absoluter Pfad oder eine komplette URL mit http:// am Anfang stehen."
+msgid ""
+"This can be either an absolute path (as above) or a full URL starting with "
+"'http://'."
+msgstr ""
+"Hier muss entweder ein absoluter Pfad oder eine komplette URL mit http:// am "
+"Anfang stehen."
#: contrib/redirects/models.py:13
msgid "redirect"
@@ -3544,12 +3680,18 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "Dieser Wert darf nur Buchstaben, Ziffern und Unterstriche enthalten."
#: core/validators.py:76
-msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
-msgstr "Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Schrägstriche enthalten."
+msgid ""
+"This value must contain only letters, numbers, underscores, dashes or "
+"slashes."
+msgstr ""
+"Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Schrägstriche "
+"enthalten."
#: core/validators.py:80
msgid "This value must contain only letters, numbers, underscores or hyphens."
-msgstr "Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Bindestriche enthalten."
+msgstr ""
+"Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Bindestriche "
+"enthalten."
#: core/validators.py:84
msgid "Uppercase letters are not allowed here."
@@ -3583,8 +3725,7 @@ msgstr "Nichtnumerische Zeichen sind hier nicht erlaubt."
msgid "This value can't be comprised solely of digits."
msgstr "Dieser Wert darf nicht nur aus Ziffern bestehen."
-#: core/validators.py:128
-#: newforms/fields.py:151
+#: core/validators.py:128 newforms/fields.py:151
msgid "Enter a whole number."
msgstr "Bitte eine ganze Zahl eingeben."
@@ -3601,8 +3742,7 @@ msgstr "Das Jahr muss 1900 oder später sein."
msgid "Invalid date: %s"
msgstr "Ungültiges Datum: %s"
-#: core/validators.py:156
-#: db/models/fields/__init__.py:522
+#: core/validators.py:156 db/models/fields/__init__.py:527
msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Bitte ein gültiges Datum im Format JJJJ-MM-TT eingeben."
@@ -3610,27 +3750,29 @@ msgstr "Bitte ein gültiges Datum im Format JJJJ-MM-TT eingeben."
msgid "Enter a valid time in HH:MM format."
msgstr "Bitte eine gültige Zeit im Format SS:MM eingeben."
-#: core/validators.py:165
-#: db/models/fields/__init__.py:599
+#: core/validators.py:165 db/models/fields/__init__.py:604
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
-msgstr "Bitte eine gültige Datums- und Zeitangabe im Format JJJJ-MM-TT SS:MM eingeben."
+msgstr ""
+"Bitte eine gültige Datums- und Zeitangabe im Format JJJJ-MM-TT SS:MM "
+"eingeben."
-#: core/validators.py:170
-#: newforms/fields.py:402
+#: core/validators.py:170 newforms/fields.py:402
msgid "Enter a valid e-mail address."
msgstr "Bitte eine gültige E-Mail-Adresse eingeben."
-#: core/validators.py:182
-#: core/validators.py:474
-#: newforms/fields.py:432
+#: 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 "Es wurde keine Datei übermittelt. Eventuell ist das Formular-Encoding falsch."
+msgstr ""
+"Es wurde keine Datei übermittelt. Eventuell ist das Formular-Encoding falsch."
-#: core/validators.py:193
-#: newforms/fields.py:458
-msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
-msgstr "Bitte ein Bild hochladen. Die hochgeladene Datei ist kein Bild, oder ist defekt."
+#: core/validators.py:193 newforms/fields.py:458
+msgid ""
+"Upload a valid image. The file you uploaded was either not an image or a "
+"corrupted image."
+msgstr ""
+"Bitte ein Bild hochladen. Die hochgeladene Datei ist kein Bild, oder ist "
+"defekt."
#: core/validators.py:200
#, python-format
@@ -3640,7 +3782,8 @@ msgstr "Die URL %s zeigt nicht auf ein gültiges Bild."
#: core/validators.py:204
#, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
-msgstr "Telefonnummern müssen das Format XXX-XXX-XXXX haben. \"%s\" ist ungültig."
+msgstr ""
+"Telefonnummern müssen das Format XXX-XXX-XXXX haben. \"%s\" ist ungültig."
#: core/validators.py:212
#, python-format
@@ -3670,8 +3813,7 @@ msgstr "Ungültiges XML: %s"
msgid "Invalid URL: %s"
msgstr "Ungültige URL: %s"
-#: core/validators.py:259
-#: core/validators.py:261
+#: core/validators.py:259 core/validators.py:261
#, python-format
msgid "The URL %s is a broken link."
msgstr "Die URL %s funktioniert nicht."
@@ -3696,20 +3838,21 @@ msgstr "Dieses Feld muss zum Feld '%s' passen."
msgid "Please enter something for at least one field."
msgstr "Bitte mindestens eines der Felder ausfüllen."
-#: core/validators.py:316
-#: core/validators.py:327
+#: core/validators.py:316 core/validators.py:327
msgid "Please enter both fields or leave them both empty."
msgstr "Bitte entweder beide Felder ausfüllen, oder beide leer lassen."
#: core/validators.py:335
#, python-format
msgid "This field must be given if %(field)s is %(value)s"
-msgstr "Dieses Feld muss gefüllt sein, wenn Feld %(field)s den Wert %(value)s hat."
+msgstr ""
+"Dieses Feld muss gefüllt sein, wenn Feld %(field)s den Wert %(value)s hat."
#: core/validators.py:348
#, python-format
msgid "This field must be given if %(field)s is not %(value)s"
-msgstr "Dieses Feld muss gefüllt sein, wenn Feld %(field)s nicht %(value)s ist."
+msgstr ""
+"Dieses Feld muss gefüllt sein, wenn Feld %(field)s nicht %(value)s ist."
#: core/validators.py:367
msgid "Duplicate values are not allowed."
@@ -3742,23 +3885,33 @@ msgstr "Bitte eine gültige Dezimalzahl eingeben."
#: core/validators.py:444
#, python-format
msgid "Please enter a valid decimal number with at most %s total digit."
-msgid_plural "Please enter a valid decimal number with at most %s total digits."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s total digits."
msgstr[0] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffer eingeben."
msgstr[1] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffern eingeben."
#: core/validators.py:447
#, python-format
-msgid "Please enter a valid decimal number with a whole part of at most %s digit."
-msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits."
-msgstr[0] "Bitte eine gültige Dezimalzahl mit einer Gesamtzahl von maximal %s Ziffer eingeben."
-msgstr[1] "Bitte eine gültige Dezimalzahl mit einer Gesamtzahl von maximal %s Ziffern eingeben."
+msgid ""
+"Please enter a valid decimal number with a whole part of at most %s digit."
+msgid_plural ""
+"Please enter a valid decimal number with a whole part of at most %s digits."
+msgstr[0] ""
+"Bitte eine gültige Dezimalzahl mit einer Gesamtzahl von maximal %s Ziffer "
+"eingeben."
+msgstr[1] ""
+"Bitte eine gültige Dezimalzahl mit einer Gesamtzahl von maximal %s Ziffern "
+"eingeben."
#: core/validators.py:450
#, python-format
msgid "Please enter a valid decimal number with at most %s decimal place."
-msgid_plural "Please enter a valid decimal number with at most %s decimal places."
-msgstr[0] "Bitte eine gültige Dezimalzahl mit maximal %s Dezimalstelle eingeben."
-msgstr[1] "Bitte eine gültige Dezimalzahl mit maximal %s Dezimalstellen eingeben."
+msgid_plural ""
+"Please enter a valid decimal number with at most %s decimal places."
+msgstr[0] ""
+"Bitte eine gültige Dezimalzahl mit maximal %s Dezimalstelle eingeben."
+msgstr[1] ""
+"Bitte eine gültige Dezimalzahl mit maximal %s Dezimalstellen eingeben."
#: core/validators.py:458
msgid "Please enter a valid floating point number."
@@ -3767,12 +3920,15 @@ msgstr "Bitte eine gültige Dezimalzahl eingeben."
#: core/validators.py:467
#, python-format
msgid "Make sure your uploaded file is at least %s bytes big."
-msgstr "Bitte sicherstellen, dass die hochgeladene Datei mindestens %s Bytes groß ist."
+msgstr ""
+"Bitte sicherstellen, dass die hochgeladene Datei mindestens %s Bytes groß "
+"ist."
#: core/validators.py:468
#, python-format
msgid "Make sure your uploaded file is at most %s bytes big."
-msgstr "Bitte sicherstellen, dass die hochgeladene Datei maximal %s Bytes groß ist."
+msgstr ""
+"Bitte sicherstellen, dass die hochgeladene Datei maximal %s Bytes groß ist."
#: core/validators.py:485
msgid "The format for this field is wrong."
@@ -3789,79 +3945,103 @@ msgstr "Konnte nichts von %s empfangen."
#: core/validators.py:539
#, python-format
-msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
+msgid ""
+"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "Die URL %(url)s lieferte den falschen Content-Type '%(contenttype)s'."
#: core/validators.py:572
#, python-format
-msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
-msgstr "Bitte das ungeschlossene %(tag)s Tag in Zeile %(line)s schließen. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
+"\"%(start)s\".)"
+msgstr ""
+"Bitte das ungeschlossene %(tag)s Tag in Zeile %(line)s schließen. Die Zeile "
+"beginnt mit \"%(start)s\"."
#: core/validators.py:576
#, python-format
-msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
-msgstr "In Zeile %(line)s ist Text, der nicht in dem Kontext erlaubt ist. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"Some text starting on line %(line)s is not allowed in that context. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"In Zeile %(line)s ist Text, der nicht in dem Kontext erlaubt ist. Die Zeile "
+"beginnt mit \"%(start)s\"."
#: core/validators.py:581
#, python-format
-msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
-msgstr "Das Attribute %(attr)s in Zeile %(line)s ist ungültig. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"Das Attribute %(attr)s in Zeile %(line)s ist ungültig. Die Zeile beginnt mit "
+"\"%(start)s\"."
#: core/validators.py:586
#, python-format
-msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
-msgstr "<%(tag)s> in Zeile %(line)s ist ungültig. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
+"(start)s\".)"
+msgstr ""
+"<%(tag)s> in Zeile %(line)s ist ungültig. Die Zeile beginnt mit \"%(start)s"
+"\"."
#: core/validators.py:590
#, python-format
-msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
-msgstr "Ein Tag in Zeile %(line)s hat eines oder mehrere Pflichtattribute nicht. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"A tag on line %(line)s is missing one or more required attributes. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"Ein Tag in Zeile %(line)s hat eines oder mehrere Pflichtattribute nicht. Die "
+"Zeile beginnt mit \"%(start)s\"."
#: core/validators.py:595
#, python-format
-msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
-msgstr "Das Attribut %(attr)s in Zeile %(line)s hat einen ungültigen Wert. Die Zeile beginnt mit \"%(start)s\"."
+msgid ""
+"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
+"starts with \"%(start)s\".)"
+msgstr ""
+"Das Attribut %(attr)s in Zeile %(line)s hat einen ungültigen Wert. Die Zeile "
+"beginnt mit \"%(start)s\"."
#: db/models/manipulators.py:308
#, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
-msgstr "Ein '%(object)s' in dieser '%(type)s' existiert bereits für dieses '%(field)s'."
+msgstr ""
+"Ein '%(object)s' in dieser '%(type)s' existiert bereits für dieses '%(field)"
+"s'."
#: db/models/fields/__init__.py:52
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "Ein '%(optname)s' mit diesem '%(fieldname)s' existiert bereits."
-#: db/models/fields/__init__.py:161
-#: db/models/fields/__init__.py:322
-#: db/models/fields/__init__.py:754
-#: db/models/fields/__init__.py:765
-#: newforms/fields.py:45
-#: oldforms/__init__.py:374
+#: db/models/fields/__init__.py:161 db/models/fields/__init__.py:327
+#: db/models/fields/__init__.py:759 db/models/fields/__init__.py:770
+#: newforms/fields.py:45 oldforms/__init__.py:374
msgid "This field is required."
msgstr "Dieses Feld ist zwingend erforderlich."
-#: db/models/fields/__init__.py:422
+#: db/models/fields/__init__.py:427
msgid "This value must be an integer."
msgstr "Dieser Wert muss eine Ganzzahl sein."
-#: db/models/fields/__init__.py:461
+#: db/models/fields/__init__.py:466
msgid "This value must be either True or False."
msgstr "Dieser Wert muss wahr oder falsch sein."
-#: db/models/fields/__init__.py:485
+#: db/models/fields/__init__.py:490
msgid "This field cannot be null."
msgstr "Dieses Feld darf nicht leer sein."
-#: db/models/fields/__init__.py:663
+#: db/models/fields/__init__.py:668
msgid "This value must be a decimal number."
msgstr "Dieser Wert muss eine Ganzzahl sein."
-#: db/models/fields/__init__.py:774
+#: db/models/fields/__init__.py:779
msgid "Enter a valid filename."
msgstr "Bitte einen gültigen Dateinamen eingeben."
-#: db/models/fields/__init__.py:945
+#: db/models/fields/__init__.py:950
msgid "This value must be either None, True or False."
msgstr "Dieser Wert muss None, True oder False sein."
@@ -3875,15 +4055,21 @@ msgid "Separate multiple IDs with commas."
msgstr "Mehrere IDs können mit Komma getrennt werden."
#: db/models/fields/related.py:696
-msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
-msgstr "Um mehr als eine Selektion zu treffen, \"Strg\", oder auf dem Mac \"Command\", beim Klicken gedrückt halten."
+msgid ""
+"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
+msgstr ""
+"Um mehr als eine Selektion zu treffen, \"Strg\", oder auf dem Mac \"Command"
+"\", beim Klicken gedrückt halten."
#: db/models/fields/related.py:743
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
-msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
-msgstr[0] "Bitte gültige IDs für %(self)s eingeben. Der Wert %(value)r ist ungültig."
-msgstr[1] "Bitte gültige IDs für %(self)s eingeben. Die Werte %(value)r sind ungültig."
+msgid_plural ""
+"Please enter valid %(self)s IDs. The values %(value)r are invalid."
+msgstr[0] ""
+"Bitte gültige IDs für %(self)s eingeben. Der Wert %(value)r ist ungültig."
+msgstr[1] ""
+"Bitte gültige IDs für %(self)s eingeben. Die Werte %(value)r sind ungültig."
#: newforms/fields.py:46
msgid "Enter a valid value."
@@ -3892,29 +4078,28 @@ msgstr "Bitte einen gültigen Wert eingeben."
#: newforms/fields.py:123
#, python-format
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
-msgstr "Bitte sicherstellen, dass der Text maximal %(max)d Zeichen hat. (Er hat %(length)d)."
+msgstr ""
+"Bitte sicherstellen, dass der Text maximal %(max)d Zeichen hat. (Er hat %"
+"(length)d)."
#: newforms/fields.py:124
#, python-format
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
-msgstr "Bitte sicherstellen, dass der Text wenigstens %(min)d Zeichen hat. (Er hat %(length)d.)"
+msgstr ""
+"Bitte sicherstellen, dass der Text wenigstens %(min)d Zeichen hat. (Er hat %"
+"(length)d.)"
-#: newforms/fields.py:152
-#: newforms/fields.py:181
-#: newforms/fields.py:210
+#: 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 "Dieser Wert darf maximal %s sein."
-#: newforms/fields.py:153
-#: newforms/fields.py:182
-#: newforms/fields.py:211
+#: 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 "Dieser Wert muss größer oder gleich %s sein."
-#: newforms/fields.py:180
-#: newforms/fields.py:209
+#: newforms/fields.py:180 newforms/fields.py:209
msgid "Enter a number."
msgstr "Bitte eine Zahl eingeben."
@@ -3933,13 +4118,11 @@ msgstr "Bitte geben Sie nicht mehr als %s Dezimalstellen ein."
msgid "Ensure that there are no more than %s digits before the decimal point."
msgstr "Bitte geben Sie nicht mehr als %s Ziffern vor dem Komma ein."
-#: newforms/fields.py:262
-#: newforms/fields.py:723
+#: newforms/fields.py:262 newforms/fields.py:723
msgid "Enter a valid date."
msgstr "Bitte ein gültiges Datum eingeben."
-#: newforms/fields.py:295
-#: newforms/fields.py:724
+#: newforms/fields.py:295 newforms/fields.py:724
msgid "Enter a valid time."
msgstr "Bitte eine gültige Uhrzeit eingeben."
@@ -3951,8 +4134,7 @@ msgstr "Bitte gültiges Datum und Uhrzeit eingeben."
msgid "No file was submitted."
msgstr "Es wurde keine Datei übertragen."
-#: newforms/fields.py:434
-#: oldforms/__init__.py:689
+#: newforms/fields.py:434 oldforms/__init__.py:689
msgid "The submitted file is empty."
msgstr "Die ausgewählte Datei ist leer."
@@ -3964,19 +4146,17 @@ msgstr "Bitte eine gültige Adresse eingeben."
msgid "This URL appears to be a broken link."
msgstr "Diese Adresse scheint nicht gültig zu sein."
-#: newforms/fields.py:559
-#: newforms/models.py:300
+#: newforms/fields.py:559 newforms/models.py:300
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr "Bitte eine gültige Auswahl treffen."
#: newforms/fields.py:598
#, python-format
msgid "Select a valid choice. %(value)s is not one of the available choices."
-msgstr "Bitte eine gültige Auswahl treffen. %(value)s ist keine gültige Auswahl."
+msgstr ""
+"Bitte eine gültige Auswahl treffen. %(value)s ist keine gültige Auswahl."
-#: newforms/fields.py:599
-#: newforms/fields.py:661
-#: newforms/models.py:360
+#: newforms/fields.py:599 newforms/fields.py:661 newforms/models.py:360
msgid "Enter a list of values."
msgstr "Eine Liste mit Werten eingeben."
@@ -4000,12 +4180,11 @@ msgstr[1] "Bitte sicherstellen, dass der Text weniger als %s Zeichen hat."
msgid "Line breaks are not allowed here."
msgstr "Zeilenumbrüche sind hier nicht erlaubt."
-#: oldforms/__init__.py:512
-#: oldforms/__init__.py:586
-#: oldforms/__init__.py:625
+#: 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 "Bitte eine gültige Auswahl treffen; '%(data)s' ist nicht in %(choices)s."
+msgstr ""
+"Bitte eine gültige Auswahl treffen; '%(data)s' ist nicht in %(choices)s."
#: oldforms/__init__.py:745
msgid "Enter a whole number between -32,768 and 32,767."
@@ -4133,28 +4312,23 @@ msgstr "Januar"
msgid "February"
msgstr "Februar"
-#: utils/dates.py:18
-#: utils/dates.py:31
+#: utils/dates.py:18 utils/dates.py:31
msgid "March"
msgstr "März"
-#: utils/dates.py:18
-#: utils/dates.py:31
+#: utils/dates.py:18 utils/dates.py:31
msgid "April"
msgstr "April"
-#: utils/dates.py:18
-#: utils/dates.py:31
+#: utils/dates.py:18 utils/dates.py:31
msgid "May"
msgstr "Mai"
-#: utils/dates.py:18
-#: utils/dates.py:31
+#: utils/dates.py:18 utils/dates.py:31
msgid "June"
msgstr "Juni"
-#: utils/dates.py:19
-#: utils/dates.py:31
+#: utils/dates.py:19 utils/dates.py:31
msgid "July"
msgstr "Juli"
@@ -4308,23 +4482,23 @@ msgstr "%(number)d %(type)s"
msgid ", %(number)d %(type)s"
msgstr ", %(number)d %(type)s"
-#: utils/translation/trans_real.py:404
+#: utils/translation/trans_real.py:403
msgid "DATE_FORMAT"
msgstr "j. N Y"
-#: utils/translation/trans_real.py:405
+#: utils/translation/trans_real.py:404
msgid "DATETIME_FORMAT"
msgstr "j. N Y, H:i"
-#: utils/translation/trans_real.py:406
+#: utils/translation/trans_real.py:405
msgid "TIME_FORMAT"
msgstr "H:i"
-#: utils/translation/trans_real.py:422
+#: utils/translation/trans_real.py:421
msgid "YEAR_MONTH_FORMAT"
msgstr "F Y"
-#: utils/translation/trans_real.py:423
+#: utils/translation/trans_real.py:422
msgid "MONTH_DAY_FORMAT"
msgstr "j. F"
@@ -4342,10 +4516,3 @@ msgstr "%(verbose_name)s wurde erfolgreich aktualisiert."
#, python-format
msgid "The %(verbose_name)s was deleted."
msgstr "%(verbose_name)s wurde gelöscht"
-
-#~ msgid ""
-#~ "Enter a postcode. A space is required between the two postcode parts."
-#~ msgstr ""
-#~ "Bitte eine gültige Postleitzahl eingeben. Ein Leerzeichen trennt die zwei "
-#~ "Teile."
-
diff --git a/django/contrib/admin/templates/admin_doc/index.html b/django/contrib/admin/templates/admin_doc/index.html
index 64766fb46f..750dd2f5ac 100644
--- a/django/contrib/admin/templates/admin_doc/index.html
+++ b/django/contrib/admin/templates/admin_doc/index.html
@@ -1,27 +1,27 @@
-{% extends "admin/base_site.html" %}
-{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
-{% block title %}Documentation{% endblock %}
-
-{% block content %}
-
-<h1>Documentation</h1>
-
-<div id="content-main">
- <h3><a href="tags/">Tags</a></h3>
- <p>List of all the template tags and their functions.</p>
-
- <h3><a href="filters/">Filters</a></h3>
- <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
-
- <h3><a href="models/">Models</a></h3>
- <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
-
- <h3><a href="views/">Views</a></h3>
- <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
-
- <h3><a href="bookmarklets/">Bookmarklets</a></h3>
- <p>Tools for your browser to quickly access admin functionality.</p>
-</div>
-
-{% endblock %}
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
+{% block title %}Documentation{% endblock %}
+
+{% block content %}
+
+<h1>Documentation</h1>
+
+<div id="content-main">
+ <h3><a href="tags/">Tags</a></h3>
+ <p>List of all the template tags and their functions.</p>
+
+ <h3><a href="filters/">Filters</a></h3>
+ <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
+
+ <h3><a href="models/">Models</a></h3>
+ <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
+
+ <h3><a href="views/">Views</a></h3>
+ <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
+
+ <h3><a href="bookmarklets/">Bookmarklets</a></h3>
+ <p>Tools for your browser to quickly access admin functionality.</p>
+</div>
+
+{% endblock %}
diff --git a/django/contrib/admin/templates/admin_doc/view_index.html b/django/contrib/admin/templates/admin_doc/view_index.html
index 1ed5ba2ac1..716e2d1a91 100644
--- a/django/contrib/admin/templates/admin_doc/view_index.html
+++ b/django/contrib/admin/templates/admin_doc/view_index.html
@@ -1,42 +1,42 @@
-{% extends "admin/base_site.html" %}
-{% load i18n %}
-{% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Views</div>{% endblock %}
-{% block title %}Views{% endblock %}
-
-{% block content %}
-
-<h1>View documentation</h1>
-
-{% regroup views|dictsort:"site_id" by site as views_by_site %}
-
-<div id="content-related" class="sidebar">
-<div class="module">
-<h2>Jump to site</h2>
-<ul>
- {% for site_views in views_by_site %}
- <li><a href="#site{{ site_views.grouper.id }}">{{ site_views.grouper.name }}</a></li>
- {% endfor %}
-</ul>
-</div>
-</div>
-
-<div id="content-main">
-
-{% for site_views in views_by_site %}
-<div class="module">
-<h2 id="site{{ site_views.grouper.id }}">Views by URL on {{ site_views.grouper.name }}</h2>
-
-{% for view in site_views.list|dictsort:"url" %}
-{% ifchanged %}
-<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3>
-<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
-<p>{{ view.title }}</p>
-<hr />
-{% endifchanged %}
-{% endfor %}
-</div>
-{% endfor %}
-</div>
-{% endblock %}
-
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+{% block coltype %}colSM{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Views</div>{% endblock %}
+{% block title %}Views{% endblock %}
+
+{% block content %}
+
+<h1>View documentation</h1>
+
+{% regroup views|dictsort:"site_id" by site as views_by_site %}
+
+<div id="content-related" class="sidebar">
+<div class="module">
+<h2>Jump to site</h2>
+<ul>
+ {% for site_views in views_by_site %}
+ <li><a href="#site{{ site_views.grouper.id }}">{{ site_views.grouper.name }}</a></li>
+ {% endfor %}
+</ul>
+</div>
+</div>
+
+<div id="content-main">
+
+{% for site_views in views_by_site %}
+<div class="module">
+<h2 id="site{{ site_views.grouper.id }}">Views by URL on {{ site_views.grouper.name }}</h2>
+
+{% for view in site_views.list|dictsort:"url" %}
+{% ifchanged %}
+<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3>
+<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
+<p>{{ view.title }}</p>
+<hr />
+{% endifchanged %}
+{% endfor %}
+</div>
+{% endfor %}
+</div>
+{% endblock %}
+
diff --git a/django/contrib/formtools/wizard.py b/django/contrib/formtools/wizard.py
index da2f0d56de..a197c3e659 100644
--- a/django/contrib/formtools/wizard.py
+++ b/django/contrib/formtools/wizard.py
@@ -1,246 +1,246 @@
-"""
-FormWizard class -- implements a multi-page form, validating between each
-step and storing the form's state as HTML hidden fields so that no state is
-stored on the server side.
-"""
-
-from django import newforms as forms
-from django.conf import settings
-from django.http import Http404
-from django.shortcuts import render_to_response
-from django.template.context import RequestContext
-import cPickle as pickle
-import md5
-
-class FormWizard(object):
- # Dictionary of extra template context variables.
- extra_context = {}
-
- # The HTML (and POST data) field name for the "step" variable.
- step_field_name="wizard_step"
-
- # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################
-
- def __init__(self, form_list, initial=None):
- "form_list should be a list of Form classes (not instances)."
- self.form_list = form_list[:]
- self.initial = initial or {}
- self.step = 0 # A zero-based counter keeping track of which step we're in.
-
- def __repr__(self):
- return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)
-
- def get_form(self, step, data=None):
- "Helper method that returns the Form instance for the given step."
- return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))
-
- def num_steps(self):
- "Helper method that returns the number of steps."
- # You might think we should just set "self.form_list = len(form_list)"
- # in __init__(), but this calculation needs to be dynamic, because some
- # hook methods might alter self.form_list.
- return len(self.form_list)
-
- def __call__(self, request, *args, **kwargs):
- """
- Main method that does all the hard work, conforming to the Django view
- interface.
- """
- if 'extra_context' in kwargs:
- self.extra_context.update(kwargs['extra_context'])
- current_step = self.determine_step(request, *args, **kwargs)
- self.parse_params(request, *args, **kwargs)
-
- # Sanity check.
- if current_step >= self.num_steps():
- raise Http404('Step %s does not exist' % current_step)
-
- # For each previous step, verify the hash and process.
- # TODO: Move "hash_%d" to a method to make it configurable.
- for i in range(current_step):
- form = self.get_form(i, request.POST)
- if request.POST.get("hash_%d" % i, '') != self.security_hash(request, form):
- return self.render_hash_failure(request, i)
- self.process_step(request, form, i)
-
- # Process the current step. If it's valid, go to the next step or call
- # done(), depending on whether any steps remain.
- if request.method == 'POST':
- form = self.get_form(current_step, request.POST)
- else:
- form = self.get_form(current_step)
- if form.is_valid():
- self.process_step(request, form, current_step)
- next_step = current_step + 1
-
- # If this was the last step, validate all of the forms one more
- # time, as a sanity check, and call done().
- num = self.num_steps()
- if next_step == num:
- final_form_list = [self.get_form(i, request.POST) for i in range(num)]
-
- # Validate all the forms. If any of them fail validation, that
- # must mean the validator relied on some other input, such as
- # an external Web site.
- for i, f in enumerate(final_form_list):
- if not f.is_valid():
- return self.render_revalidation_failure(request, i, f)
- return self.done(request, final_form_list)
-
- # Otherwise, move along to the next step.
- else:
- form = self.get_form(next_step)
- current_step = next_step
-
- return self.render(form, request, current_step)
-
- def render(self, form, request, step, context=None):
- "Renders the given Form object, returning an HttpResponse."
- old_data = request.POST
- prev_fields = []
- if old_data:
- hidden = forms.HiddenInput()
- # Collect all data from previous steps and render it as HTML hidden fields.
- for i in range(step):
- old_form = self.get_form(i, old_data)
- hash_name = 'hash_%s' % i
- prev_fields.extend([bf.as_hidden() for bf in old_form])
- prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
- return self.render_template(request, form, ''.join(prev_fields), step, context)
-
- # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
-
- def prefix_for_step(self, step):
- "Given the step, returns a Form prefix to use."
- return str(step)
-
- def render_hash_failure(self, request, step):
- """
- Hook for rendering a template if a hash check failed.
-
- step is the step that failed. Any previous step is guaranteed to be
- valid.
-
- This default implementation simply renders the form for the given step,
- but subclasses may want to display an error message, etc.
- """
- return self.render(self.get_form(step), request, step, context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
-
- def render_revalidation_failure(self, request, step, form):
- """
- Hook for rendering a template if final revalidation failed.
-
- It is highly unlikely that this point would ever be reached, but See
- the comment in __call__() for an explanation.
- """
- return self.render(form, request, step)
-
- def security_hash(self, request, form):
- """
- Calculates the security hash for the given HttpRequest and Form instances.
-
- This creates a list of the form field names/values in a deterministic
- order, pickles the result with the SECRET_KEY setting and takes an md5
- hash of that.
-
- Subclasses may want to take into account request-specific information,
- such as the IP address.
- """
- data = [(bf.name, bf.data or '') for bf in form] + [settings.SECRET_KEY]
- # Use HIGHEST_PROTOCOL because it's the most efficient. It requires
- # Python 2.3, but Django requires 2.3 anyway, so that's OK.
- pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
- return md5.new(pickled).hexdigest()
-
- def determine_step(self, request, *args, **kwargs):
- """
- Given the request object and whatever *args and **kwargs were passed to
- __call__(), returns the current step (which is zero-based).
-
- Note that the result should not be trusted. It may even be a completely
- invalid number. It's not the job of this method to validate it.
- """
- if not request.POST:
- return 0
- try:
- step = int(request.POST.get(self.step_field_name, 0))
- except ValueError:
- return 0
- return step
-
- def parse_params(self, request, *args, **kwargs):
- """
- Hook for setting some state, given the request object and whatever
- *args and **kwargs were passed to __call__(), sets some state.
-
- This is called at the beginning of __call__().
- """
- pass
-
- def get_template(self, step):
- """
- Hook for specifying the name of the template to use for a given step.
-
- Note that this can return a tuple of template names if you'd like to
- use the template system's select_template() hook.
- """
- return 'forms/wizard.html'
-
- def render_template(self, request, form, previous_fields, step, context=None):
- """
- Renders the template for the given step, returning an HttpResponse object.
-
- Override this method if you want to add a custom context, return a
- different MIME type, etc. If you only need to override the template
- name, use get_template() instead.
-
- The template will be rendered with the following context:
- step_field -- The name of the hidden field containing the step.
- step0 -- The current step (zero-based).
- step -- The current step (one-based).
- step_count -- The total number of steps.
- form -- The Form instance for the current step (either empty
- or with errors).
- previous_fields -- A string representing every previous data field,
- plus hashes for completed forms, all in the form of
- hidden fields. Note that you'll need to run this
- through the "safe" template filter, to prevent
- auto-escaping, because it's raw HTML.
- """
- context = context or {}
- context.update(self.extra_context)
- return render_to_response(self.get_template(self.step), dict(context,
- step_field=self.step_field_name,
- step0=step,
- step=step + 1,
- step_count=self.num_steps(),
- form=form,
- previous_fields=previous_fields
- ), context_instance=RequestContext(request))
-
- def process_step(self, request, form, step):
- """
- Hook for modifying the FormWizard's internal state, given a fully
- validated Form object. The Form is guaranteed to have clean, valid
- data.
-
- This method should *not* modify any of that data. Rather, it might want
- to set self.extra_context or dynamically alter self.form_list, based on
- previously submitted forms.
-
- Note that this method is called every time a page is rendered for *all*
- submitted steps.
- """
- pass
-
- # METHODS SUBCLASSES MUST OVERRIDE ########################################
-
- def done(self, request, form_list):
- """
- Hook for doing something with the validated data. This is responsible
- for the final processing.
-
- form_list is a list of Form instances, each containing clean, valid
- data.
- """
- raise NotImplementedError("Your %s class has not defined a done() method, which is required." % self.__class__.__name__)
+"""
+FormWizard class -- implements a multi-page form, validating between each
+step and storing the form's state as HTML hidden fields so that no state is
+stored on the server side.
+"""
+
+from django import newforms as forms
+from django.conf import settings
+from django.http import Http404
+from django.shortcuts import render_to_response
+from django.template.context import RequestContext
+import cPickle as pickle
+import md5
+
+class FormWizard(object):
+ # Dictionary of extra template context variables.
+ extra_context = {}
+
+ # The HTML (and POST data) field name for the "step" variable.
+ step_field_name="wizard_step"
+
+ # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################
+
+ def __init__(self, form_list, initial=None):
+ "form_list should be a list of Form classes (not instances)."
+ self.form_list = form_list[:]
+ self.initial = initial or {}
+ self.step = 0 # A zero-based counter keeping track of which step we're in.
+
+ def __repr__(self):
+ return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)
+
+ def get_form(self, step, data=None):
+ "Helper method that returns the Form instance for the given step."
+ return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))
+
+ def num_steps(self):
+ "Helper method that returns the number of steps."
+ # You might think we should just set "self.form_list = len(form_list)"
+ # in __init__(), but this calculation needs to be dynamic, because some
+ # hook methods might alter self.form_list.
+ return len(self.form_list)
+
+ def __call__(self, request, *args, **kwargs):
+ """
+ Main method that does all the hard work, conforming to the Django view
+ interface.
+ """
+ if 'extra_context' in kwargs:
+ self.extra_context.update(kwargs['extra_context'])
+ current_step = self.determine_step(request, *args, **kwargs)
+ self.parse_params(request, *args, **kwargs)
+
+ # Sanity check.
+ if current_step >= self.num_steps():
+ raise Http404('Step %s does not exist' % current_step)
+
+ # For each previous step, verify the hash and process.
+ # TODO: Move "hash_%d" to a method to make it configurable.
+ for i in range(current_step):
+ form = self.get_form(i, request.POST)
+ if request.POST.get("hash_%d" % i, '') != self.security_hash(request, form):
+ return self.render_hash_failure(request, i)
+ self.process_step(request, form, i)
+
+ # Process the current step. If it's valid, go to the next step or call
+ # done(), depending on whether any steps remain.
+ if request.method == 'POST':
+ form = self.get_form(current_step, request.POST)
+ else:
+ form = self.get_form(current_step)
+ if form.is_valid():
+ self.process_step(request, form, current_step)
+ next_step = current_step + 1
+
+ # If this was the last step, validate all of the forms one more
+ # time, as a sanity check, and call done().
+ num = self.num_steps()
+ if next_step == num:
+ final_form_list = [self.get_form(i, request.POST) for i in range(num)]
+
+ # Validate all the forms. If any of them fail validation, that
+ # must mean the validator relied on some other input, such as
+ # an external Web site.
+ for i, f in enumerate(final_form_list):
+ if not f.is_valid():
+ return self.render_revalidation_failure(request, i, f)
+ return self.done(request, final_form_list)
+
+ # Otherwise, move along to the next step.
+ else:
+ form = self.get_form(next_step)
+ current_step = next_step
+
+ return self.render(form, request, current_step)
+
+ def render(self, form, request, step, context=None):
+ "Renders the given Form object, returning an HttpResponse."
+ old_data = request.POST
+ prev_fields = []
+ if old_data:
+ hidden = forms.HiddenInput()
+ # Collect all data from previous steps and render it as HTML hidden fields.
+ for i in range(step):
+ old_form = self.get_form(i, old_data)
+ hash_name = 'hash_%s' % i
+ prev_fields.extend([bf.as_hidden() for bf in old_form])
+ prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
+ return self.render_template(request, form, ''.join(prev_fields), step, context)
+
+ # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
+
+ def prefix_for_step(self, step):
+ "Given the step, returns a Form prefix to use."
+ return str(step)
+
+ def render_hash_failure(self, request, step):
+ """
+ Hook for rendering a template if a hash check failed.
+
+ step is the step that failed. Any previous step is guaranteed to be
+ valid.
+
+ This default implementation simply renders the form for the given step,
+ but subclasses may want to display an error message, etc.
+ """
+ return self.render(self.get_form(step), request, step, context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
+
+ def render_revalidation_failure(self, request, step, form):
+ """
+ Hook for rendering a template if final revalidation failed.
+
+ It is highly unlikely that this point would ever be reached, but See
+ the comment in __call__() for an explanation.
+ """
+ return self.render(form, request, step)
+
+ def security_hash(self, request, form):
+ """
+ Calculates the security hash for the given HttpRequest and Form instances.
+
+ This creates a list of the form field names/values in a deterministic
+ order, pickles the result with the SECRET_KEY setting and takes an md5
+ hash of that.
+
+ Subclasses may want to take into account request-specific information,
+ such as the IP address.
+ """
+ data = [(bf.name, bf.data or '') for bf in form] + [settings.SECRET_KEY]
+ # Use HIGHEST_PROTOCOL because it's the most efficient. It requires
+ # Python 2.3, but Django requires 2.3 anyway, so that's OK.
+ pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
+ return md5.new(pickled).hexdigest()
+
+ def determine_step(self, request, *args, **kwargs):
+ """
+ Given the request object and whatever *args and **kwargs were passed to
+ __call__(), returns the current step (which is zero-based).
+
+ Note that the result should not be trusted. It may even be a completely
+ invalid number. It's not the job of this method to validate it.
+ """
+ if not request.POST:
+ return 0
+ try:
+ step = int(request.POST.get(self.step_field_name, 0))
+ except ValueError:
+ return 0
+ return step
+
+ def parse_params(self, request, *args, **kwargs):
+ """
+ Hook for setting some state, given the request object and whatever
+ *args and **kwargs were passed to __call__(), sets some state.
+
+ This is called at the beginning of __call__().
+ """
+ pass
+
+ def get_template(self, step):
+ """
+ Hook for specifying the name of the template to use for a given step.
+
+ Note that this can return a tuple of template names if you'd like to
+ use the template system's select_template() hook.
+ """
+ return 'forms/wizard.html'
+
+ def render_template(self, request, form, previous_fields, step, context=None):
+ """
+ Renders the template for the given step, returning an HttpResponse object.
+
+ Override this method if you want to add a custom context, return a
+ different MIME type, etc. If you only need to override the template
+ name, use get_template() instead.
+
+ The template will be rendered with the following context:
+ step_field -- The name of the hidden field containing the step.
+ step0 -- The current step (zero-based).
+ step -- The current step (one-based).
+ step_count -- The total number of steps.
+ form -- The Form instance for the current step (either empty
+ or with errors).
+ previous_fields -- A string representing every previous data field,
+ plus hashes for completed forms, all in the form of
+ hidden fields. Note that you'll need to run this
+ through the "safe" template filter, to prevent
+ auto-escaping, because it's raw HTML.
+ """
+ context = context or {}
+ context.update(self.extra_context)
+ return render_to_response(self.get_template(self.step), dict(context,
+ step_field=self.step_field_name,
+ step0=step,
+ step=step + 1,
+ step_count=self.num_steps(),
+ form=form,
+ previous_fields=previous_fields
+ ), context_instance=RequestContext(request))
+
+ def process_step(self, request, form, step):
+ """
+ Hook for modifying the FormWizard's internal state, given a fully
+ validated Form object. The Form is guaranteed to have clean, valid
+ data.
+
+ This method should *not* modify any of that data. Rather, it might want
+ to set self.extra_context or dynamically alter self.form_list, based on
+ previously submitted forms.
+
+ Note that this method is called every time a page is rendered for *all*
+ submitted steps.
+ """
+ pass
+
+ # METHODS SUBCLASSES MUST OVERRIDE ########################################
+
+ def done(self, request, form_list):
+ """
+ Hook for doing something with the validated data. This is responsible
+ for the final processing.
+
+ form_list is a list of Form instances, each containing clean, valid
+ data.
+ """
+ raise NotImplementedError("Your %s class has not defined a done() method, which is required." % self.__class__.__name__)
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index cd3e3d9c75..d65c81c101 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -9,7 +9,9 @@ class SessionStore(SessionBase):
Implements a file based session store.
"""
def __init__(self, session_key=None):
- self.storage_path = getattr(settings, "SESSION_FILE_PATH", tempfile.gettempdir())
+ self.storage_path = getattr(settings, "SESSION_FILE_PATH", None)
+ if not self.storage_path:
+ self.storage_path = tempfile.gettempdir()
# Make sure the storage path is valid.
if not os.path.isdir(self.storage_path):
diff --git a/django/contrib/syndication/feeds.py b/django/contrib/syndication/feeds.py
index 45b97d970a..85af79cc27 100644
--- a/django/contrib/syndication/feeds.py
+++ b/django/contrib/syndication/feeds.py
@@ -3,7 +3,8 @@ from django.template import Context, loader, Template, TemplateDoesNotExist
from django.contrib.sites.models import Site, RequestSite
from django.utils import feedgenerator
from django.utils.encoding import smart_unicode, iri_to_uri
-from django.conf import settings
+from django.conf import settings
+from django.template import RequestContext
def add_domain(domain, url):
if not (url.startswith('http://') or url.startswith('https://')):
@@ -55,18 +56,23 @@ class Feed(object):
return attr()
return attr
+ def get_object(self, bits):
+ return None
+
def get_feed(self, url=None):
"""
Returns a feedgenerator.DefaultFeed object, fully populated, for
this feed. Raises FeedDoesNotExist for invalid parameters.
"""
if url:
- try:
- obj = self.get_object(url.split('/'))
- except (AttributeError, ObjectDoesNotExist):
- raise FeedDoesNotExist
+ bits = url.split('/')
else:
- obj = None
+ bits = []
+
+ try:
+ obj = self.get_object(bits)
+ except ObjectDoesNotExist:
+ raise FeedDoesNotExist
if Site._meta.installed:
current_site = Site.objects.get_current()
@@ -119,9 +125,9 @@ class Feed(object):
else:
author_email = author_link = None
feed.add_item(
- title = title_tmp.render(Context({'obj': item, 'site': current_site})),
+ title = title_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})),
link = link,
- description = description_tmp.render(Context({'obj': item, 'site': current_site})),
+ description = description_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})),
unique_id = self.__get_dynamic_attr('item_guid', item, link),
enclosure = enc,
pubdate = self.__get_dynamic_attr('item_pubdate', item),
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index d78e2eda0b..819b19a366 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -243,7 +243,7 @@ def setup_environ(settings_mod):
# way. For example, if this file (manage.py) lives in a directory
# "myproject", this code would add "/path/to/myproject" to sys.path.
project_directory, settings_filename = os.path.split(settings_mod.__file__)
- if not project_directory:
+ if project_directory == os.curdir or not project_directory:
project_directory = os.getcwd()
project_name = os.path.basename(project_directory)
settings_name = os.path.splitext(settings_filename)[0]
diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py
index ab4f409f15..867d4fd3da 100644
--- a/django/core/management/commands/startproject.py
+++ b/django/core/management/commands/startproject.py
@@ -20,8 +20,13 @@ class Command(LabelCommand):
# the parent directory.
directory = os.getcwd()
- if project_name in INVALID_PROJECT_NAMES:
- raise CommandError("%r conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name." % project_name)
+ try:
+ proj_name = __import__(project_name)
+ if proj_name:
+ raise CommandError("%r conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name." % project_name)
+ except ImportError:
+ if project_name in INVALID_PROJECT_NAMES:
+ raise CommandError("%r contains an invalid project name. Please try another name." % project_name)
copy_helper(self.style, 'project', project_name, directory)
diff --git a/django/core/paginator.py b/django/core/paginator.py
index 71a5479fd5..dabd20dfc0 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -1,46 +1,149 @@
class InvalidPage(Exception):
pass
-class ObjectPaginator(object):
+class Paginator(object):
+ def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
+ self.object_list = object_list
+ self.per_page = per_page
+ self.orphans = orphans
+ self.allow_empty_first_page = allow_empty_first_page
+ self._num_pages = self._count = None
+
+ def validate_number(self, number):
+ "Validates the given 1-based page number."
+ try:
+ number = int(number)
+ except ValueError:
+ raise InvalidPage('That page number is not an integer')
+ if number < 1:
+ raise InvalidPage('That page number is less than 1')
+ if number > self.num_pages:
+ if number == 1 and self.allow_empty_first_page:
+ pass
+ else:
+ raise InvalidPage('That page contains no results')
+ return number
+
+ def page(self, number):
+ "Returns a Page object for the given 1-based page number."
+ number = self.validate_number(number)
+ bottom = (number - 1) * self.per_page
+ top = bottom + self.per_page
+ if top + self.orphans >= self.count:
+ top = self.count
+ return Page(self.object_list[bottom:top], number, self)
+
+ def _get_count(self):
+ "Returns the total number of objects, across all pages."
+ if self._count is None:
+ self._count = len(self.object_list)
+ return self._count
+ count = property(_get_count)
+
+ def _get_num_pages(self):
+ "Returns the total number of pages."
+ if self._num_pages is None:
+ hits = self.count - 1 - self.orphans
+ if hits < 1:
+ hits = 0
+ if hits == 0 and not self.allow_empty_first_page:
+ self._num_pages = 0
+ else:
+ self._num_pages = hits // self.per_page + 1
+ return self._num_pages
+ num_pages = property(_get_num_pages)
+
+ def _get_page_range(self):
+ """
+ Returns a 1-based range of pages for iterating through within
+ a template for loop.
+ """
+ return range(1, self.num_pages + 1)
+ page_range = property(_get_page_range)
+
+class QuerySetPaginator(Paginator):
"""
- This class makes pagination easy. Feed it a QuerySet or list, plus the number
- of objects you want on each page. Then read the hits and pages properties to
- see how many pages it involves. Call get_page with a page number (starting
- at 0) to get back a list of objects for that page.
-
- Finally, check if a page number has a next/prev page using
- has_next_page(page_number) and has_previous_page(page_number).
-
- Use orphans to avoid small final pages. For example:
- 13 records, num_per_page=10, orphans=2 --> pages==2, len(self.get_page(0))==10
- 12 records, num_per_page=10, orphans=2 --> pages==1, len(self.get_page(0))==12
+ Like Paginator, but works on QuerySets.
+ """
+ def _get_count(self):
+ if self._count is None:
+ self._count = self.object_list.count()
+ return self._count
+ count = property(_get_count)
+
+class Page(object):
+ def __init__(self, object_list, number, paginator):
+ self.object_list = object_list
+ self.number = number
+ self.paginator = paginator
+
+ def __repr__(self):
+ return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
+
+ def has_next(self):
+ return self.number < self.paginator.num_pages
+
+ def has_previous(self):
+ return self.number > 1
+
+ def has_other_pages(self):
+ return self.has_previous() or self.has_next()
+
+ def next_page_number(self):
+ return self.number + 1
+
+ def previous_page_number(self):
+ return self.number - 1
+
+ def start_index(self):
+ """
+ Returns the 1-based index of the first object on this page,
+ relative to total objects in the paginator.
+ """
+ return (self.paginator.per_page * (self.number - 1)) + 1
+
+ def end_index(self):
+ """
+ Returns the 1-based index of the last object on this page,
+ relative to total objects found (hits).
+ """
+ if self.number == self.paginator.num_pages:
+ return self.paginator.count
+ return self.number * self.paginator.per_page
+
+class ObjectPaginator(Paginator):
+ """
+ Legacy ObjectPaginator class, for backwards compatibility.
+
+ Note that each method on this class that takes page_number expects a
+ zero-based page number, whereas the new API (Paginator/Page) uses one-based
+ page numbers.
"""
def __init__(self, query_set, num_per_page, orphans=0):
+ Paginator.__init__(self, query_set, num_per_page, orphans)
+ import warnings
+ warnings.warn("The ObjectPaginator is deprecated. Use django.core.paginator.Paginator instead.", DeprecationWarning)
+
+ # Keep these attributes around for backwards compatibility.
self.query_set = query_set
self.num_per_page = num_per_page
- self.orphans = orphans
self._hits = self._pages = None
- self._page_range = None
def validate_page_number(self, page_number):
try:
- page_number = int(page_number)
+ page_number = int(page_number) + 1
except ValueError:
raise InvalidPage
- if page_number < 0 or page_number > self.pages - 1:
- raise InvalidPage
- return page_number
+ return self.validate_number(page_number)
def get_page(self, page_number):
- page_number = self.validate_page_number(page_number)
- bottom = page_number * self.num_per_page
- top = bottom + self.num_per_page
- if top + self.orphans >= self.hits:
- top = self.hits
- return self.query_set[bottom:top]
+ try:
+ page_number = int(page_number) + 1
+ except ValueError:
+ raise InvalidPage
+ return self.page(page_number).object_list
def has_next_page(self, page_number):
- "Does page $page_number have a 'next' page?"
return page_number < self.pages - 1
def has_previous_page(self, page_number):
@@ -52,7 +155,7 @@ class ObjectPaginator(object):
relative to total objects found (hits).
"""
page_number = self.validate_page_number(page_number)
- return (self.num_per_page * page_number) + 1
+ return (self.num_per_page * (page_number - 1)) + 1
def last_on_page(self, page_number):
"""
@@ -60,40 +163,23 @@ class ObjectPaginator(object):
relative to total objects found (hits).
"""
page_number = self.validate_page_number(page_number)
- page_number += 1 # 1-base
- if page_number == self.pages:
- return self.hits
+ if page_number == self.num_pages:
+ return self.count
return page_number * self.num_per_page
- def _get_hits(self):
- if self._hits is None:
- # Try .count() or fall back to len().
+ def _get_count(self):
+ # The old API allowed for self.object_list to be either a QuerySet or a
+ # list. Here, we handle both.
+ if self._count is None:
try:
- self._hits = int(self.query_set.count())
- except (AttributeError, TypeError, ValueError):
- # AttributeError if query_set has no object count.
- # TypeError if query_set.count() required arguments.
- # ValueError if int() fails.
- self._hits = len(self.query_set)
- return self._hits
-
- def _get_pages(self):
- if self._pages is None:
- hits = (self.hits - 1 - self.orphans)
- if hits < 1:
- hits = 0
- self._pages = hits // self.num_per_page + 1
- return self._pages
-
- def _get_page_range(self):
- """
- Returns a 1-based range of pages for iterating through within
- a template for loop.
- """
- if self._page_range is None:
- self._page_range = range(1, self.pages + 1)
- return self._page_range
+ self._count = self.object_list.count()
+ except AttributeError:
+ self._count = len(self.object_list)
+ return self._count
+ count = property(_get_count)
- hits = property(_get_hits)
- pages = property(_get_pages)
- page_range = property(_get_page_range)
+ # The old API called it "hits" instead of "count".
+ hits = count
+
+ # The old API called it "pages" instead of "num_pages".
+ pages = Paginator.num_pages
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 50c87ff276..a79497ecec 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -22,10 +22,10 @@ class Serializer(object):
Abstract serializer base class.
"""
- # Indicates if the implemented serializer is only available for
+ # Indicates if the implemented serializer is only available for
# internal Django use.
internal_use_only = False
-
+
def serialize(self, queryset, **options):
"""
Serialize a queryset.
@@ -60,8 +60,6 @@ class Serializer(object):
"""
if isinstance(field, models.DateTimeField):
value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
- elif isinstance(field, models.FileField):
- value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
else:
value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
return smart_unicode(value)
diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py
index de04a5af62..d7145e15ec 100644
--- a/django/core/servers/fastcgi.py
+++ b/django/core/servers/fastcgi.py
@@ -37,7 +37,9 @@ Optional Fcgi settings: (setting=value)
maxchildren=NUMBER hard limit number of processes / threads
daemonize=BOOL whether to detach from terminal.
pidfile=FILE write the spawned process-id to this file.
- workdir=DIRECTORY change to this directory when daemonizing
+ workdir=DIRECTORY change to this directory when daemonizing.
+ outlog=FILE write stdout to this file.
+ errlog=FILE write stderr to this file.
Examples:
Run a "standard" fastcgi process on a file-descriptor
@@ -69,6 +71,8 @@ FASTCGI_OPTIONS = {
'minspare': 2,
'maxchildren': 50,
'maxrequests': 0,
+ 'outlog': None,
+ 'errlog': None,
}
def fastcgi_help(message=None):
@@ -150,9 +154,15 @@ def runfastcgi(argset=[], **kwargs):
else:
return fastcgi_help("ERROR: Invalid option for daemonize parameter.")
+ daemon_kwargs = {}
+ if options['outlog']:
+ daemon_kwargs['out_log'] = options['outlog']
+ if options['errlog']:
+ daemon_kwargs['err_log'] = options['errlog']
+
if daemonize:
from django.utils.daemonize import become_daemon
- become_daemon(our_home_dir=options["workdir"])
+ become_daemon(our_home_dir=options["workdir"], **daemon_kwargs)
if options["pidfile"]:
fp = open(options["pidfile"], "w")
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index edf9259510..6e426318f5 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -856,6 +856,16 @@ class FilePathField(Field):
self.path, self.match, self.recursive = path, match, recursive
kwargs['max_length'] = kwargs.get('max_length', 100)
Field.__init__(self, verbose_name, name, **kwargs)
+
+ def formfield(self, **kwargs):
+ defaults = {
+ 'path': self.path,
+ 'match': self.match,
+ 'recursive': self.recursive,
+ 'form_class': forms.FilePathField,
+ }
+ defaults.update(kwargs)
+ return super(FilePathField, self).formfield(**defaults)
def get_manipulator_field_objs(self):
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index bb1783b87c..f2254d7373 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -622,6 +622,13 @@ class ForeignKey(RelatedField, Field):
params['choices'] = self.get_choices_default()
return field_objs, params
+ def get_default(self):
+ "Here we check if the default value is an object and return the to_field if so."
+ field_default = super(ForeignKey, self).get_default()
+ if isinstance(field_default, self.rel.to):
+ return getattr(field_default, self.rel.get_related_field().attname)
+ return field_default
+
def get_manipulator_field_objs(self):
rel_field = self.rel.get_related_field()
if self.rel.raw_id_admin and not isinstance(rel_field, AutoField):
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 388a54dc85..f9b8baf3b1 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1,6 +1,7 @@
import warnings
-from django.db import connection, transaction
+from django.conf import settings
+from django.db import connection, transaction, IntegrityError
from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models.query_utils import Q, not_q
from django.db.models import signals, sql
@@ -204,11 +205,14 @@ class _QuerySet(object):
try:
return self.get(**kwargs), False
except self.model.DoesNotExist:
- params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
- params.update(defaults)
- obj = self.model(**params)
- obj.save()
- return obj, True
+ try:
+ params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
+ params.update(defaults)
+ obj = self.model(**params)
+ obj.save()
+ return obj, True
+ except IntegrityError, e:
+ return self.get(**kwargs), False
def latest(self, field_name=None):
"""
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 5439aa6c63..7faa3c875e 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -82,6 +82,9 @@ class HttpRequest(object):
def is_secure(self):
return os.environ.get("HTTPS") == "on"
+ def is_ajax(self):
+ return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
+
def _set_encoding(self, val):
"""
Sets the encoding used for GET/POST accesses. If the GET or POST
diff --git a/django/newforms/extras/widgets.py b/django/newforms/extras/widgets.py
index 0097ba3f54..e3ef1d7f69 100644
--- a/django/newforms/extras/widgets.py
+++ b/django/newforms/extras/widgets.py
@@ -3,6 +3,7 @@ Extra HTML Widget classes
"""
import datetime
+import re
from django.newforms.widgets import Widget, Select
from django.utils.dates import MONTHS
@@ -10,6 +11,8 @@ from django.utils.safestring import mark_safe
__all__ = ('SelectDateWidget',)
+RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
+
class SelectDateWidget(Widget):
"""
A Widget that splits date input into three <select> boxes.
@@ -32,28 +35,43 @@ class SelectDateWidget(Widget):
def render(self, name, value, attrs=None):
try:
- value = datetime.date(*map(int, value.split('-')))
year_val, month_val, day_val = value.year, value.month, value.day
- except (AttributeError, TypeError, ValueError):
+ except AttributeError:
year_val = month_val = day_val = None
+ if isinstance(value, basestring):
+ match = RE_DATE.match(value)
+ if match:
+ year_val, month_val, day_val = [int(v) for v in match.groups()]
output = []
+ if 'id' in self.attrs:
+ id_ = self.attrs['id']
+ else:
+ id_ = 'id_%s' % name
+
month_choices = MONTHS.items()
month_choices.sort()
- select_html = Select(choices=month_choices).render(self.month_field % name, month_val)
+ local_attrs = self.build_attrs(id=self.month_field % id_)
+ select_html = Select(choices=month_choices).render(self.month_field % name, month_val, local_attrs)
output.append(select_html)
day_choices = [(i, i) for i in range(1, 32)]
- select_html = Select(choices=day_choices).render(self.day_field % name, day_val)
+ local_attrs['id'] = self.day_field % id_
+ select_html = Select(choices=day_choices).render(self.day_field % name, day_val, local_attrs)
output.append(select_html)
year_choices = [(i, i) for i in self.years]
- select_html = Select(choices=year_choices).render(self.year_field % name, year_val)
+ local_attrs['id'] = self.year_field % id_
+ select_html = Select(choices=year_choices).render(self.year_field % name, year_val, local_attrs)
output.append(select_html)
return mark_safe(u'\n'.join(output))
+ def id_for_label(self, id_):
+ return '%s_month' % id_
+ id_for_label = classmethod(id_for_label)
+
def value_from_datadict(self, data, files, name):
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)
if y and m and d:
diff --git a/django/newforms/fields.py b/django/newforms/fields.py
index bc3e543037..08e8b842ec 100644
--- a/django/newforms/fields.py
+++ b/django/newforms/fields.py
@@ -4,6 +4,7 @@ Field classes.
import copy
import datetime
+import os
import re
import time
# Python 2.3 fallbacks
@@ -31,7 +32,7 @@ __all__ = (
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
- 'SplitDateTimeField', 'IPAddressField',
+ 'SplitDateTimeField', 'IPAddressField', 'FilePathField',
)
# These values, if given to to_python(), will trigger the self.required check.
@@ -718,6 +719,33 @@ class MultiValueField(Field):
"""
raise NotImplementedError('Subclasses must implement this method.')
+class FilePathField(ChoiceField):
+ def __init__(self, path, match=None, recursive=False, required=True,
+ widget=Select, label=None, initial=None, help_text=None,
+ *args, **kwargs):
+ self.path, self.match, self.recursive = path, match, recursive
+ super(FilePathField, self).__init__(choices=(), required=required,
+ widget=widget, label=label, initial=initial, help_text=help_text,
+ *args, **kwargs)
+ self.choices = []
+ if self.match is not None:
+ self.match_re = re.compile(self.match)
+ if recursive:
+ for root, dirs, files in os.walk(self.path):
+ for f in files:
+ if self.match is None or self.match_re.search(f):
+ f = os.path.join(root, f)
+ self.choices.append((f, f.replace(path, "", 1)))
+ else:
+ try:
+ for f in os.listdir(self.path):
+ full_file = os.path.join(self.path, f)
+ if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)):
+ self.choices.append((full_file, f))
+ except OSError:
+ pass
+ self.widget.choices = self.choices
+
class SplitDateTimeField(MultiValueField):
default_error_messages = {
'invalid_date': _(u'Enter a valid date.'),
diff --git a/django/newforms/models.py b/django/newforms/models.py
index f3809dc370..0590839b25 100644
--- a/django/newforms/models.py
+++ b/django/newforms/models.py
@@ -277,19 +277,18 @@ class ModelForm(BaseModelForm):
# Fields #####################################################################
-class QuerySetIterator(object):
- def __init__(self, queryset, empty_label, cache_choices):
- self.queryset = queryset
- self.empty_label = empty_label
- self.cache_choices = cache_choices
+class ModelChoiceIterator(object):
+ def __init__(self, field):
+ self.field = field
+ self.queryset = field.queryset
def __iter__(self):
- if self.empty_label is not None:
- yield (u"", self.empty_label)
+ if self.field.empty_label is not None:
+ yield (u"", self.field.empty_label)
for obj in self.queryset:
- yield (obj.pk, smart_unicode(obj))
+ yield (obj.pk, self.field.label_from_instance(obj))
# Clear the QuerySet cache if required.
- if not self.cache_choices:
+ if not self.field.cache_choices:
self.queryset._result_cache = None
class ModelChoiceField(ChoiceField):
@@ -306,6 +305,7 @@ class ModelChoiceField(ChoiceField):
help_text=None, *args, **kwargs):
self.empty_label = empty_label
self.cache_choices = cache_choices
+
# Call Field instead of ChoiceField __init__() because we don't need
# ChoiceField.__init__().
Field.__init__(self, required, widget, label, initial, help_text,
@@ -321,19 +321,30 @@ class ModelChoiceField(ChoiceField):
queryset = property(_get_queryset, _set_queryset)
+ # this method will be used to create object labels by the QuerySetIterator.
+ # Override it to customize the label.
+ def label_from_instance(self, obj):
+ """
+ This method is used to convert objects into strings; it's used to
+ generate the labels for the choices presented by this object. Subclasses
+ can override this method to customize the display of the choices.
+ """
+ return smart_unicode(obj)
+
def _get_choices(self):
# If self._choices is set, then somebody must have manually set
# the property self.choices. In this case, just return self._choices.
if hasattr(self, '_choices'):
return self._choices
+
# Otherwise, execute the QuerySet in self.queryset to determine the
- # choices dynamically. Return a fresh QuerySetIterator that has not
- # been consumed. Note that we're instantiating a new QuerySetIterator
- # *each* time _get_choices() is called (and, thus, each time
- # self.choices is accessed) so that we can ensure the QuerySet has not
- # been consumed.
- return QuerySetIterator(self.queryset, self.empty_label,
- self.cache_choices)
+ # choices dynamically. Return a fresh QuerySetIterator that has not been
+ # consumed. Note that we're instantiating a new QuerySetIterator *each*
+ # time _get_choices() is called (and, thus, each time self.choices is
+ # accessed) so that we can ensure the QuerySet has not been consumed. This
+ # construct might look complicated but it allows for lazy evaluation of
+ # the queryset.
+ return ModelChoiceIterator(self)
def _set_choices(self, value):
# This method is copied from ChoiceField._set_choices(). It's necessary
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index 8e5bcf5bd8..cef314387a 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -124,7 +124,10 @@ def floatformat(text, arg=-1):
d = int(arg)
except ValueError:
return force_unicode(f)
- m = f - int(f)
+ try:
+ m = f - int(f)
+ except OverflowError:
+ return force_unicode(f)
if not m and d < 0:
return mark_safe(u'%d' % int(f))
else:
diff --git a/django/test/client.py b/django/test/client.py
index 67d3aa9030..bac28f797b 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -1,3 +1,4 @@
+import urllib
import sys
from cStringIO import StringIO
from django.conf import settings
@@ -208,7 +209,7 @@ class Client:
r = {
'CONTENT_LENGTH': None,
'CONTENT_TYPE': 'text/html; charset=utf-8',
- 'PATH_INFO': path,
+ 'PATH_INFO': urllib.unquote(path),
'QUERY_STRING': urlencode(data, doseq=True),
'REQUEST_METHOD': 'GET',
}
@@ -227,7 +228,7 @@ class Client:
r = {
'CONTENT_LENGTH': len(post_data),
'CONTENT_TYPE': content_type,
- 'PATH_INFO': path,
+ 'PATH_INFO': urllib.unquote(path),
'REQUEST_METHOD': 'POST',
'wsgi.input': StringIO(post_data),
}
diff --git a/django/utils/daemonize.py b/django/utils/daemonize.py
index 9671b8d91f..f0c2f684bd 100644
--- a/django/utils/daemonize.py
+++ b/django/utils/daemonize.py
@@ -18,10 +18,10 @@ if os.name == 'posix':
# Second fork
try:
if os.fork() > 0:
- sys.exit(0)
+ os._exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
- sys.exit(1)
+ os._exit(1)
si = open('/dev/null', 'r')
so = open(out_log, 'a+', 0)
@@ -29,6 +29,8 @@ if os.name == 'posix':
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
+ # Set custom file descriptors so that they get proper buffering.
+ sys.stdout, sys.stderr = so, se
else:
def become_daemon(our_home_dir='.', out_log=None, err_log=None):
"""
diff --git a/django/views/debug.py b/django/views/debug.py
index b7ac12db38..a118ac3126 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -1,11 +1,12 @@
import os
import re
import sys
+import datetime
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.http import HttpResponse, HttpResponseServerError, HttpResponseNotFound
from django.utils.encoding import smart_unicode
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
@@ -70,6 +71,11 @@ def technical_500_response(request, exc_type, exc_value, tb):
Create a technical server error response. The last three arguments are
the values returned from sys.exc_info() and friends.
"""
+ html = get_traceback_html(request, exc_type, exc_value, tb)
+ return HttpResponseServerError(html, mimetype='text/html')
+
+def get_traceback_html(request, exc_type, exc_value, tb):
+ "Return HTML code for traceback."
template_info = None
template_does_not_exist = False
loader_debug_info = None
@@ -153,13 +159,14 @@ def technical_500_response(request, exc_type, exc_value, tb):
'settings': get_safe_settings(),
'sys_executable': sys.executable,
'sys_version_info': '%d.%d.%d' % sys.version_info[0:3],
+ 'server_time': datetime.datetime.now(),
'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,
})
- return HttpResponseServerError(t.render(c), mimetype='text/html')
+ return t.render(c)
def technical_404_response(request, exception):
"Create a technical 404 error response. The exception should be the Http404."
@@ -190,7 +197,7 @@ def empty_urlconf(request):
c = Context({
'project_name': settings.SETTINGS_MODULE.split('.')[0]
})
- return HttpResponseNotFound(t.render(c), mimetype='text/html')
+ return HttpResponse(t.render(c), mimetype='text/html')
def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None):
"""
@@ -384,6 +391,10 @@ TECHNICAL_500_TEMPLATE = """
<th>Python Path:</th>
<td>{{ sys_path }}</td>
</tr>
+ <tr>
+ <th>Server time:</th>
+ <td>{{server_time|date:"r"}}</td>
+ </tr>
</table>
</div>
{% if unicode_hint %}
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
index 617a6443a2..cb9b014eb5 100644
--- a/django/views/generic/list_detail.py
+++ b/django/views/generic/list_detail.py
@@ -1,7 +1,7 @@
from django.template import loader, RequestContext
from django.http import Http404, HttpResponse
from django.core.xheaders import populate_xheaders
-from django.core.paginator import ObjectPaginator, InvalidPage
+from django.core.paginator import QuerySetPaginator, InvalidPage
from django.core.exceptions import ObjectDoesNotExist
def object_list(request, queryset, paginate_by=None, page=None,
@@ -45,43 +45,47 @@ def object_list(request, queryset, paginate_by=None, page=None,
if extra_context is None: extra_context = {}
queryset = queryset._clone()
if paginate_by:
- paginator = ObjectPaginator(queryset, paginate_by)
+ paginator = QuerySetPaginator(queryset, paginate_by, allow_empty_first_page=allow_empty)
if not page:
page = request.GET.get('page', 1)
try:
page_number = int(page)
except ValueError:
if page == 'last':
- page_number = paginator.pages
+ page_number = paginator.num_pages
else:
- # Page is not 'last', nor can it be converted to an int
+ # Page is not 'last', nor can it be converted to an int.
raise Http404
try:
- object_list = paginator.get_page(page_number - 1)
+ page_obj = paginator.page(page_number)
except InvalidPage:
- if page_number == 1 and allow_empty:
- object_list = []
- else:
- raise Http404
+ raise Http404
c = RequestContext(request, {
- '%s_list' % template_object_name: object_list,
- 'is_paginated': paginator.pages > 1,
- 'results_per_page': paginate_by,
- 'has_next': paginator.has_next_page(page_number - 1),
- 'has_previous': paginator.has_previous_page(page_number - 1),
- 'page': page_number,
- 'next': page_number + 1,
- 'previous': page_number - 1,
- 'last_on_page': paginator.last_on_page(page_number - 1),
- 'first_on_page': paginator.first_on_page(page_number - 1),
- 'pages': paginator.pages,
- 'hits' : paginator.hits,
- 'page_range' : paginator.page_range
+ '%s_list' % template_object_name: page_obj.object_list,
+ 'paginator': paginator,
+ 'page_obj': page_obj,
+
+ # Legacy template context stuff. New templates should use page_obj
+ # to access this instead.
+ 'is_paginated': page_obj.has_other_pages(),
+ 'results_per_page': paginator.per_page,
+ 'has_next': page_obj.has_next(),
+ 'has_previous': page_obj.has_previous(),
+ 'page': page_obj.number,
+ 'next': page_obj.next_page_number(),
+ 'previous': page_obj.previous_page_number(),
+ 'last_on_page': page_obj.start_index(),
+ 'first_on_page': page_obj.end_index(),
+ 'pages': paginator.num_pages,
+ 'hits': paginator.count,
+ 'page_range': paginator.page_range,
}, context_processors)
else:
c = RequestContext(request, {
'%s_list' % template_object_name: queryset,
- 'is_paginated': False
+ 'paginator': None,
+ 'page_obj': None,
+ 'is_paginated': False,
}, context_processors)
if not allow_empty and len(queryset) == 0:
raise Http404
diff --git a/docs/custom_model_fields.txt b/docs/custom_model_fields.txt
index 923b331a95..2b344921ef 100644
--- a/docs/custom_model_fields.txt
+++ b/docs/custom_model_fields.txt
@@ -401,8 +401,8 @@ For example::
# ...
def get_db_prep_save(self, value):
- return ''.join([''.join(l) for l in (self.north,
- self.east, self.south, self.west)])
+ return ''.join([''.join(l) for l in (value.north,
+ value.east, value.south, value.west)])
``pre_save(self, model_instance, add)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/generic_views.txt b/docs/generic_views.txt
index 17187894c0..b7beb0b4be 100644
--- a/docs/generic_views.txt
+++ b/docs/generic_views.txt
@@ -751,6 +751,19 @@ In addition to ``extra_context``, the template's context will be:
If the results are paginated, the context will contain these extra variables:
+ * **New in Django development version:** ``paginator``: An instance of
+ ``django.core.paginator.Paginator``.
+
+ * **New in Django development version:** ``page_obj``: An instance of
+ ``django.core.paginator.Page``.
+
+In older versions of Django, before ``paginator`` and ``page_obj`` were added
+to this template's context, the template included several other variables
+related to pagination. Note that you should *NOT* use these variables anymore;
+use ``paginator`` and ``page_obj`` instead, because they let you do everything
+these old variables let you do (and more!). But for legacy installations,
+here's a list of those old template variables:
+
* ``results_per_page``: The number of objects per page. (Same as the
``paginate_by`` parameter.)
@@ -777,8 +790,8 @@ If the results are paginated, the context will contain these extra variables:
* ``hits``: The total number of objects across *all* pages, not just this
page.
- * **New in Django development version:** ``page_range``: A list of the
- page numbers that are available. This is 1-based.
+ * ``page_range``: A list of the page numbers that are available. This is
+ 1-based.
Notes on pagination
~~~~~~~~~~~~~~~~~~~
diff --git a/docs/install.txt b/docs/install.txt
index 542036e2af..341c4280e8 100644
--- a/docs/install.txt
+++ b/docs/install.txt
@@ -167,6 +167,20 @@ These commands will install Django in your Python installation's
Installing the development version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. admonition:: Tracking Django development
+
+ If you decide to use the latest development version of Django,
+ you'll want to pay close attention to `the development timeline`_,
+ and you'll want to keep an eye on `the list of
+ backwards-incompatible changes`_; this will help you stay on top
+ of any new features you might want to use, as well as any changes
+ you'll need to make to your code when updating your copy of Django
+ (for stable releases, any necessary changes are documented in the
+ release notes).
+
+.. _the development timeline: http://code.djangoproject.com/timeline
+.. _the list of backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
+
If you'd like to be able to update your Django code occasionally with the
latest bug fixes and improvements, follow these instructions:
diff --git a/docs/model-api.txt b/docs/model-api.txt
index e4d3805236..5502bd51eb 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -626,7 +626,8 @@ option is ignored.
``default``
~~~~~~~~~~~
-The default value for the field.
+The default value for the field. This can be a value or a callable object. If
+callable it will be called every time a new object is created.
``editable``
~~~~~~~~~~~~
@@ -1814,14 +1815,15 @@ For example::
This example allows you to request ``Person.men.all()``, ``Person.women.all()``,
and ``Person.people.all()``, yielding predictable results.
-If you use custom ``Manager`` objects, take note that the first ``Manager``
-Django encounters (in order by which they're defined in the model) has a
-special status. Django interprets the first ``Manager`` defined in a class as
-the "default" ``Manager``. Certain operations -- such as Django's admin site --
-use the default ``Manager`` to obtain lists of objects, so it's generally a
-good idea for the first ``Manager`` to be relatively unfiltered. In the last
-example, the ``people`` ``Manager`` is defined first -- so it's the default
-``Manager``.
+If you use custom ``Manager`` objects, take note that the first
+``Manager`` Django encounters (in the order in which they're defined
+in the model) has a special status. Django interprets this first
+``Manager`` defined in a class as the "default" ``Manager``, and
+several parts of Django (though not the admin application) will use
+that ``Manager`` exclusively for that model. As a result, it's often a
+good idea to be careful in your choice of default manager, in order to
+avoid a situation where overriding of ``get_query_set()`` results in
+an inability to retrieve objects you'd like to work with.
Model methods
=============
diff --git a/docs/modelforms.txt b/docs/modelforms.txt
index 47eaa9a769..05f9b1b3d4 100644
--- a/docs/modelforms.txt
+++ b/docs/modelforms.txt
@@ -231,6 +231,16 @@ For example::
# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()
+Other than the ``save()`` and ``save_m2m()`` methods, a ``ModelForm``
+works exactly the same way as any other ``newforms`` form. For
+example, the ``is_valid()`` method is used to check for validity, the
+``is_multipart()`` method is used to determine whether a form requires
+multipart file upload (and hence whether ``request.FILES`` must be
+passed to the form), etc.; see `the standard newforms documentation`_
+for more information.
+
+.. _the standard newforms documentation: ../newforms/
+
Using a subset of fields on the form
------------------------------------
diff --git a/docs/newforms.txt b/docs/newforms.txt
index 0b5559ab88..533ff75185 100644
--- a/docs/newforms.txt
+++ b/docs/newforms.txt
@@ -1333,13 +1333,14 @@ given length.
An ``UploadedFile`` object has two attributes:
- ====================== =====================================================
- Argument Description
- ====================== =====================================================
+ ====================== ====================================================
+ Attribute Description
+ ====================== ====================================================
``filename`` The name of the file, provided by the uploading
client.
+
``content`` The array of bytes comprising the file content.
- ====================== =====================================================
+ ====================== ====================================================
The string representation of an ``UploadedFile`` is the same as the filename
attribute.
@@ -1349,6 +1350,38 @@ When you use a ``FileField`` on a form, you must also remember to
.. _`bind the file data to the form`: `Binding uploaded files to a form`_
+``FilePathField``
+~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+ * Default widget: ``Select``
+ * Empty value: ``None``
+ * Normalizes to: A unicode object
+ * Validates that the selected choice exists in the list of choices.
+ * Error message keys: ``required``, ``invalid_choice``
+
+The field allows choosing from files inside a certain directory. It takes three
+extra arguments:
+
+ ============== ========== ===============================================
+ Argument Required? Description
+ ============== ========== ===============================================
+ ``path`` Yes The absolute path to the directory whose
+ contents you want listed. This directory must
+ exist.
+
+ ``recursive`` No If ``False`` (the default) only the direct
+ contents of ``path`` will be offered as choices.
+ If ``True``, the directory will be descended
+ into recursively and all descendants will be
+ listed as choices.
+
+ ``match`` No A regular expression pattern; only files with
+ names matching this expression will be allowed
+ as choices.
+ ============== ========== ===============================================
+
``ImageField``
~~~~~~~~~~~~~~
@@ -1499,6 +1532,41 @@ the bottom of this document, for examples of their use.
``SplitDateTimeField``
~~~~~~~~~~~~~~~~~~~~~~
+Fields which handle relationships
+---------------------------------
+
+For representing relationships between models, two fields are
+provided which can derive their choices from a ``QuerySet``, and which
+place one or more model objects into the ``cleaned_data`` dictionary
+of forms in which they're used. Both of these fields have an
+additional required argument:
+
+``queryset``
+ A ``QuerySet`` of model objects from which the choices for the
+ field will be derived, and which will be used to validate the
+ user's selection.
+
+``ModelChoiceField``
+~~~~~~~~~~~~~~~~~~~~
+
+Allows the selection of a single model object, suitable for representing a
+foreign key. The method receives an object as an argument and must return a
+string to represent it.
+
+The labels for the choice field call the ``__unicode__`` method of the model to
+generate string representations. To provide custom labels, subclass ``ModelChoiceField`` and override ``label_for_model``::
+
+ class MyModelChoiceField(ModelChoiceField):
+ def label_from_instance(self, obj):
+ return "My Object #%i" % obj.id
+
+``ModelMultipleChoiceField``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Allows the selection of one or more model objects, suitable for representing a
+many-to-many relation. As with ``ModelChoiceField``, you can use
+``label_from_instance`` to customize the object labels.
+
Creating custom fields
----------------------
@@ -1569,9 +1637,9 @@ The three types of cleaning methods are:
These methods are run in the order given above, one field at a time. That is,
for each field in the form (in the order they are declared in the form
-definition), the ``Field.clean()`` method (or it's override) is run, then
+definition), the ``Field.clean()`` method (or its override) is run, then
``clean_<fieldname>()``. Finally, once those two methods are run for every
-field, the ``Form.clean()`` method, or it's override, is executed.
+field, the ``Form.clean()`` method, or its override, is executed.
As mentioned above, any of these methods can raise a ``ValidationError``. For
any field, if the ``Field.clean()`` method raises a ``ValidationError``, any
@@ -1693,7 +1761,7 @@ For example, take the following simple form::
comment = forms.CharField()
This form will include three default TextInput widgets, with default rendering -
-no CSS class, no extra attributes. This means that the inputs boxes provided for
+no CSS class, no extra attributes. This means that the input boxes provided for
each widget will be rendered exactly the same::
>>> f = CommentForm(auto_id=False)
diff --git a/docs/pagination.txt b/docs/pagination.txt
new file mode 100644
index 0000000000..486c92264b
--- /dev/null
+++ b/docs/pagination.txt
@@ -0,0 +1,133 @@
+==========
+Pagination
+==========
+
+**New in Django development version**
+
+Django provides a few classes that help you manage paginated data -- that is,
+data that's split across several pages, with "Previous/Next" links. These
+classes live in the module ``django/core/paginator.py``.
+
+Example
+=======
+
+Give ``Paginator`` a list of objects, plus the number of items you'd like to
+have on each page, and it gives you methods for accessing the items for each
+page::
+
+ >>> from django.core.paginator import Paginator
+ >>> objects = ['john', 'paul', 'george', 'ringo']
+ >>> p = Paginator(objects, 2)
+
+ >>> p.count
+ 4
+ >>> p.num_pages
+ 2
+ >>> p.page_range
+ [1, 2]
+
+ >>> page1 = p.page(1)
+ >>> page1
+ <Page 1 of 2>
+ >>> page1.object_list
+ ['john', 'paul']
+
+ >>> page2 = p.page(2)
+ >>> page2.object_list
+ ['george', 'ringo']
+ >>> page2.has_next()
+ False
+ >>> page2.has_previous()
+ True
+ >>> page2.has_other_pages()
+ True
+ >>> page2.next_page_number()
+ 3
+ >>> page2.previous_page_number()
+ 1
+ >>> page2.start_index() # The 1-based index of the first item on this page
+ 3
+ >>> page2.end_index() # The 1-based index of the last item on this page
+ 4
+
+ >>> p.page(0)
+ Traceback (most recent call last):
+ ...
+ InvalidPage
+ >>> p.page(3)
+ Traceback (most recent call last):
+ ...
+ InvalidPage
+
+``Paginator`` objects
+=====================
+
+Methods
+-------
+
+``page(number)`` -- Returns a ``Page`` object with the given 1-based index.
+Raises ``InvalidPage`` if the given page number doesn't exist.
+
+Attributes
+----------
+
+``count`` -- The total number of objects, across all pages.
+
+``num_pages`` -- The total number of pages.
+
+``page_range`` -- A 1-based range of page numbers, e.g., ``[1, 2, 3, 4]``.
+
+``Page`` objects
+================
+
+Methods
+-------
+
+``has_next()`` -- Returns ``True`` if there's a next page.
+
+``has_previous()`` -- Returns ``True`` if there's a previous page.
+
+``has_other_pages()`` -- Returns ``True`` if there's a next *or* previous page.
+
+``next_page_number()`` -- Returns the next page number. Note that this is
+"dumb" and will return the next page number regardless of whether a subsequent
+page exists.
+
+``previous_page_number()`` -- Returns the previous page number. Note that this
+is "dumb" and will return the previous page number regardless of whether a
+previous page exists.
+
+``start_index()`` -- Returns the 1-based index of the first object on the page,
+relative to all of the objects in the paginator's list. For example, when
+paginating a list of 5 objects with 2 objects per page, the second page's
+``start_index()`` would return ``3``.
+
+``end_index()`` -- Returns the 1-based index of the last object on the page,
+relative to all of the objects in the paginator's list. For example, when
+paginating a list of 5 objects with 2 objects per page, the second page's
+``end_index()`` would return ``4``.
+
+Attributes
+----------
+
+``object_list`` -- The list of objects on this page.
+
+``number`` -- The 1-based page number for this page.
+
+``paginator`` -- The associated ``Paginator`` object.
+
+``QuerySetPaginator`` objects
+=============================
+
+Use ``QuerySetPaginator`` instead of ``Paginator`` if you're paginating across
+a ``QuerySet`` from Django's database API. This is slightly more efficient, and
+there are no API differences between the two classes.
+
+The legacy ``ObjectPaginator`` class
+====================================
+
+The ``Paginator`` and ``Page`` classes are new in the Django development
+version, as of revision 7306. In previous versions, Django provided an
+``ObjectPaginator`` class that offered similar functionality but wasn't as
+convenient. This class still exists, for backwards compatibility, but Django
+now issues a ``DeprecationWarning`` if you try to use it.
diff --git a/docs/request_response.txt b/docs/request_response.txt
index e50cfc5ea3..0e0f046a2d 100644
--- a/docs/request_response.txt
+++ b/docs/request_response.txt
@@ -141,6 +141,16 @@ All attributes except ``session`` should be considered read-only.
The raw HTTP POST data. This is only useful for advanced processing. Use
``POST`` instead.
+``urlconf``
+ Not defined by Django itself, but will be read if other code
+ (e.g., a custom middleware class) sets it; when present, this will
+ be used as the root URLConf for the current request, overriding
+ the ``ROOT_URLCONF`` setting. See `How Django processes a
+ request`_ for details.
+
+.. _How Django processes a request: ../url_dispatch/#how-django-processes-a-request
+
+
Methods
-------
@@ -189,6 +199,23 @@ Methods
Returns ``True`` if the request is secure; that is, if it was made with
HTTPS.
+``is_ajax()``
+ **New in Django development version**
+
+ Returns ``True`` if the request was made via an XMLHttpRequest by checking
+ the ``HTTP_X_REQUESTED_WITH`` header for the string *'XMLHttpRequest'*. The
+ following major Javascript libraries all send this header:
+
+ * jQuery
+ * Dojo
+ * MochiKit
+ * MooTools
+ * Prototype
+ * YUI
+
+ If you write your own XMLHttpRequest call (on the browser side), you will
+ have to set this header manually to use this method.
+
QueryDict objects
-----------------
diff --git a/docs/sessions.txt b/docs/sessions.txt
index 6355524d2e..d8bac5b8d4 100644
--- a/docs/sessions.txt
+++ b/docs/sessions.txt
@@ -48,10 +48,10 @@ Using file-based sessions
To use file-based sessions, set the ``SESSION_ENGINE`` setting to
``"django.contrib.sessions.backends.file"``.
-You might also want to set the ``SESSION_FILE_PATH`` setting (which
-defaults to ``/tmp``) to control where Django stores session files. Be
-sure to check that your Web server has permissions to read and write to
-this location.
+You might also want to set the ``SESSION_FILE_PATH`` setting (which defaults
+to output from ``tempfile.gettempdir()``, most likely ``/tmp``) to control
+where Django stores session files. Be sure to check that your Web server has
+permissions to read and write to this location.
Using cache-based sessions
--------------------------
diff --git a/docs/settings.txt b/docs/settings.txt
index 77e3c6692f..fb2e04f1ea 100644
--- a/docs/settings.txt
+++ b/docs/settings.txt
@@ -185,8 +185,11 @@ ADMIN_MEDIA_PREFIX
Default: ``'/media/'``
-The URL prefix for admin media -- CSS, JavaScript and images. Make sure to use
-a trailing slash.
+The URL prefix for admin media -- CSS, JavaScript and images used by
+the Django administrative interface. Make sure to use a trailing
+slash, and to have this be different from the ``MEDIA_URL`` setting
+(since the same URL cannot be mapped onto two different sets of
+files).
ADMINS
------
@@ -754,7 +757,9 @@ ROOT_URLCONF
Default: Not defined
A string representing the full Python import path to your root URLconf. For example:
-``"mydjangoapps.urls"``. See `How Django processes a request`_.
+``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
+setting the attribute ``urlconf`` on the incoming ``HttpRequest``
+object. See `How Django processes a request`_ for details.
.. _How Django processes a request: ../url_dispatch/#how-django-processes-a-request
diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt
index ebd6af26f8..f86acfe54d 100644
--- a/docs/syndication_feeds.txt
+++ b/docs/syndication_feeds.txt
@@ -245,6 +245,13 @@ request to the URL ``/rss/beats/0613/``:
subclass of ``ObjectDoesNotExist``. Raising ``ObjectDoesNotExist`` in
``get_object()`` tells Django to produce a 404 error for that request.
+ **New in Django development version:** The ``get_object()`` method also
+ has a chance to handle the ``/rss/beats/`` url. In this case, ``bits``
+ will be an empty list. In our example, ``len(bits) != 1`` and an
+ ``ObjectDoesNotExist`` exception will be raised, so ``/rss/beats/`` will
+ generate a 404 page. But you can handle this case however you like. For
+ example you could generate a combined feed for all beats.
+
* To generate the feed's ``<title>``, ``<link>`` and ``<description>``,
Django uses the ``title()``, ``link()`` and ``description()`` methods. In
the previous example, they were simple string class attributes, but this
diff --git a/docs/templates.txt b/docs/templates.txt
index 3360b04178..ea9f3fb6b2 100644
--- a/docs/templates.txt
+++ b/docs/templates.txt
@@ -429,8 +429,9 @@ all block tags. For example::
# base.html
{% autoescape off %}
- <h1>{% block title %}</h1>
+ <h1>{% block title %}{% endblock %}</h1>
{% block content %}
+ {% endblock %}
{% endautoescape %}
@@ -438,10 +439,11 @@ all block tags. For example::
{% extends "base.html" %}
{% block title %}This & that{% endblock %}
- {% block content %}<b>Hello!</b>{% endblock %}
+ {% block content %}{{ greeting }}{% endblock %}
Because auto-escaping is turned off in the base template, it will also be
-turned off in the child template, resulting in the following rendered HTML::
+turned off in the child template, resulting in the following rendered
+HTML when the ``greeting`` variable contains the string ``<b>Hello!</b>``::
<h1>This & that</h1>
<b>Hello!</b>
diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt
index bd16fa2924..473fba1ef8 100644
--- a/docs/tutorial04.txt
+++ b/docs/tutorial04.txt
@@ -37,6 +37,12 @@ A quick rundown:
form will alter data server-side. Whenever you create a form that alters
data server-side, use ``method="post"``. This tip isn't specific to
Django; it's just good Web development practice.
+
+ * ``forloop.counter`` indicates how many times the ``for`` tag has
+ gone through its loop; for more information, see `the
+ documentation for the "for" tag`_.
+
+.. _the documentation for the "for" tag: ../templates/#for
Now, let's create a Django view that handles the submitted data and does
something with it. Remember, in `Tutorial 3`_, we created a URLconf for the
diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt
index 789399de8d..053ee954a3 100644
--- a/docs/url_dispatch.txt
+++ b/docs/url_dispatch.txt
@@ -32,9 +32,11 @@ How Django processes a request
When a user requests a page from your Django-powered site, this is the
algorithm the system follows to determine which Python code to execute:
- 1. Django looks at the ``ROOT_URLCONF`` setting in your `settings file`_.
- This should be a string representing the full Python import path to your
- URLconf. For example: ``"mydjangoapps.urls"``.
+ 1. Django determines the root URLConf module to use; ordinarily
+ this is the value of the ``ROOT_URLCONF`` setting in your
+ `settings file`_, but if the incoming ``HttpRequest`` object
+ has an attribute called ``urlconf``, its value will be used in
+ place of the ``ROOT_URLCONF`` setting.
2. Django loads that Python module and looks for the variable
``urlpatterns``. This should be a Python list, in the format returned by
the function ``django.conf.urls.defaults.patterns()``.
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py
index 381d81b987..e3edf3187e 100644
--- a/tests/modeltests/custom_pk/models.py
+++ b/tests/modeltests/custom_pk/models.py
@@ -71,8 +71,9 @@ u'ABC123'
>>> fran.save()
>>> Employee.objects.filter(last_name__exact='Jones')
[<Employee: Dan Jones>, <Employee: Fran Jones>]
->>> Employee.objects.in_bulk(['ABC123', 'XYZ456'])
-{u'XYZ456': <Employee: Fran Jones>, u'ABC123': <Employee: Dan Jones>}
+>>> emps = Employee.objects.in_bulk(['ABC123', 'XYZ456'])
+>>> emps['ABC123']
+<Employee: Dan Jones>
>>> b = Business(name='Sears')
>>> b.save()
diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py
index f3cce70e12..5cff48ac51 100644
--- a/tests/modeltests/lookup/models.py
+++ b/tests/modeltests/lookup/models.py
@@ -76,8 +76,11 @@ Article 4
# in_bulk() takes a list of IDs and returns a dictionary mapping IDs
# to objects.
->>> Article.objects.in_bulk([1, 2])
-{1: <Article: Article 1>, 2: <Article: Article 2>}
+>>> arts = Article.objects.in_bulk([1, 2])
+>>> arts[1]
+<Article: Article 1>
+>>> arts[2]
+<Article: Article 2>
>>> Article.objects.in_bulk([3])
{3: <Article: Article 3>}
>>> Article.objects.in_bulk([1000])
diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py
index c9b9848235..3e52e33bbb 100644
--- a/tests/modeltests/manipulators/models.py
+++ b/tests/modeltests/manipulators/models.py
@@ -41,25 +41,33 @@ __test__ = {'API_TESTS':u"""
True
# Attempt to add a Musician without a first_name.
->>> man.get_validation_errors(MultiValueDict({'last_name': ['Blakey']}))
-{'first_name': [u'This field is required.']}
+>>> man.get_validation_errors(MultiValueDict({'last_name': ['Blakey']}))['first_name']
+[u'This field is required.']
# Attempt to add a Musician without a first_name and last_name.
->>> man.get_validation_errors(MultiValueDict({}))
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.']}
+>>> errors = man.get_validation_errors(MultiValueDict({}))
+>>> errors['first_name']
+[u'This field is required.']
+>>> errors['last_name']
+[u'This field is required.']
# Attempt to create an Album without a name or musician.
>>> man = Album.AddManipulator()
->>> man.get_validation_errors(MultiValueDict({}))
-{'musician': [u'This field is required.'], 'name': [u'This field is required.']}
+>>> errors = man.get_validation_errors(MultiValueDict({}))
+>>> errors['musician']
+[u'This field is required.']
+>>> errors['name']
+[u'This field is required.']
# Attempt to create an Album with an invalid musician.
->>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['foo']}))
-{'musician': [u"Select a valid choice; 'foo' is not in [u'', u'1']."]}
+>>> errors = man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['foo']}))
+>>> errors['musician']
+[u"Select a valid choice; 'foo' is not in [u'', u'1']."]
# Attempt to create an Album with an invalid release_date.
->>> man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['1'], 'release_date': 'today'}))
-{'release_date': [u'Enter a valid date in YYYY-MM-DD format.']}
+>>> errors = man.get_validation_errors(MultiValueDict({'name': ['Sallies Fforth'], 'musician': ['1'], 'release_date': 'today'}))
+>>> errors['release_date']
+[u'Enter a valid date in YYYY-MM-DD format.']
# Create an Album without a release_date (because it's optional).
>>> data = MultiValueDict({'name': ['Ella and Basie'], 'musician': ['1']})
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index c480899f84..470312f5ca 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -234,8 +234,12 @@ We can also subclass the Meta inner class to change the fields list.
>>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
>>> f.is_valid()
True
->>> f.cleaned_data
-{'url': u'entertainment', 'name': u'Entertainment', 'slug': u'entertainment'}
+>>> f.cleaned_data['url']
+u'entertainment'
+>>> f.cleaned_data['name']
+u'Entertainment'
+>>> f.cleaned_data['slug']
+u'entertainment'
>>> obj = f.save()
>>> obj
<Category: Entertainment>
@@ -245,8 +249,12 @@ True
>>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
>>> f.is_valid()
True
->>> f.cleaned_data
-{'url': u'test', 'name': u"It's a test", 'slug': u'its-test'}
+>>> f.cleaned_data['url']
+u'test'
+>>> f.cleaned_data['name']
+u"It's a test"
+>>> f.cleaned_data['slug']
+u'its-test'
>>> obj = f.save()
>>> obj
<Category: It's a test>
@@ -259,8 +267,12 @@ save() on the resulting model instance.
>>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
>>> f.is_valid()
True
->>> f.cleaned_data
-{'url': u'third', 'name': u'Third test', 'slug': u'third-test'}
+>>> f.cleaned_data['url']
+u'third'
+>>> f.cleaned_data['name']
+u'Third test'
+>>> f.cleaned_data['slug']
+u'third-test'
>>> obj = f.save(commit=False)
>>> obj
<Category: Third test>
@@ -272,8 +284,10 @@ True
If you call save() with invalid data, you'll get a ValueError.
>>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'})
->>> f.errors
-{'name': [u'This field is required.'], 'slug': [u'This field is required.']}
+>>> f.errors['name']
+[u'This field is required.']
+>>> f.errors['slug']
+[u'This field is required.']
>>> f.cleaned_data
Traceback (most recent call last):
...
@@ -645,6 +659,19 @@ Traceback (most recent call last):
...
ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+# check that we can safely iterate choices repeatedly
+>>> gen_one = list(f.choices)
+>>> gen_two = f.choices
+>>> gen_one[2]
+(2L, u"It's a test")
+>>> list(gen_two)
+[(u'', u'---------'), (1L, u'Entertainment'), (2L, u"It's a test"), (3L, u'Third')]
+
+# check that we can override the label_from_instance method to print custom labels (#4620)
+>>> f.queryset = Category.objects.all()
+>>> f.label_from_instance = lambda obj: "category " + str(obj)
+>>> list(f.choices)
+[(u'', u'---------'), (1L, 'category Entertainment'), (2L, "category It's a test"), (3L, 'category Third'), (4L, 'category Fourth')]
# ModelMultipleChoiceField ####################################################
@@ -730,6 +757,10 @@ Traceback (most recent call last):
...
ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
+>>> f.queryset = Category.objects.all()
+>>> f.label_from_instance = lambda obj: "multicategory " + str(obj)
+>>> list(f.choices)
+[(1L, 'multicategory Entertainment'), (2L, "multicategory It's a test"), (3L, 'multicategory Third'), (4L, 'multicategory Fourth')]
# PhoneNumberField ############################################################
@@ -739,8 +770,10 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
>>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
>>> f.is_valid()
True
->>> f.cleaned_data
-{'phone': u'312-555-1212', 'description': u'Assistance'}
+>>> f.cleaned_data['phone']
+u'312-555-1212'
+>>> f.cleaned_data['description']
+u'Assistance'
# FileField ###################################################################
@@ -766,7 +799,7 @@ True
<class 'django.newforms.fields.UploadedFile'>
>>> instance = f.save()
>>> instance.file
-u'.../test1.txt'
+u'...test1.txt'
# Edit an instance that already has the file defined in the model. This will not
# save the file again, but leave it exactly as it is.
@@ -775,10 +808,10 @@ u'.../test1.txt'
>>> f.is_valid()
True
>>> f.cleaned_data['file']
-u'.../test1.txt'
+u'...test1.txt'
>>> instance = f.save()
>>> instance.file
-u'.../test1.txt'
+u'...test1.txt'
# Delete the current file since this is not done by Django.
@@ -791,7 +824,7 @@ u'.../test1.txt'
True
>>> instance = f.save()
>>> instance.file
-u'.../test2.txt'
+u'...test2.txt'
>>> instance.delete()
@@ -810,7 +843,7 @@ True
True
>>> instance = f.save()
>>> instance.file
-u'.../test3.txt'
+u'...test3.txt'
>>> instance.delete()
# ImageField ###################################################################
@@ -832,7 +865,7 @@ True
<class 'django.newforms.fields.UploadedFile'>
>>> instance = f.save()
>>> instance.image
-u'.../test.png'
+u'...test.png'
# Edit an instance that already has the image defined in the model. This will not
# save the image again, but leave it exactly as it is.
@@ -841,10 +874,10 @@ u'.../test.png'
>>> f.is_valid()
True
>>> f.cleaned_data['image']
-u'.../test.png'
+u'...test.png'
>>> instance = f.save()
>>> instance.image
-u'.../test.png'
+u'...test.png'
# Delete the current image since this is not done by Django.
@@ -857,7 +890,7 @@ u'.../test.png'
True
>>> instance = f.save()
>>> instance.image
-u'.../test2.png'
+u'...test2.png'
>>> instance.delete()
@@ -876,7 +909,7 @@ True
True
>>> instance = f.save()
>>> instance.image
-u'.../test3.png'
+u'...test3.png'
>>> instance.delete()
"""}
diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py
index f44c67a139..277c5961e3 100644
--- a/tests/modeltests/pagination/models.py
+++ b/tests/modeltests/pagination/models.py
@@ -4,6 +4,11 @@
Django provides a framework for paginating a list of objects in a few lines
of code. This is often useful for dividing search results or long lists of
objects into easily readable pages.
+
+In Django 0.96 and earlier, a single ObjectPaginator class implemented this
+functionality. In the Django development version, the behavior is split across
+two classes -- Paginator and Page -- that are more easier to use. The legacy
+ObjectPaginator class is deprecated.
"""
from django.db import models
@@ -16,70 +21,210 @@ class Article(models.Model):
return self.headline
__test__ = {'API_TESTS':"""
-# prepare a list of objects for pagination
+# Prepare a list of objects for pagination.
>>> from datetime import datetime
>>> for x in range(1, 10):
... a = Article(headline='Article %s' % x, pub_date=datetime(2005, 7, 29))
... a.save()
-# create a basic paginator, 5 articles per page
+####################################
+# New/current API (Paginator/Page) #
+####################################
+
+>>> from django.core.paginator import Paginator, InvalidPage
+>>> paginator = Paginator(Article.objects.all(), 5)
+>>> paginator.count
+9
+>>> paginator.num_pages
+2
+>>> paginator.page_range
+[1, 2]
+
+# Get the first page.
+>>> p = paginator.page(1)
+>>> p
+<Page 1 of 2>
+>>> p.object_list
+[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>, <Article: Article 5>]
+>>> p.has_next()
+True
+>>> p.has_previous()
+False
+>>> p.has_other_pages()
+True
+>>> p.next_page_number()
+2
+>>> p.previous_page_number()
+0
+>>> p.start_index()
+1
+>>> p.end_index()
+5
+
+# Get the second page.
+>>> p = paginator.page(2)
+>>> p
+<Page 2 of 2>
+>>> p.object_list
+[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>]
+>>> p.has_next()
+False
+>>> p.has_previous()
+True
+>>> p.has_other_pages()
+True
+>>> p.next_page_number()
+3
+>>> p.previous_page_number()
+1
+>>> p.start_index()
+6
+>>> p.end_index()
+9
+
+# Invalid pages raise InvalidPage.
+>>> paginator.page(0)
+Traceback (most recent call last):
+...
+InvalidPage: ...
+>>> paginator.page(3)
+Traceback (most recent call last):
+...
+InvalidPage: ...
+
+# Empty paginators with allow_empty_first_page=True.
+>>> paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=True)
+>>> paginator.count
+0
+>>> paginator.num_pages
+1
+>>> paginator.page_range
+[1]
+
+# Empty paginators with allow_empty_first_page=False.
+>>> paginator = Paginator(Article.objects.filter(id=0), 5, allow_empty_first_page=False)
+>>> paginator.count
+0
+>>> paginator.num_pages
+0
+>>> paginator.page_range
+[]
+
+# Paginators work with regular lists/tuples, too -- not just with QuerySets.
+>>> paginator = Paginator([1, 2, 3, 4, 5, 6, 7, 8, 9], 5)
+>>> paginator.count
+9
+>>> paginator.num_pages
+2
+>>> paginator.page_range
+[1, 2]
+
+# Get the first page.
+>>> p = paginator.page(1)
+>>> p
+<Page 1 of 2>
+>>> p.object_list
+[1, 2, 3, 4, 5]
+>>> p.has_next()
+True
+>>> p.has_previous()
+False
+>>> p.has_other_pages()
+True
+>>> p.next_page_number()
+2
+>>> p.previous_page_number()
+0
+>>> p.start_index()
+1
+>>> p.end_index()
+5
+
+################################
+# Legacy API (ObjectPaginator) #
+################################
+
+# Don't print out the deprecation warnings during testing.
+>>> from warnings import filterwarnings
+>>> filterwarnings("ignore")
+
>>> from django.core.paginator import ObjectPaginator, InvalidPage
>>> paginator = ObjectPaginator(Article.objects.all(), 5)
-
-# the paginator knows how many hits and pages it contains
>>> paginator.hits
9
-
>>> paginator.pages
2
+>>> paginator.page_range
+[1, 2]
-# get the first page (zero-based)
+# Get the first page.
>>> paginator.get_page(0)
[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>, <Article: Article 5>]
-
-# get the second page
->>> paginator.get_page(1)
-[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>]
-
-# does the first page have a next or previous page?
>>> paginator.has_next_page(0)
True
-
>>> paginator.has_previous_page(0)
False
+>>> paginator.first_on_page(0)
+1
+>>> paginator.last_on_page(0)
+5
-# check the second page
+# Get the second page.
+>>> paginator.get_page(1)
+[<Article: Article 6>, <Article: Article 7>, <Article: Article 8>, <Article: Article 9>]
>>> paginator.has_next_page(1)
False
-
>>> paginator.has_previous_page(1)
True
-
->>> paginator.first_on_page(0)
-1
>>> paginator.first_on_page(1)
6
->>> paginator.last_on_page(0)
-5
>>> paginator.last_on_page(1)
9
+# Invalid pages raise InvalidPage.
+>>> paginator.get_page(-1)
+Traceback (most recent call last):
+...
+InvalidPage: ...
+>>> paginator.get_page(2)
+Traceback (most recent call last):
+...
+InvalidPage: ...
+
+# Empty paginators with allow_empty_first_page=True.
+>>> paginator = ObjectPaginator(Article.objects.filter(id=0), 5)
+>>> paginator.count
+0
+>>> paginator.num_pages
+1
+>>> paginator.page_range
+[1]
+
+##################
+# Orphan support #
+##################
+
# Add a few more records to test out the orphans feature.
>>> for x in range(10, 13):
... Article(headline="Article %s" % x, pub_date=datetime(2006, 10, 6)).save()
-# With orphans set to 3 and 10 items per page, we should get all 12 items on a single page:
+# With orphans set to 3 and 10 items per page, we should get all 12 items on a single page.
+>>> paginator = Paginator(Article.objects.all(), 10, orphans=3)
+>>> paginator.num_pages
+1
+
+# With orphans only set to 1, we should get two pages.
+>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1)
+>>> paginator.num_pages
+2
+
+# LEGACY: With orphans set to 3 and 10 items per page, we should get all 12 items on a single page.
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=3)
>>> paginator.pages
1
-# With orphans only set to 1, we should get two pages:
+# LEGACY: With orphans only set to 1, we should get two pages.
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1)
>>> paginator.pages
2
-
-# The paginator can provide a list of all available pages.
->>> paginator = ObjectPaginator(Article.objects.all(), 10)
->>> paginator.page_range
-[1, 2]
"""}
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py
index aacd041678..63f9f7a361 100644
--- a/tests/modeltests/validation/models.py
+++ b/tests/modeltests/validation/models.py
@@ -41,8 +41,8 @@ __test__ = {'API_TESTS':"""
23
>>> p = Person(**dict(valid_params, id='foo'))
->>> p.validate()
-{'id': [u'This value must be an integer.']}
+>>> p.validate()['id']
+[u'This value must be an integer.']
>>> p = Person(**dict(valid_params, id=None))
>>> p.validate()
@@ -75,8 +75,8 @@ True
False
>>> p = Person(**dict(valid_params, is_child='foo'))
->>> p.validate()
-{'is_child': [u'This value must be either True or False.']}
+>>> p.validate()['is_child']
+[u'This value must be either True or False.']
>>> p = Person(**dict(valid_params, name=u'Jose'))
>>> p.validate()
@@ -115,8 +115,8 @@ datetime.date(2000, 5, 3)
datetime.date(2000, 5, 3)
>>> p = Person(**dict(valid_params, birthdate='foo'))
->>> p.validate()
-{'birthdate': [u'Enter a valid date in YYYY-MM-DD format.']}
+>>> p.validate()['birthdate']
+[u'Enter a valid date in YYYY-MM-DD format.']
>>> p = Person(**dict(valid_params, favorite_moment=datetime.datetime(2002, 4, 3, 13, 23)))
>>> p.validate()
@@ -143,11 +143,15 @@ datetime.datetime(2002, 4, 3, 0, 0)
u'john@example.com'
>>> p = Person(**dict(valid_params, email=22))
->>> p.validate()
-{'email': [u'Enter a valid e-mail address.']}
+>>> p.validate()['email']
+[u'Enter a valid e-mail address.']
# Make sure that Date and DateTime return validation errors and don't raise Python errors.
->>> Person(name='John Doe', is_child=True, email='abc@def.com').validate()
-{'favorite_moment': [u'This field is required.'], 'birthdate': [u'This field is required.']}
+>>> p = Person(name='John Doe', is_child=True, email='abc@def.com')
+>>> errors = p.validate()
+>>> errors['favorite_moment']
+[u'This field is required.']
+>>> errors['birthdate']
+[u'This field is required.']
"""}
diff --git a/tests/regressiontests/forms/extra.py b/tests/regressiontests/forms/extra.py
index 9dff4071f1..a8b369715d 100644
--- a/tests/regressiontests/forms/extra.py
+++ b/tests/regressiontests/forms/extra.py
@@ -22,7 +22,7 @@ classes that demonstrate some of the library's abilities.
>>> from django.newforms.extras import SelectDateWidget
>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
>>> print w.render('mydate', '')
-<select name="mydate_month">
+<select name="mydate_month" id="id_mydate_month">
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
@@ -36,7 +36,7 @@ classes that demonstrate some of the library's abilities.
<option value="11">November</option>
<option value="12">December</option>
</select>
-<select name="mydate_day">
+<select name="mydate_day" id="id_mydate_day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
@@ -69,7 +69,7 @@ classes that demonstrate some of the library's abilities.
<option value="30">30</option>
<option value="31">31</option>
</select>
-<select name="mydate_year">
+<select name="mydate_year" id="id_mydate_year">
<option value="2007">2007</option>
<option value="2008">2008</option>
<option value="2009">2009</option>
@@ -84,7 +84,7 @@ classes that demonstrate some of the library's abilities.
>>> w.render('mydate', None) == w.render('mydate', '')
True
>>> print w.render('mydate', '2010-04-15')
-<select name="mydate_month">
+<select name="mydate_month" id="id_mydate_month">
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
@@ -98,7 +98,7 @@ True
<option value="11">November</option>
<option value="12">December</option>
</select>
-<select name="mydate_day">
+<select name="mydate_day" id="id_mydate_day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
@@ -131,7 +131,74 @@ True
<option value="30">30</option>
<option value="31">31</option>
</select>
-<select name="mydate_year">
+<select name="mydate_year" id="id_mydate_year">
+<option value="2007">2007</option>
+<option value="2008">2008</option>
+<option value="2009">2009</option>
+<option value="2010" selected="selected">2010</option>
+<option value="2011">2011</option>
+<option value="2012">2012</option>
+<option value="2013">2013</option>
+<option value="2014">2014</option>
+<option value="2015">2015</option>
+<option value="2016">2016</option>
+</select>
+
+Accepts a datetime or a string:
+
+>>> w.render('mydate', datetime.date(2010, 4, 15)) == w.render('mydate', '2010-04-15')
+True
+
+Invalid dates still render the failed date:
+>>> print w.render('mydate', '2010-02-31')
+<select name="mydate_month" id="id_mydate_month">
+<option value="1">January</option>
+<option value="2" selected="selected">February</option>
+<option value="3">March</option>
+<option value="4">April</option>
+<option value="5">May</option>
+<option value="6">June</option>
+<option value="7">July</option>
+<option value="8">August</option>
+<option value="9">September</option>
+<option value="10">October</option>
+<option value="11">November</option>
+<option value="12">December</option>
+</select>
+<select name="mydate_day" id="id_mydate_day">
+<option value="1">1</option>
+<option value="2">2</option>
+<option value="3">3</option>
+<option value="4">4</option>
+<option value="5">5</option>
+<option value="6">6</option>
+<option value="7">7</option>
+<option value="8">8</option>
+<option value="9">9</option>
+<option value="10">10</option>
+<option value="11">11</option>
+<option value="12">12</option>
+<option value="13">13</option>
+<option value="14">14</option>
+<option value="15">15</option>
+<option value="16">16</option>
+<option value="17">17</option>
+<option value="18">18</option>
+<option value="19">19</option>
+<option value="20">20</option>
+<option value="21">21</option>
+<option value="22">22</option>
+<option value="23">23</option>
+<option value="24">24</option>
+<option value="25">25</option>
+<option value="26">26</option>
+<option value="27">27</option>
+<option value="28">28</option>
+<option value="29">29</option>
+<option value="30">30</option>
+<option value="31" selected="selected">31</option>
+</select>
+<select name="mydate_year" id="id_mydate_year">
<option value="2007">2007</option>
<option value="2008">2008</option>
<option value="2009">2009</option>
@@ -252,8 +319,8 @@ ValidationError: [u'This field is required.']
</select>
<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
->>> f.cleaned_data
-{'field1': u'some text,JP,2007-04-25 06:24:00'}
+>>> f.cleaned_data['field1']
+u'some text,JP,2007-04-25 06:24:00'
# IPAddressField ##################################################################
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
index 9216210e09..9421d8c005 100644
--- a/tests/regressiontests/forms/fields.py
+++ b/tests/regressiontests/forms/fields.py
@@ -1133,6 +1133,33 @@ u''
>>> f.clean(None)
u''
+# FilePathField ###############################################################
+
+>>> import os
+>>> from django import newforms as forms
+>>> path = forms.__file__
+>>> path = os.path.dirname(path) + '/'
+>>> path
+'.../django/newforms/'
+>>> f = forms.FilePathField(path=path)
+>>> f.choices.sort()
+>>> f.choices
+[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/__init__.pyc', '__init__.pyc'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/fields.pyc', 'fields.pyc'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/forms.pyc', 'forms.pyc'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/models.pyc', 'models.pyc'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/util.pyc', 'util.pyc'), ('.../django/newforms/widgets.py', 'widgets.py'), ('.../django/newforms/widgets.pyc', 'widgets.pyc')]
+>>> f.clean('fields.py')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+>>> f.clean(path + 'fields.py')
+u'.../django/newforms/fields.py'
+>>> f = forms.FilePathField(path=path, match='^.*?\.py$')
+>>> f.choices.sort()
+>>> f.choices
+[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')]
+>>> f = forms.FilePathField(path=path, recursive=True, match='^.*?\.py$')
+>>> f.choices.sort()
+>>> f.choices
+[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/extras/__init__.py', 'extras/__init__.py'), ('.../django/newforms/extras/widgets.py', 'extras/widgets.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')]
+
# SplitDateTimeField ##########################################################
>>> f = SplitDateTimeField()
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py
index 7c0cf8abf3..d7fa1780f5 100644
--- a/tests/regressiontests/forms/forms.py
+++ b/tests/regressiontests/forms/forms.py
@@ -36,8 +36,8 @@ True
u''
>>> p.errors.as_text()
u''
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p.cleaned_data["first_name"], p.cleaned_data["last_name"], p.cleaned_data["birthday"]
+(u'John', u'Lennon', datetime.date(1940, 10, 9))
>>> print p['first_name']
<input type="text" name="first_name" value="John" id="id_first_name" />
>>> print p['last_name']
@@ -68,8 +68,12 @@ Empty dictionaries are valid, too.
>>> p = Person({})
>>> p.is_bound
True
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.errors['first_name']
+[u'This field is required.']
+>>> p.errors['last_name']
+[u'This field is required.']
+>>> p.errors['birthday']
+[u'This field is required.']
>>> p.is_valid()
False
>>> p.cleaned_data
@@ -137,8 +141,10 @@ u'<li><label for="id_first_name">First name:</label> <input type="text" name="fi
u'<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" value="John" id="id_first_name" /></p>\n<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" /></p>\n<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></p>'
>>> p = Person({'last_name': u'Lennon'})
->>> p.errors
-{'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.errors['first_name']
+[u'This field is required.']
+>>> p.errors['birthday']
+[u'This field is required.']
>>> p.is_valid()
False
>>> p.errors.as_ul()
@@ -175,8 +181,13 @@ but cleaned_data contains only the form's fields.
>>> p = Person(data)
>>> p.is_valid()
True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p.cleaned_data['first_name']
+u'John'
+>>> p.cleaned_data['last_name']
+u'Lennon'
+>>> p.cleaned_data['birthday']
+datetime.date(1940, 10, 9)
+
cleaned_data will include a key and value for *all* fields defined in the Form,
even if the Form's data didn't include a value for fields that are not
@@ -191,8 +202,12 @@ empty string.
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
->>> f.cleaned_data
-{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
+>>> f.cleaned_data['nick_name']
+u''
+>>> f.cleaned_data['first_name']
+u'John'
+>>> f.cleaned_data['last_name']
+u'Lennon'
For DateFields, it's set to None.
>>> class OptionalPersonForm(Form):
@@ -203,8 +218,12 @@ For DateFields, it's set to None.
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
->>> f.cleaned_data
-{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'}
+>>> print f.cleaned_data['birth_date']
+None
+>>> f.cleaned_data['first_name']
+u'John'
+>>> f.cleaned_data['last_name']
+u'Lennon'
"auto_id" tells the Form to add an "id" attribute to each form element.
If it's a string that contains '%s', Django will use that as a format string
@@ -549,18 +568,22 @@ The MultipleHiddenInput widget renders multiple values as hidden fields.
When using CheckboxSelectMultiple, the framework expects a list of input and
returns a list of input.
>>> f = SongForm({'name': 'Yesterday'}, auto_id=False)
->>> f.errors
-{'composers': [u'This field is required.']}
+>>> f.errors['composers']
+[u'This field is required.']
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
>>> f.errors
{}
->>> f.cleaned_data
-{'composers': [u'J'], 'name': u'Yesterday'}
+>>> f.cleaned_data['composers']
+[u'J']
+>>> f.cleaned_data['name']
+u'Yesterday'
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
>>> f.errors
{}
->>> f.cleaned_data
-{'composers': [u'J', u'P'], 'name': u'Yesterday'}
+>>> f.cleaned_data['composers']
+[u'J', u'P']
+>>> f.cleaned_data['name']
+u'Yesterday'
Validation errors are HTML-escaped when output as HTML.
>>> class EscapingForm(Form):
@@ -598,16 +621,24 @@ including the current field (e.g., the field XXX if you're in clean_XXX()).
>>> f.errors
{}
>>> f = UserRegistration({}, auto_id=False)
->>> f.errors
-{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
+>>> f.errors['username']
+[u'This field is required.']
+>>> f.errors['password1']
+[u'This field is required.']
+>>> f.errors['password2']
+[u'This field is required.']
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
->>> f.errors
-{'password2': [u'Please make sure your passwords match.']}
+>>> f.errors['password2']
+[u'Please make sure your passwords match.']
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors
{}
->>> f.cleaned_data
-{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
+>>> f.cleaned_data['username']
+u'adrian'
+>>> f.cleaned_data['password1']
+u'foo'
+>>> f.cleaned_data['password2']
+u'foo'
Another way of doing multiple-field validation is by implementing the
Form's clean() method. If you do this, any ValidationError raised by that
@@ -632,11 +663,15 @@ Form.clean() is required to return a dictionary of all clean data.
<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr>
<tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr>
<tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password2" /></td></tr>
->>> f.errors
-{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
+>>> f.errors['username']
+[u'This field is required.']
+>>> f.errors['password1']
+[u'This field is required.']
+>>> f.errors['password2']
+[u'This field is required.']
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
->>> f.errors
-{'__all__': [u'Please make sure your passwords match.']}
+>>> f.errors['__all__']
+[u'Please make sure your passwords match.']
>>> print f.as_table()
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
<tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>
@@ -650,8 +685,12 @@ Form.clean() is required to return a dictionary of all clean data.
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors
{}
->>> f.cleaned_data
-{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
+>>> f.cleaned_data['username']
+u'adrian'
+>>> f.cleaned_data['password1']
+u'foo'
+>>> f.cleaned_data['password2']
+u'foo'
# Dynamic construction ########################################################
@@ -1024,8 +1063,8 @@ An 'initial' value is *not* used as a fallback if data is not provided. In this
example, we don't provide a value for 'username', and the form raises a
validation error rather than using the initial value for 'username'.
>>> p = UserRegistration({'password': 'secret'})
->>> p.errors
-{'username': [u'This field is required.']}
+>>> p.errors['username']
+[u'This field is required.']
>>> p.is_valid()
False
@@ -1069,8 +1108,8 @@ A dynamic 'initial' value is *not* used as a fallback if data is not provided.
In this example, we don't provide a value for 'username', and the form raises a
validation error rather than using the initial value for 'username'.
>>> p = UserRegistration({'password': 'secret'}, initial={'username': 'django'})
->>> p.errors
-{'username': [u'This field is required.']}
+>>> p.errors['username']
+[u'This field is required.']
>>> p.is_valid()
False
@@ -1123,8 +1162,8 @@ A callable 'initial' value is *not* used as a fallback if data is not provided.
In this example, we don't provide a value for 'username', and the form raises a
validation error rather than using the initial value for 'username'.
>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
->>> p.errors
-{'username': [u'This field is required.']}
+>>> p.errors['username']
+[u'This field is required.']
>>> p.is_valid()
False
@@ -1258,8 +1297,12 @@ actual field name.
{}
>>> p.is_valid()
True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p.cleaned_data['first_name']
+u'John'
+>>> p.cleaned_data['last_name']
+u'Lennon'
+>>> p.cleaned_data['birthday']
+datetime.date(1940, 10, 9)
Let's try submitting some bad data to make sure form.errors and field.errors
work as expected.
@@ -1269,8 +1312,12 @@ work as expected.
... 'person1-birthday': u''
... }
>>> p = Person(data, prefix='person1')
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.errors['first_name']
+[u'This field is required.']
+>>> p.errors['last_name']
+[u'This field is required.']
+>>> p.errors['birthday']
+[u'This field is required.']
>>> p['first_name'].errors
[u'This field is required.']
>>> p['person1-first_name'].errors
@@ -1286,8 +1333,12 @@ the form doesn't "see" the fields.
... 'birthday': u'1940-10-9'
... }
>>> p = Person(data, prefix='person1')
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.errors['first_name']
+[u'This field is required.']
+>>> p.errors['last_name']
+[u'This field is required.']
+>>> p.errors['birthday']
+[u'This field is required.']
With prefixes, a single data dictionary can hold data for multiple instances
of the same form.
@@ -1302,13 +1353,21 @@ of the same form.
>>> p1 = Person(data, prefix='person1')
>>> p1.is_valid()
True
->>> p1.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p1.cleaned_data['first_name']
+u'John'
+>>> p1.cleaned_data['last_name']
+u'Lennon'
+>>> p1.cleaned_data['birthday']
+datetime.date(1940, 10, 9)
>>> p2 = Person(data, prefix='person2')
>>> p2.is_valid()
True
->>> p2.cleaned_data
-{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)}
+>>> p2.cleaned_data['first_name']
+u'Jim'
+>>> p2.cleaned_data['last_name']
+u'Morrison'
+>>> p2.cleaned_data['birthday']
+datetime.date(1943, 12, 8)
By default, forms append a hyphen between the prefix and the field name, but a
form can alter that behavior by implementing the add_prefix() method. This
@@ -1333,8 +1392,12 @@ self.prefix.
>>> p = Person(data, prefix='foo')
>>> p.is_valid()
True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p.cleaned_data['first_name']
+u'John'
+>>> p.cleaned_data['last_name']
+u'Lennon'
+>>> p.cleaned_data['birthday']
+datetime.date(1940, 10, 9)
# Forms with NullBooleanFields ################################################
diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py
index e69de29bb2..7e07227961 100644
--- a/tests/regressiontests/model_fields/models.py
+++ b/tests/regressiontests/model_fields/models.py
@@ -0,0 +1,24 @@
+
+from django.db import models
+
+class Foo(models.Model):
+ a = models.CharField(max_length=10)
+
+def get_foo():
+ return Foo.objects.get(id=1)
+
+class Bar(models.Model):
+ b = models.CharField(max_length=10)
+ a = models.ForeignKey(Foo, default=get_foo)
+
+__test__ = {'API_TESTS':"""
+# Create a couple of Places.
+>>> f = Foo.objects.create(a='abc')
+>>> f.id
+1
+>>> b = Bar(b = "bcd")
+>>> b.a
+<Foo: Foo object>
+>>> b.save()
+
+"""}
diff --git a/tests/regressiontests/syndication/__init__.py b/tests/regressiontests/syndication/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/syndication/__init__.py
diff --git a/tests/regressiontests/syndication/models.py b/tests/regressiontests/syndication/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/syndication/models.py
diff --git a/tests/regressiontests/syndication/tests.py b/tests/regressiontests/syndication/tests.py
new file mode 100644
index 0000000000..6a9dd643d7
--- /dev/null
+++ b/tests/regressiontests/syndication/tests.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+from django.test import TestCase
+from django.test.client import Client
+
+class SyndicationFeedTest(TestCase):
+ def test_complex_base_url(self):
+ """
+ Tests that that the base url for a complex feed doesn't raise a 500
+ exception.
+ """
+ c = Client()
+ response = c.get('/syndication/feeds/complex/')
+ self.assertEquals(response.status_code, 404)
diff --git a/tests/regressiontests/syndication/urls.py b/tests/regressiontests/syndication/urls.py
new file mode 100644
index 0000000000..24644ffd53
--- /dev/null
+++ b/tests/regressiontests/syndication/urls.py
@@ -0,0 +1,18 @@
+from django.conf.urls.defaults import patterns
+from django.core.exceptions import ObjectDoesNotExist
+from django.contrib.syndication import feeds
+
+
+class ComplexFeed(feeds.Feed):
+ def get_object(self, bits):
+ if len(bits) != 1:
+ raise ObjectDoesNotExist
+ return None
+
+
+urlpatterns = patterns('',
+ (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {
+ 'feed_dict': dict(
+ complex = ComplexFeed,
+ )}),
+)
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index b5d9ae63b9..305ccc9aa3 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -3,7 +3,7 @@ Regression tests for the Test Client, especially the customized assertions.
"""
from django.test import Client, TestCase
-from django.core import mail
+from django.core.urlresolvers import reverse
import os
class AssertContainsTests(TestCase):
@@ -261,3 +261,31 @@ class LoginTests(TestCase):
# Check that assertRedirects uses the original client, not the
# default client.
self.assertRedirects(response, "http://testserver/test_client_regress/get_view/")
+
+
+class URLEscapingTests(TestCase):
+ def test_simple_argument_get(self):
+ "Get a view that has a simple string argument"
+ response = self.client.get(reverse('arg_view', args=['Slartibartfast']))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'Howdy, Slartibartfast')
+
+ def test_argument_with_space_get(self):
+ "Get a view that has a string argument that requires escaping"
+ response = self.client.get(reverse('arg_view', args=['Arthur Dent']))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'Hi, Arthur')
+
+ def test_simple_argument_post(self):
+ "Post for a view that has a simple string argument"
+ response = self.client.post(reverse('arg_view', args=['Slartibartfast']))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'Howdy, Slartibartfast')
+
+ def test_argument_with_space_post(self):
+ "Post for a view that has a string argument that requires escaping"
+ response = self.client.post(reverse('arg_view', args=['Arthur Dent']))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'Hi, Arthur')
+
+
diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py
index e771707f61..d3304caef0 100644
--- a/tests/regressiontests/test_client_regress/urls.py
+++ b/tests/regressiontests/test_client_regress/urls.py
@@ -5,5 +5,6 @@ urlpatterns = patterns('',
(r'^no_template_view/$', views.no_template_view),
(r'^file_upload/$', views.file_upload_view),
(r'^get_view/$', views.get_view),
+ url(r'^arg_view/(?P<name>.+)/$', views.view_with_argument, name='arg_view'),
(r'^login_protected_redirect_view/$', views.login_protected_redirect_view)
)
diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py
index 75efd212e1..f44757dc10 100644
--- a/tests/regressiontests/test_client_regress/views.py
+++ b/tests/regressiontests/test_client_regress/views.py
@@ -1,7 +1,5 @@
from django.contrib.auth.decorators import login_required
-from django.core.mail import EmailMessage, SMTPConnection
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
-from django.shortcuts import render_to_response
def no_template_view(request):
"A simple view that expects a GET request, and returns a rendered template"
@@ -20,10 +18,22 @@ def file_upload_view(request):
return HttpResponseServerError()
def get_view(request):
- "A simple login protected view"
+ "A simple login protected view"
return HttpResponse("Hello world")
get_view = login_required(get_view)
+def view_with_argument(request, name):
+ """A view that takes a string argument
+
+ The purpose of this view is to check that if a space is provided in
+ the argument, the test framework unescapes the %20 before passing
+ the value to the view.
+ """
+ if name == 'Arthur Dent':
+ return HttpResponse('Hi, Arthur')
+ else:
+ return HttpResponse('Howdy, %s' % name)
+
def login_protected_redirect_view(request):
"A view that redirects all requests to the GET view"
return HttpResponseRedirect('/test_client_regress/get_view/')
diff --git a/tests/urls.py b/tests/urls.py
index 41b4aaf6d3..dbdf9a8064 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -19,4 +19,7 @@ urlpatterns = patterns('',
(r'^middleware/', include('regressiontests.middleware.urls')),
(r'^utils/', include('regressiontests.utils.urls')),
+
+ # test urlconf for syndication tests
+ (r'^syndication/', include('regressiontests.syndication.urls')),
)