1
0
mirror of https://github.com/django/django.git synced 2025-07-05 02:09:13 +00:00

newforms-admin: Merged to [4545]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4546 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-02-20 00:41:14 +00:00
parent 649423e81c
commit 67e0248806
55 changed files with 11374 additions and 2745 deletions

View File

@ -104,6 +104,7 @@ answer newbie questions, and generally made Django that much better:
Michael Josephson <http://www.sdjournal.com/> Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com jpellerin@gmail.com
junzhang.jn@gmail.com junzhang.jn@gmail.com
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
Garth Kidd <http://www.deadlybloodyserious.com/> Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr> kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/> Sune Kirkeby <http://ibofobi.dk/>
@ -153,15 +154,18 @@ answer newbie questions, and generally made Django that much better:
Michael Radziej <mir@noris.de> Michael Radziej <mir@noris.de>
ramiro ramiro
Brian Ray <http://brianray.chipy.org/> Brian Ray <http://brianray.chipy.org/>
remco@diji.biz
rhettg@gmail.com rhettg@gmail.com
Oliver Rutherfurd <http://rutherfurd.net/> Oliver Rutherfurd <http://rutherfurd.net/>
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
David Schein David Schein
scott@staplefish.com
serbaut@gmail.com serbaut@gmail.com
Pete Shinners <pete@shinners.org> Pete Shinners <pete@shinners.org>
SmileyChris <smileychris@gmail.com> SmileyChris <smileychris@gmail.com>
smurf@smurf.noris.de smurf@smurf.noris.de
sopel sopel
Georgi Stanojevski <glisha@gmail.com>
Thomas Steinacher <tom@eggdrop.ch> Thomas Steinacher <tom@eggdrop.ch>
nowell strite nowell strite
Radek Švarz <http://www.svarz.cz/translate/> Radek Švarz <http://www.svarz.cz/translate/>
@ -175,6 +179,7 @@ answer newbie questions, and generally made Django that much better:
Makoto Tsuyuki <mtsuyuki@gmail.com> Makoto Tsuyuki <mtsuyuki@gmail.com>
Amit Upadhyay Amit Upadhyay
Geert Vanderkelen Geert Vanderkelen
viestards.lists@gmail.com
Milton Waddams Milton Waddams
wam-djangobug@wamber.net wam-djangobug@wamber.net
Dan Watson <http://theidioteque.net/> Dan Watson <http://theidioteque.net/>

View File

@ -38,6 +38,7 @@ LANGUAGE_CODE = 'en-us'
LANGUAGES = ( LANGUAGES = (
('ar', gettext_noop('Arabic')), ('ar', gettext_noop('Arabic')),
('bn', gettext_noop('Bengali')), ('bn', gettext_noop('Bengali')),
('ca', gettext_noop('Catalan')),
('cs', gettext_noop('Czech')), ('cs', gettext_noop('Czech')),
('cy', gettext_noop('Welsh')), ('cy', gettext_noop('Welsh')),
('da', gettext_noop('Danish')), ('da', gettext_noop('Danish')),
@ -54,6 +55,8 @@ LANGUAGES = (
('is', gettext_noop('Icelandic')), ('is', gettext_noop('Icelandic')),
('it', gettext_noop('Italian')), ('it', gettext_noop('Italian')),
('ja', gettext_noop('Japanese')), ('ja', gettext_noop('Japanese')),
('lv', gettext_noop('Latvian')),
('mk', gettext_noop('Macedonian')),
('nl', gettext_noop('Dutch')), ('nl', gettext_noop('Dutch')),
('no', gettext_noop('Norwegian')), ('no', gettext_noop('Norwegian')),
('pl', gettext_noop('Polish')), ('pl', gettext_noop('Polish')),

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,121 @@
# translation of djangojs.po to
# Spanish translation for the django-admin JS files.
# Copyright (C)
# This file is distributed under the same license as the PACKAGE package.
#
# Jorge Gajon <gajon@gajon.org>, 2005.
# Marc Fargas <marc@fargas.com>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-15 11:05+1100\n"
"PO-Revision-Date: 2007-01-19 10:30+0100\n"
"Last-Translator: Marc Fargas <marc@fargas.com>\n"
"Language-Team: <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "%s Disponibles"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "Seleccionar tots"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "Afegir"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Eliminar"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "%s Escollits"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Faci les seves seleccions i faci click a"
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Deseleccionar tots"
#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Diumenge Dilluns Dimarts Dimecres Dijous Divendres Dissabte"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "D L M X J V S"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Ara"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "Rellotje"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Esculli una hora"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Mitja nit"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "6 a.m."
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "Migdia"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Cancel·lar"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Avui"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Calendari"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Ahir"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Demà"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -107,3 +107,12 @@ msgstr "Gestern"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
msgid "Tomorrow" msgid "Tomorrow"
msgstr "Morgen" msgstr "Morgen"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "Anzeigen"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "Verbergen"

View File

@ -1029,19 +1029,19 @@ msgstr " %(filter_title)s:"
#: contrib/admin/templates/admin/submit_line.html:4 #: contrib/admin/templates/admin/submit_line.html:4
msgid "Save as new" msgid "Save as new"
msgstr "Talleta uutena" msgstr "Tallenna uutena"
#: contrib/admin/templates/admin/submit_line.html:5 #: contrib/admin/templates/admin/submit_line.html:5
msgid "Save and add another" msgid "Save and add another"
msgstr "Talleta ja lisää seuraava" msgstr "Tallenna ja lisää seuraava"
#: contrib/admin/templates/admin/submit_line.html:6 #: contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing" msgid "Save and continue editing"
msgstr "Talleta välillä ja jatka muokkaamista" msgstr "Tallenna välillä ja jatka muokkaamista"
#: contrib/admin/templates/admin/submit_line.html:7 #: contrib/admin/templates/admin/submit_line.html:7
msgid "Save" msgid "Save"
msgstr "Talleta ja poistu" msgstr "Tallenna ja poistu"
#: contrib/admin/templates/admin/change_list.html:11 #: contrib/admin/templates/admin/change_list.html:11
#, python-format #, python-format

View File

@ -1,13 +1,13 @@
# Translation of django.po to japanese. # Translation of django.po to japanese.
# Copyright (C) 2005,2006 THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2005,2006 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# makoto tsuyuki <mtsuyuki@gmail.com>, 2005,2006. # makoto tsuyuki <mtsuyuki@gmail.com>, 2005,2006,2007.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Django 1.0\n" "Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-10-21 20:42+0900\n" "POT-Creation-Date: 2007-02-15 23:43+0900\n"
"PO-Revision-Date: 2006-05-18 00:28+0900\n" "PO-Revision-Date: 2006-05-18 00:28+0900\n"
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n" "Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
"Language-Team: Japanese <django-ja@googlegroups.com>\n" "Language-Team: Japanese <django-ja@googlegroups.com>\n"
@ -24,126 +24,138 @@ msgid "Bengali"
msgstr "ベンガル語" msgstr "ベンガル語"
#: conf/global_settings.py:41 #: conf/global_settings.py:41
msgid "Catalan"
msgstr "カタロニア語"
#: conf/global_settings.py:42
msgid "Czech" msgid "Czech"
msgstr "チェコ語" msgstr "チェコ語"
#: conf/global_settings.py:42 #: conf/global_settings.py:43
msgid "Welsh" msgid "Welsh"
msgstr "ウェールズ語" msgstr "ウェールズ語"
#: conf/global_settings.py:43 #: conf/global_settings.py:44
msgid "Danish" msgid "Danish"
msgstr "デンマーク語" msgstr "デンマーク語"
#: conf/global_settings.py:44 #: conf/global_settings.py:45
msgid "German" msgid "German"
msgstr "ドイツ語" msgstr "ドイツ語"
#: conf/global_settings.py:45 #: conf/global_settings.py:46
msgid "Greek" msgid "Greek"
msgstr "ギリシャ語" msgstr "ギリシャ語"
#: conf/global_settings.py:46 #: conf/global_settings.py:47
msgid "English" msgid "English"
msgstr "英語" msgstr "英語"
#: conf/global_settings.py:47 #: conf/global_settings.py:48
msgid "Spanish" msgid "Spanish"
msgstr "スペイン語" msgstr "スペイン語"
#: conf/global_settings.py:48 #: conf/global_settings.py:49
msgid "Argentinean Spanish" msgid "Argentinean Spanish"
msgstr "アルゼンチンスペイン語" msgstr "アルゼンチンスペイン語"
#: conf/global_settings.py:49 #: conf/global_settings.py:50
msgid "Finnish" msgid "Finnish"
msgstr "フィンランド語" msgstr "フィンランド語"
#: conf/global_settings.py:50 #: conf/global_settings.py:51
msgid "French" msgid "French"
msgstr "フランス語" msgstr "フランス語"
#: conf/global_settings.py:51 #: conf/global_settings.py:52
msgid "Galician" msgid "Galician"
msgstr "ガリシア語" msgstr "ガリシア語"
#: conf/global_settings.py:52 #: conf/global_settings.py:53
msgid "Hungarian" msgid "Hungarian"
msgstr "ハンガリー語" msgstr "ハンガリー語"
#: conf/global_settings.py:53 #: conf/global_settings.py:54
msgid "Hebrew" msgid "Hebrew"
msgstr "ヘブライ語" msgstr "ヘブライ語"
#: conf/global_settings.py:54 #: conf/global_settings.py:55
msgid "Icelandic" msgid "Icelandic"
msgstr "アイスランド語" msgstr "アイスランド語"
#: conf/global_settings.py:55 #: conf/global_settings.py:56
msgid "Italian" msgid "Italian"
msgstr "イタリア語" msgstr "イタリア語"
#: conf/global_settings.py:56 #: conf/global_settings.py:57
msgid "Japanese" msgid "Japanese"
msgstr "日本語" msgstr "日本語"
#: conf/global_settings.py:57 #: conf/global_settings.py:58
msgid "Latvian"
msgstr "ラトビア語"
#: conf/global_settings.py:59
msgid "Macedonian"
msgstr "マケドニア語"
#: conf/global_settings.py:60
msgid "Dutch" msgid "Dutch"
msgstr "オランダ語" msgstr "オランダ語"
#: conf/global_settings.py:58 #: conf/global_settings.py:61
msgid "Norwegian" msgid "Norwegian"
msgstr "ノルウェー語" msgstr "ノルウェー語"
#: conf/global_settings.py:59 #: conf/global_settings.py:62
msgid "Polish" msgid "Polish"
msgstr "ポーランド語" msgstr "ポーランド語"
#: conf/global_settings.py:60 #: conf/global_settings.py:63
msgid "Brazilian" msgid "Brazilian"
msgstr "ブラジル語" msgstr "ブラジル語"
#: conf/global_settings.py:61 #: conf/global_settings.py:64
msgid "Romanian" msgid "Romanian"
msgstr "ルーマニア語" msgstr "ルーマニア語"
#: conf/global_settings.py:62 #: conf/global_settings.py:65
msgid "Russian" msgid "Russian"
msgstr "ロシア語" msgstr "ロシア語"
#: conf/global_settings.py:63 #: conf/global_settings.py:66
msgid "Slovak" msgid "Slovak"
msgstr "スロバキア語" msgstr "スロバキア語"
#: conf/global_settings.py:64 #: conf/global_settings.py:67
msgid "Slovenian" msgid "Slovenian"
msgstr "スロヴェニア語" msgstr "スロヴェニア語"
#: conf/global_settings.py:65 #: conf/global_settings.py:68
msgid "Serbian" msgid "Serbian"
msgstr "セルビア語" msgstr "セルビア語"
#: conf/global_settings.py:66 #: conf/global_settings.py:69
msgid "Swedish" msgid "Swedish"
msgstr "スウェーデン語" msgstr "スウェーデン語"
#: conf/global_settings.py:67 #: conf/global_settings.py:70
msgid "Tamil" msgid "Tamil"
msgstr "タミル語" msgstr "タミル語"
#: conf/global_settings.py:68 #: conf/global_settings.py:71
msgid "Turkish" msgid "Turkish"
msgstr "トルコ語" msgstr "トルコ語"
#: conf/global_settings.py:69 #: conf/global_settings.py:72
msgid "Ukrainian" msgid "Ukrainian"
msgstr "ウクライナ語" msgstr "ウクライナ語"
#: conf/global_settings.py:70 #: conf/global_settings.py:73
msgid "Simplified Chinese" msgid "Simplified Chinese"
msgstr "簡体字中国語" msgstr "簡体字中国語"
#: conf/global_settings.py:71 #: conf/global_settings.py:74
msgid "Traditional Chinese" msgid "Traditional Chinese"
msgstr "繁体字中国語" msgstr "繁体字中国語"
@ -181,15 +193,18 @@ msgstr "今月"
msgid "This year" msgid "This year"
msgstr "今年" msgstr "今年"
#: contrib/admin/filterspecs.py:143 #: contrib/admin/filterspecs.py:143 newforms/widgets.py:170
#: oldforms/__init__.py:572
msgid "Yes" msgid "Yes"
msgstr "はい" msgstr "はい"
#: contrib/admin/filterspecs.py:143 #: contrib/admin/filterspecs.py:143 newforms/widgets.py:170
#: oldforms/__init__.py:572
msgid "No" msgid "No"
msgstr "いいえ" msgstr "いいえ"
#: contrib/admin/filterspecs.py:150 #: contrib/admin/filterspecs.py:150 newforms/widgets.py:170
#: oldforms/__init__.py:572
msgid "Unknown" msgid "Unknown"
msgstr "不明" msgstr "不明"
@ -237,6 +252,7 @@ msgstr "申し訳ありませんが、お探しのページは見つかりませ
#: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/delete_confirmation.html:6
#: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/admin/invalid_setup.html:4
#: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin/object_history.html:5
#: contrib/admin/templates/admin/auth/user/change_password.html:12
#: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3
#: contrib/admin/templates/registration/logged_out.html:4 #: contrib/admin/templates/registration/logged_out.html:4
#: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_done.html:4
@ -275,6 +291,7 @@ msgstr "ようこそ"
#: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3
#: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_done.html:3
#: contrib/admin/templates/registration/password_change_form.html:3 #: contrib/admin/templates/registration/password_change_form.html:3
@ -286,6 +303,9 @@ msgstr "ドキュメント"
#: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin/auth/user/change_password.html:15
#: contrib/admin/templates/admin/auth/user/change_password.html:46
#: contrib/admin/templates/admin_doc/bookmarklets.html:4 #: contrib/admin/templates/admin_doc/bookmarklets.html:4
#: contrib/admin/templates/admin_doc/index.html:4 #: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/missing_docutils.html:4 #: contrib/admin/templates/admin_doc/missing_docutils.html:4
@ -306,6 +326,7 @@ msgstr "パスワードの変更"
#: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_list.html:5
#: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/delete_confirmation.html:3
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/auth/user/change_password.html:9
#: contrib/admin/templates/admin_doc/bookmarklets.html:4 #: contrib/admin/templates/admin_doc/bookmarklets.html:4
#: contrib/admin/templates/admin_doc/index.html:4 #: contrib/admin/templates/admin_doc/index.html:4
#: contrib/admin/templates/admin_doc/missing_docutils.html:4 #: contrib/admin/templates/admin_doc/missing_docutils.html:4
@ -335,30 +356,31 @@ msgstr "Django 管理サイト"
msgid "Add" msgid "Add"
msgstr "追加" msgstr "追加"
#: contrib/admin/templates/admin/change_form.html:20 #: contrib/admin/templates/admin/change_form.html:21
#: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin/object_history.html:5
msgid "History" msgid "History"
msgstr "履歴" msgstr "履歴"
#: contrib/admin/templates/admin/change_form.html:21 #: contrib/admin/templates/admin/change_form.html:22
msgid "View on site" msgid "View on site"
msgstr "サイト上で表示" msgstr "サイト上で表示"
#: contrib/admin/templates/admin/change_form.html:30 #: contrib/admin/templates/admin/change_form.html:32
#: contrib/admin/templates/admin/auth/user/change_password.html:24
msgid "Please correct the error below." msgid "Please correct the error below."
msgid_plural "Please correct the errors below." msgid_plural "Please correct the errors below."
msgstr[0] "下記のエラーを修正してください。" msgstr[0] "下記のエラーを修正してください。"
msgstr[1] "下記のエラーを修正してください。" msgstr[1] "下記のエラーを修正してください。"
#: contrib/admin/templates/admin/change_form.html:48 #: contrib/admin/templates/admin/change_form.html:50
msgid "Ordering" msgid "Ordering"
msgstr "順序" msgstr "順序"
#: contrib/admin/templates/admin/change_form.html:51 #: contrib/admin/templates/admin/change_form.html:53
msgid "Order:" msgid "Order:"
msgstr "並び変え:" msgstr "並び変え:"
#: contrib/admin/templates/admin/change_list.html:11 #: contrib/admin/templates/admin/change_list.html:12
#, python-format #, python-format
msgid "Add %(name)s" msgid "Add %(name)s"
msgstr "%(name)s を追加" msgstr "%(name)s を追加"
@ -451,10 +473,6 @@ msgstr "ユーザ名:"
msgid "Password:" msgid "Password:"
msgstr "パスワード:" msgstr "パスワード:"
#: contrib/admin/templates/admin/login.html:22
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
msgstr "<a href=\"/password_reset/\">パスワードをお忘れですか</a>"
#: contrib/admin/templates/admin/login.html:25 #: contrib/admin/templates/admin/login.html:25
#: contrib/admin/views/decorators.py:24 #: contrib/admin/views/decorators.py:24
msgid "Log in" msgid "Log in"
@ -533,17 +551,25 @@ msgid "Username"
msgstr "ユーザ名" msgstr "ユーザ名"
#: contrib/admin/templates/admin/auth/user/add_form.html:18 #: contrib/admin/templates/admin/auth/user/add_form.html:18
#: contrib/admin/templates/admin/auth/user/change_password.html:34
msgid "Password" msgid "Password"
msgstr "パスワード" msgstr "パスワード"
#: contrib/admin/templates/admin/auth/user/add_form.html:23 #: contrib/admin/templates/admin/auth/user/add_form.html:23
#: contrib/admin/templates/admin/auth/user/change_password.html:39
msgid "Password (again)" msgid "Password (again)"
msgstr "パスワード(確認用)" msgstr "パスワード(確認用)"
#: contrib/admin/templates/admin/auth/user/add_form.html:24 #: contrib/admin/templates/admin/auth/user/add_form.html:24
#: contrib/admin/templates/admin/auth/user/change_password.html:40
msgid "Enter the same password as above, for verification." msgid "Enter the same password as above, for verification."
msgstr "確認のため、再度パスワードを入力してください。" msgstr "確認のため、再度パスワードを入力してください。"
#: contrib/admin/templates/admin/auth/user/change_password.html:28
#, python-format
msgid "Enter a new password for the user <strong>%(username)s</strong>."
msgstr "<strong>%(username)s</strong>さんの新しいパスワードを入力してください。"
#: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets" msgid "Bookmarklets"
msgstr "ブックマークレット" msgstr "ブックマークレット"
@ -743,25 +769,34 @@ msgstr "現在:"
msgid "Change:" msgid "Change:"
msgstr "変更:" msgstr "変更:"
#: contrib/admin/templatetags/admin_list.py:230 #: contrib/admin/templatetags/admin_list.py:238
msgid "All dates" msgid "All dates"
msgstr "いつでも" msgstr "いつでも"
#: contrib/admin/views/auth.py:17 contrib/admin/views/main.py:257 #: contrib/admin/views/auth.py:19 contrib/admin/views/main.py:257
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully." msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" を追加しました。" msgstr "%(name)s \"%(obj)s\" を追加しました。"
#: contrib/admin/views/auth.py:22 contrib/admin/views/main.py:261 #: contrib/admin/views/auth.py:24 contrib/admin/views/main.py:261
#: contrib/admin/views/main.py:347 #: contrib/admin/views/main.py:347
msgid "You may edit it again below." msgid "You may edit it again below."
msgstr "続けて編集できます。" msgstr "続けて編集できます。"
#: contrib/admin/views/auth.py:28 #: contrib/admin/views/auth.py:30
msgid "Add user" msgid "Add user"
msgstr "ユーザを追加" msgstr "ユーザを追加"
#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59 #: contrib/admin/views/auth.py:57
msgid "Password changed successfully."
msgstr "パスワードを変更しました"
#: contrib/admin/views/auth.py:64
#, python-format
msgid "Change password: %s"
msgstr "パスワードの変更: %s"
#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60
msgid "" msgid ""
"Please enter a correct username and password. Note that both fields are case-" "Please enter a correct username and password. Note that both fields are case-"
"sensitive." "sensitive."
@ -949,7 +984,7 @@ msgid "Added %s."
msgstr "%s を追加しました。" msgstr "%s を追加しました。"
#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 #: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337
#: contrib/admin/views/main.py:339 #: contrib/admin/views/main.py:339 db/models/manipulators.py:306
msgid "and" msgid "and"
msgstr "と" msgstr "と"
@ -1021,15 +1056,15 @@ msgstr "変更する %s を選択"
msgid "Database error" msgid "Database error"
msgstr "データベースエラー" msgstr "データベースエラー"
#: contrib/auth/forms.py:16 #: contrib/auth/forms.py:17 contrib/auth/forms.py:138
msgid "The two password fields didn't match." msgid "The two password fields didn't match."
msgstr "確認用パスワードが一致しません。" msgstr "確認用パスワードが一致しません。"
#: contrib/auth/forms.py:24 #: contrib/auth/forms.py:25
msgid "A user with that username already exists." msgid "A user with that username already exists."
msgstr "同じユーザ名が既に登録済みです。" msgstr "同じユーザ名が既に登録済みです。"
#: contrib/auth/forms.py:52 #: contrib/auth/forms.py:53
msgid "" msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are " "Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in." "required for logging in."
@ -1037,21 +1072,21 @@ msgstr ""
"お使いのブラウザはクッキーを有効にしていないようです。ログインにはクッキーが" "お使いのブラウザはクッキーを有効にしていないようです。ログインにはクッキーが"
"必要です。" "必要です。"
#: contrib/auth/forms.py:61 #: contrib/auth/forms.py:62
msgid "This account is inactive." msgid "This account is inactive."
msgstr "アカウントが無効です。" msgstr "アカウントが無効です。"
#: contrib/auth/forms.py:84 #: contrib/auth/forms.py:85
msgid "" msgid ""
"That e-mail address doesn't have an associated user account. Are you sure " "That e-mail address doesn't have an associated user account. Are you sure "
"you've registered?" "you've registered?"
msgstr "メールアドレスの一致するユーザはいません。本当に登録しましたか?" msgstr "メールアドレスの一致するユーザはいません。本当に登録しましたか?"
#: contrib/auth/forms.py:116 #: contrib/auth/forms.py:117
msgid "The two 'new password' fields didn't match." msgid "The two 'new password' fields didn't match."
msgstr "新しいパスワード(確認用)が一致しません。" msgstr "新しいパスワード(確認用)が一致しません。"
#: contrib/auth/forms.py:123 #: contrib/auth/forms.py:124
msgid "Your old password was entered incorrectly. Please enter it again." msgid "Your old password was entered incorrectly. Please enter it again."
msgstr "元のパスワードが間違っています。もう一度入力してください。" msgstr "元のパスワードが間違っています。もう一度入力してください。"
@ -1108,8 +1143,12 @@ msgid "password"
msgstr "パスワード" msgstr "パスワード"
#: contrib/auth/models.py:94 #: contrib/auth/models.py:94
msgid "Use '[algo]$[salt]$[hexdigest]'" msgid ""
msgstr "'[アルゴリズム]$[ソルト]$[ダイジェスト(hex)]' 形式を使って下さい" "Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
msgstr ""
"'[algo]$[salt]$[hexdigest]'形式か、"
"<a href=\"password/\">パスワード変更フォーム</a>を使ってください。"
#: contrib/auth/models.py:95 #: contrib/auth/models.py:95
msgid "staff status" msgid "staff status"
@ -1478,15 +1517,15 @@ msgstr "コメント ID が不正です"
msgid "No voting for yourself" msgid "No voting for yourself"
msgstr "自分には投票できません。" msgstr "自分には投票できません。"
#: contrib/contenttypes/models.py:20 #: contrib/contenttypes/models.py:26
msgid "python model class name" msgid "python model class name"
msgstr "Python モデルクラス名" msgstr "Python モデルクラス名"
#: contrib/contenttypes/models.py:23 #: contrib/contenttypes/models.py:29
msgid "content type" msgid "content type"
msgstr "コンテンツタイプ" msgstr "コンテンツタイプ"
#: contrib/contenttypes/models.py:24 #: contrib/contenttypes/models.py:30
msgid "content types" msgid "content types"
msgstr "コンテンツタイプ" msgstr "コンテンツタイプ"
@ -1536,6 +1575,10 @@ msgstr "フラットページ"
msgid "flat pages" msgid "flat pages"
msgstr "フラットページ" msgstr "フラットページ"
#: contrib/localflavor/usa/forms.py:13
msgid "Enter a zip code in the format XXXXX or XXXXX-XXXX."
msgstr "XXXXXか、XXXXX-XXXXの形式で郵便番号を入力してください。"
#: contrib/redirects/models.py:7 #: contrib/redirects/models.py:7
msgid "redirect from" msgid "redirect from"
msgstr "リダイレクト元" msgstr "リダイレクト元"
@ -1600,92 +1643,92 @@ msgstr "サイト"
msgid "sites" msgid "sites"
msgstr "サイト" msgstr "サイト"
#: core/validators.py:63 #: core/validators.py:64
msgid "This value must contain only letters, numbers and underscores." msgid "This value must contain only letters, numbers and underscores."
msgstr "半角の英数字およびアンダースコア以外は使用できません。" msgstr "半角の英数字およびアンダースコア以外は使用できません。"
#: core/validators.py:67 #: core/validators.py:68
msgid "" msgid ""
"This value must contain only letters, numbers, underscores, dashes or " "This value must contain only letters, numbers, underscores, dashes or "
"slashes." "slashes."
msgstr "" msgstr ""
"半角の英数字、アンダースコア、ダッシュ、スラッシュ以外は使用できません。" "半角の英数字、アンダースコア、ダッシュ、スラッシュ以外は使用できません。"
#: core/validators.py:71 #: core/validators.py:72
msgid "This value must contain only letters, numbers, underscores or hyphens." msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr "半角の英数字、アンダースコア、ハイフン以外は使用できません。" msgstr "半角の英数字、アンダースコア、ハイフン以外は使用できません。"
#: core/validators.py:75 #: core/validators.py:76
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."
msgstr "大文字はここでは使用できません。" msgstr "大文字はここでは使用できません。"
#: core/validators.py:79 #: core/validators.py:80
msgid "Lowercase letters are not allowed here." msgid "Lowercase letters are not allowed here."
msgstr "小文字はここでは使用できません。" msgstr "小文字はここでは使用できません。"
#: core/validators.py:86 #: core/validators.py:87
msgid "Enter only digits separated by commas." msgid "Enter only digits separated by commas."
msgstr "カンマ区切りの数字だけを入力してください。" msgstr "カンマ区切りの数字だけを入力してください。"
#: core/validators.py:98 #: core/validators.py:99
msgid "Enter valid e-mail addresses separated by commas." msgid "Enter valid e-mail addresses separated by commas."
msgstr "カンマ区切りの有効なメールアドレスを入力してください。" msgstr "カンマ区切りの有効なメールアドレスを入力してください。"
#: core/validators.py:102 #: core/validators.py:103
msgid "Please enter a valid IP address." msgid "Please enter a valid IP address."
msgstr "有効な IP アドレスを入力してください。" msgstr "有効な IP アドレスを入力してください。"
#: core/validators.py:106 #: core/validators.py:107
msgid "Empty values are not allowed here." msgid "Empty values are not allowed here."
msgstr "入力は必須です。" msgstr "入力は必須です。"
#: core/validators.py:110 #: core/validators.py:111
msgid "Non-numeric characters aren't allowed here." msgid "Non-numeric characters aren't allowed here."
msgstr "数値以外は使用できません。" msgstr "数値以外は使用できません。"
#: core/validators.py:114 #: core/validators.py:115
msgid "This value can't be comprised solely of digits." msgid "This value can't be comprised solely of digits."
msgstr "数値だけの値にはできません。" msgstr "数値だけの値にはできません。"
#: core/validators.py:119 #: core/validators.py:120 newforms/fields.py:126
msgid "Enter a whole number." msgid "Enter a whole number."
msgstr "整数を入力してください。" msgstr "整数を入力してください。"
#: core/validators.py:123 #: core/validators.py:124
msgid "Only alphabetical characters are allowed here." msgid "Only alphabetical characters are allowed here."
msgstr "半角アルファベット以外使用できません。" msgstr "半角アルファベット以外使用できません。"
#: core/validators.py:138 #: core/validators.py:139
msgid "Year must be 1900 or later." msgid "Year must be 1900 or later."
msgstr "1900年以降を指定してください。" msgstr "1900年以降を指定してください。"
#: core/validators.py:142 #: core/validators.py:143
#, python-format #, python-format
msgid "Invalid date: %s." msgid "Invalid date: %s."
msgstr "無効な日付: %s" msgstr "無効な日付: %s"
#: core/validators.py:146 db/models/fields/__init__.py:424 #: core/validators.py:147 db/models/fields/__init__.py:454
msgid "Enter a valid date in YYYY-MM-DD format." msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "YYYY-MM-DD形式で日付を入力してください。" msgstr "YYYY-MM-DD形式で日付を入力してください。"
#: core/validators.py:151 #: core/validators.py:152
msgid "Enter a valid time in HH:MM format." msgid "Enter a valid time in HH:MM format."
msgstr "HH:MM形式で時刻を入力してください。" msgstr "HH:MM形式で時刻を入力してください。"
#: core/validators.py:155 db/models/fields/__init__.py:486 #: core/validators.py:156 db/models/fields/__init__.py:521
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "YYYY-MM-DD HH:MM形式で日時を入力してください。" msgstr "YYYY-MM-DD HH:MM形式で日時を入力してください。"
#: core/validators.py:160 #: core/validators.py:161 newforms/fields.py:269
msgid "Enter a valid e-mail address." msgid "Enter a valid e-mail address."
msgstr "有効なメールアドレスを入力してください。" msgstr "有効なメールアドレスを入力してください。"
#: core/validators.py:172 core/validators.py:401 forms/__init__.py:662 #: core/validators.py:173 core/validators.py:442 oldforms/__init__.py:667
msgid "No file was submitted. Check the encoding type on the form." msgid "No file was submitted. Check the encoding type on the form."
msgstr "" msgstr ""
"ファイルが取得できませんでした。formのencoding typeを確認してください。" "ファイルが取得できませんでした。formのencoding typeを確認してください。"
#: core/validators.py:176 #: core/validators.py:177
msgid "" msgid ""
"Upload a valid image. The file you uploaded was either not an image or a " "Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image." "corrupted image."
@ -1693,26 +1736,26 @@ msgstr ""
"画像をアップロードしてください。アップロードした画像は画像でないか、または壊" "画像をアップロードしてください。アップロードした画像は画像でないか、または壊"
"れています。" "れています。"
#: core/validators.py:183 #: core/validators.py:184
#, python-format #, python-format
msgid "The URL %s does not point to a valid image." msgid "The URL %s does not point to a valid image."
msgstr "URL ( %s ) は画像ではありません。" msgstr "URL ( %s ) は画像ではありません。"
#: core/validators.py:187 #: core/validators.py:188
#, python-format #, python-format
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
msgstr "電話番号は XXX-XXX-XXXX 形式で入力してください。\"%s\" は無効です。" msgstr "電話番号は XXX-XXX-XXXX 形式で入力してください。\"%s\" は無効です。"
#: core/validators.py:195 #: core/validators.py:196
#, python-format #, python-format
msgid "The URL %s does not point to a valid QuickTime video." msgid "The URL %s does not point to a valid QuickTime video."
msgstr "URL ( %s ) は QuickTime ビデオではありません。" msgstr "URL ( %s ) は QuickTime ビデオではありません。"
#: core/validators.py:199 #: core/validators.py:200
msgid "A valid URL is required." msgid "A valid URL is required."
msgstr "正しい URL を入力してください。" msgstr "正しい URL を入力してください。"
#: core/validators.py:213 #: core/validators.py:214
#, python-format #, python-format
msgid "" msgid ""
"Valid HTML is required. Specific errors are:\n" "Valid HTML is required. Specific errors are:\n"
@ -1721,71 +1764,86 @@ msgstr ""
"有効な HTML を入力してください。エラー:\n" "有効な HTML を入力してください。エラー:\n"
"%s" "%s"
#: core/validators.py:220 #: core/validators.py:221
#, python-format #, python-format
msgid "Badly formed XML: %s" msgid "Badly formed XML: %s"
msgstr "不正な XML です: %s" msgstr "不正な XML です: %s"
#: core/validators.py:230 #: core/validators.py:238
#, python-format #, python-format
msgid "Invalid URL: %s" msgid "Invalid URL: %s"
msgstr "無効なURL: %s" msgstr "無効なURL: %s"
#: core/validators.py:234 core/validators.py:236 #: core/validators.py:243 core/validators.py:245
#, python-format #, python-format
msgid "The URL %s is a broken link." msgid "The URL %s is a broken link."
msgstr "URL ( %s ) はリンクが壊れています。" msgstr "URL ( %s ) はリンクが壊れています。"
#: core/validators.py:242 #: core/validators.py:251
msgid "Enter a valid U.S. state abbreviation." msgid "Enter a valid U.S. state abbreviation."
msgstr "正しい米州略称を入力してください。" msgstr "正しい米州略称を入力してください。"
#: core/validators.py:256 #: core/validators.py:265
#, python-format #, python-format
msgid "Watch your mouth! The word %s is not allowed here." msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "言葉使いに気を付けて! %s という言葉は使えません。" msgstr[0] "言葉使いに気を付けて! %s という言葉は使えません。"
msgstr[1] "言葉使いに気を付けて! %s という言葉は使えません。" msgstr[1] "言葉使いに気を付けて! %s という言葉は使えません。"
#: core/validators.py:263 #: core/validators.py:272
#, python-format #, python-format
msgid "This field must match the '%s' field." msgid "This field must match the '%s' field."
msgstr "このフィールドは '%s' フィールドと一致せねばなりません。" msgstr "このフィールドは '%s' フィールドと一致せねばなりません。"
#: core/validators.py:282 #: core/validators.py:291
msgid "Please enter something for at least one field." msgid "Please enter something for at least one field."
msgstr "少なくとも一つのフィールドに何か入力してください。" msgstr "少なくとも一つのフィールドに何か入力してください。"
#: core/validators.py:291 core/validators.py:302 #: core/validators.py:300 core/validators.py:311
msgid "Please enter both fields or leave them both empty." msgid "Please enter both fields or leave them both empty."
msgstr "両方のフィールドに入力するか、両方とも未入力にしてください。" msgstr "両方のフィールドに入力するか、両方とも未入力にしてください。"
#: core/validators.py:309 #: core/validators.py:318
#, python-format #, python-format
msgid "This field must be given if %(field)s is %(value)s" msgid "This field must be given if %(field)s is %(value)s"
msgstr "" msgstr ""
"%(field)s を %(value)s にするのなら、このフィールドに必ず入力してください。" "%(field)s を %(value)s にするのなら、このフィールドに必ず入力してください。"
#: core/validators.py:321 #: core/validators.py:330
#, python-format #, python-format
msgid "This field must be given if %(field)s is not %(value)s" msgid "This field must be given if %(field)s is not %(value)s"
msgstr "" msgstr ""
"%(field)s を %(value)s にしないのなら、このフィールドに必ず入力してください。" "%(field)s を %(value)s にしないのなら、このフィールドに必ず入力してください。"
#: core/validators.py:340 #: core/validators.py:349
msgid "Duplicate values are not allowed." msgid "Duplicate values are not allowed."
msgstr "重複する値は認められません。" msgstr "重複する値は認められません。"
#: core/validators.py:363 #: core/validators.py:364
#, python-format
msgid "This value must be between %s and %s."
msgstr "この値は %s から %s の間でなければなりません。"
#: core/validators.py:366
#, python-format
msgid "This value must be at least %s."
msgstr "この値は %s 以上でなければなりません。"
#: core/validators.py:368
#, python-format
msgid "This value must be no more than %s."
msgstr "この値は %s より小さくなければなりません。"
#: core/validators.py:404
#, python-format #, python-format
msgid "This value must be a power of %s." msgid "This value must be a power of %s."
msgstr "この値は %s の累乗でなければなりません。" msgstr "この値は %s の累乗でなければなりません。"
#: core/validators.py:374 #: core/validators.py:415
msgid "Please enter a valid decimal number." msgid "Please enter a valid decimal number."
msgstr "有効な 10 進数を入力してください。" msgstr "有効な 10 進数を入力してください。"
#: core/validators.py:378 #: core/validators.py:419
#, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s total digit." msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "" msgid_plural ""
@ -1793,7 +1851,7 @@ msgid_plural ""
msgstr[0] "全体で %s 文字以下の数字を入力してください。" msgstr[0] "全体で %s 文字以下の数字を入力してください。"
msgstr[1] "全体で %s 文字以下の数字を入力してください。" msgstr[1] "全体で %s 文字以下の数字を入力してください。"
#: core/validators.py:381 #: core/validators.py:422
#, python-format #, python-format
msgid "" msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit." "Please enter a valid decimal number with a whole part of at most %s digit."
@ -1802,7 +1860,7 @@ msgid_plural ""
msgstr[0] "整数部は %s 文字以下の数字を入力してください。" msgstr[0] "整数部は %s 文字以下の数字を入力してください。"
msgstr[1] "整数部は %s 文字以下の数字を入力してください。" msgstr[1] "整数部は %s 文字以下の数字を入力してください。"
#: core/validators.py:384 #: core/validators.py:425
#, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s decimal place." msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural "" msgid_plural ""
@ -1810,37 +1868,37 @@ msgid_plural ""
msgstr[0] "小数部は %s 文字以下の数字を入力してください。" msgstr[0] "小数部は %s 文字以下の数字を入力してください。"
msgstr[1] "小数部は %s 文字以下の数字を入力してください。" msgstr[1] "小数部は %s 文字以下の数字を入力してください。"
#: core/validators.py:394 #: core/validators.py:435
#, python-format #, python-format
msgid "Make sure your uploaded file is at least %s bytes big." msgid "Make sure your uploaded file is at least %s bytes big."
msgstr "アップロードするファイルの大きさは %s バイト以上にしてください。" msgstr "アップロードするファイルの大きさは %s バイト以上にしてください。"
#: core/validators.py:395 #: core/validators.py:436
#, python-format #, python-format
msgid "Make sure your uploaded file is at most %s bytes big." msgid "Make sure your uploaded file is at most %s bytes big."
msgstr "アップロードするファイルの大きさは %s 最大バイトまでです。" msgstr "アップロードするファイルの大きさは %s 最大バイトまでです。"
#: core/validators.py:412 #: core/validators.py:453
msgid "The format for this field is wrong." msgid "The format for this field is wrong."
msgstr "フィールドの形式が正しくありません。" msgstr "フィールドの形式が正しくありません。"
#: core/validators.py:427 #: core/validators.py:468
msgid "This field is invalid." msgid "This field is invalid."
msgstr "このフィールドは無効です。" msgstr "このフィールドは無効です。"
#: core/validators.py:463 #: core/validators.py:504
#, python-format #, python-format
msgid "Could not retrieve anything from %s." msgid "Could not retrieve anything from %s."
msgstr "%s から何も検索できませんでした。" msgstr "%s から何も検索できませんでした。"
#: core/validators.py:466 #: core/validators.py:507
#, python-format #, python-format
msgid "" msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "" msgstr ""
"URL %(url)s は無効なコンテンツタイプヘッダ '%(contenttype)s' を返しました。" "URL %(url)s は無効なコンテンツタイプヘッダ '%(contenttype)s' を返しました。"
#: core/validators.py:499 #: core/validators.py:540
#, python-format #, python-format
msgid "" msgid ""
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
@ -1849,7 +1907,7 @@ msgstr ""
"%(line)s 行目から始まる %(tag)s タグを閉じてください (\"%(start)s\" で始まる" "%(line)s 行目から始まる %(tag)s タグを閉じてください (\"%(start)s\" で始まる"
"行です)。" "行です)。"
#: core/validators.py:503 #: core/validators.py:544
#, python-format #, python-format
msgid "" msgid ""
"Some text starting on line %(line)s is not allowed in that context. (Line " "Some text starting on line %(line)s is not allowed in that context. (Line "
@ -1858,7 +1916,7 @@ msgstr ""
"%(line)s 行目から始まるテキストはこのコンテキストでは使えません。 (\"%(start)" "%(line)s 行目から始まるテキストはこのコンテキストでは使えません。 (\"%(start)"
"s\" で始まる行です)。" "s\" で始まる行です)。"
#: core/validators.py:508 #: core/validators.py:549
#, python-format #, python-format
msgid "" msgid ""
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
@ -1867,7 +1925,7 @@ msgstr ""
"%(line)s 行目の \"%(attr)s\" は無効なアトリビュートです (\"%(start)s\" で始ま" "%(line)s 行目の \"%(attr)s\" は無効なアトリビュートです (\"%(start)s\" で始ま"
"る行です)。" "る行です)。"
#: core/validators.py:513 #: core/validators.py:554
#, python-format #, python-format
msgid "" msgid ""
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
@ -1876,7 +1934,7 @@ msgstr ""
"%(line)s 行目の \"<%(tag)s>\" は無効なタグです( \"%(start)s\" で始まる行で" "%(line)s 行目の \"<%(tag)s>\" は無効なタグです( \"%(start)s\" で始まる行で"
"す)。" "す)。"
#: core/validators.py:517 #: core/validators.py:558
#, python-format #, python-format
msgid "" msgid ""
"A tag on line %(line)s is missing one or more required attributes. (Line " "A tag on line %(line)s is missing one or more required attributes. (Line "
@ -1885,7 +1943,7 @@ msgstr ""
"%(line)s 行目のタグは必須アトリビュートが未入力です( \"%(start)s\" で始まる行" "%(line)s 行目のタグは必須アトリビュートが未入力です( \"%(start)s\" で始まる行"
"です)。" "です)。"
#: core/validators.py:522 #: core/validators.py:563
#, python-format #, python-format
msgid "" msgid ""
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
@ -1900,50 +1958,51 @@ msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "" msgstr ""
"%(field)s に入力されたものは、この %(type)s の %(object)s に既に存在します。" "%(field)s に入力されたものは、この %(type)s の %(object)s に既に存在します。"
#: db/models/fields/__init__.py:41 #: db/models/fields/__init__.py:42
#, python-format #, python-format
msgid "%(optname)s with this %(fieldname)s already exists." msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(fieldname)s に %(optname)s は既に存在します。" msgstr "%(fieldname)s に %(optname)s は既に存在します。"
#: db/models/fields/__init__.py:115 db/models/fields/__init__.py:266 #: db/models/fields/__init__.py:116 db/models/fields/__init__.py:273
#: db/models/fields/__init__.py:560 db/models/fields/__init__.py:571 #: db/models/fields/__init__.py:605 db/models/fields/__init__.py:616
#: forms/__init__.py:347 #: newforms/fields.py:78 newforms/fields.py:373 newforms/fields.py:449
#: newforms/fields.py:460 oldforms/__init__.py:352
msgid "This field is required." msgid "This field is required."
msgstr "このフィールドは必須です。" msgstr "このフィールドは必須です。"
#: db/models/fields/__init__.py:349 #: db/models/fields/__init__.py:366
msgid "This value must be an integer." msgid "This value must be an integer."
msgstr "値は整数でなければなりません。" msgstr "値は整数でなければなりません。"
#: db/models/fields/__init__.py:381 #: db/models/fields/__init__.py:401
msgid "This value must be either True or False." msgid "This value must be either True or False."
msgstr "値は真: True または偽: False でなければなりません。" msgstr "値は真: True または偽: False でなければなりません。"
#: db/models/fields/__init__.py:397 #: db/models/fields/__init__.py:422
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "このフィールドには NULL を指定できません。" msgstr "このフィールドには NULL を指定できません。"
#: db/models/fields/__init__.py:580 #: db/models/fields/__init__.py:625
msgid "Enter a valid filename." msgid "Enter a valid filename."
msgstr "正しいファイル名を入力してください。" msgstr "正しいファイル名を入力してください。"
#: db/models/fields/related.py:51 #: db/models/fields/related.py:53
#, python-format #, python-format
msgid "Please enter a valid %s." msgid "Please enter a valid %s."
msgstr "正しい %s を入力してください。" msgstr "正しい %s を入力してください。"
#: db/models/fields/related.py:618 #: db/models/fields/related.py:642
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr "複数の ID はカンマで区切ってください。" msgstr "複数の ID はカンマで区切ってください。"
#: db/models/fields/related.py:620 #: db/models/fields/related.py:644
msgid "" msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "" msgstr ""
"複数選択するときには Control キーを押したまま選択してください。Mac は " "複数選択するときには Control キーを押したまま選択してください。Mac は "
"Command キーを使ってください" "Command キーを使ってください"
#: db/models/fields/related.py:664 #: db/models/fields/related.py:691
#, python-format #, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural "" msgid_plural ""
@ -1951,39 +2010,96 @@ msgid_plural ""
msgstr[0] "正しい %(self)s IDを入力してください。 %(value)r は無効です。" msgstr[0] "正しい %(self)s IDを入力してください。 %(value)r は無効です。"
msgstr[1] "正しい %(self)s IDを入力してください。 %(value)r は無効です。" msgstr[1] "正しい %(self)s IDを入力してください。 %(value)r は無効です。"
#: forms/__init__.py:382 #: newforms/fields.py:101 newforms/fields.py:254
#, python-format
msgid "Ensure this value has at most %d characters."
msgstr "%d 字以下で入力してください。"
#: newforms/fields.py:103 newforms/fields.py:256
#, python-format
msgid "Ensure this value has at least %d characters."
msgstr "%d 字以上で入力してください。"
#: newforms/fields.py:128
#, python-format
msgid "Ensure this value is less than or equal to %s."
msgstr "この値は %s 以下でなければなりません。"
#: newforms/fields.py:130
#, python-format
msgid "Ensure this value is greater than or equal to %s."
msgstr "この値は %s 以上でなければなりません。"
#: newforms/fields.py:163
msgid "Enter a valid date."
msgstr "日付を正しく入力してください。"
#: newforms/fields.py:190
msgid "Enter a valid time."
msgstr "時間を正しく入力してください。"
#: newforms/fields.py:226
msgid "Enter a valid date/time."
msgstr "日付/時間を正しく入力してください。"
#: newforms/fields.py:240
msgid "Enter a valid value."
msgstr "値を正しく入力してください。"
#: newforms/fields.py:287 newforms/fields.py:309
msgid "Enter a valid URL."
msgstr "URLを正しく入力してください。"
#: newforms/fields.py:311
msgid "This URL appears to be a broken link."
msgstr "このURLはリンクが壊れています。"
#: newforms/fields.py:359
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr "正しく選択してください。選択したものは候補にありません。"
#: newforms/fields.py:377 newforms/fields.py:453
msgid "Enter a list of values."
msgstr "リストを入力してください。"
#: newforms/fields.py:386
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
msgstr "正しく選択してください。 %s は候補にありません。"
#: oldforms/__init__.py:387
#, python-format #, python-format
msgid "Ensure your text is less than %s character." msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters." msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "%s 字以下で入力してください。" msgstr[0] "%s 字以下で入力してください。"
msgstr[1] "%s 字以下で入力してください。" msgstr[1] "%s 字以下で入力してください。"
#: forms/__init__.py:387 #: oldforms/__init__.py:392
msgid "Line breaks are not allowed here." msgid "Line breaks are not allowed here."
msgstr "改行はできません。" msgstr "改行はできません。"
#: forms/__init__.py:488 forms/__init__.py:561 forms/__init__.py:600 #: oldforms/__init__.py:493 oldforms/__init__.py:566 oldforms/__init__.py:605
#, python-format #, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "正しく選択してください。; '%(data)s' は %(choices)s にありません。" msgstr "正しく選択してください。; '%(data)s' は %(choices)s にありません。"
#: forms/__init__.py:664 #: oldforms/__init__.py:669
msgid "The submitted file is empty." msgid "The submitted file is empty."
msgstr "入力されたファイルは空です。" msgstr "入力されたファイルは空です。"
#: forms/__init__.py:720 #: oldforms/__init__.py:725
msgid "Enter a whole number between -32,768 and 32,767." msgid "Enter a whole number between -32,768 and 32,767."
msgstr "-32,768 から 32,767 までの整数を入力してください。" msgstr "-32,768 から 32,767 までの整数を入力してください。"
#: forms/__init__.py:730 #: oldforms/__init__.py:735
msgid "Enter a positive number." msgid "Enter a positive number."
msgstr "正の数を入力してください。" msgstr "正の数を入力してください。"
#: forms/__init__.py:740 #: oldforms/__init__.py:745
msgid "Enter a whole number between 0 and 32,767." msgid "Enter a whole number between 0 and 32,767."
msgstr "0 から 32,767 までの整数を入力してください。" msgstr "0 から 32,767 までの整数を入力してください。"
#: template/defaultfilters.py:401 #: template/defaultfilters.py:436
msgid "yes,no,maybe" msgid "yes,no,maybe"
msgstr "はい,いいえ,たぶん" msgstr "はい,いいえ,たぶん"
@ -2209,21 +2325,3 @@ msgstr "%(verbose_name)s を更新しました。"
#, python-format #, python-format
msgid "The %(verbose_name)s was deleted." msgid "The %(verbose_name)s was deleted."
msgstr " %(verbose_name)s を削除しました。" msgstr " %(verbose_name)s を削除しました。"
#~ msgid "String (up to 50)"
#~ msgstr "文字列 (50 字まで)"
#~ msgid "Comment"
#~ msgstr "コメント"
#~ msgid "Comments"
#~ msgstr "コメント"
#~ msgid "label"
#~ msgstr "ラベル"
#~ msgid "package"
#~ msgstr "パッケージ"
#~ msgid "packages"
#~ msgstr "パッケージ"

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,118 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-15 10:46+1100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr ""
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr ""
#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,118 @@
# translation of djangojs.po to Macedonian
#
# Georgi Stanojevski <glisha@gmail.com>, 2006.
msgid ""
msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-15 10:53+1100\n"
"PO-Revision-Date: 2006-12-04 16:18+0100\n"
"Last-Translator: Georgi Stanojevski <glisha@gmail.com>\n"
"Language-Team: Macedonian <ossm-members@hedona.on.net.mk>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
msgid "Available %s"
msgstr "Достапно %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "Избери ги сите"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "Додади"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Отстрани"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "Избрано %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Означете го вашиот избор/и и кликнете"
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Исчисти ги сите"
#: contrib/admin/media/js/dateparse.js:32
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"Јануари Февруари Март Април Мај Јуни Јули Август Септември Октомври Ноември "
"Декември"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Недела Понеделник Вторник Среда Четврток Петок Сабота"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "Н П В С Ч П С"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "Сега"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "Часовник"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "Избери време"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "Полноќ"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "6 наутро"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "Пладне"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Откажи"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "Денеска"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "Календар"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "Вчера"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Утре"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ function URLify(s, num_chars) {
"with"]; "with"];
r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi'); r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
s = s.replace(r, ''); s = s.replace(r, '');
s = s.replace(/[^-A-Z0-9\s]/gi, ''); // remove unneeded chars s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
s = s.toLowerCase(); // convert to lowercase s = s.toLowerCase(); // convert to lowercase

View File

View File

@ -0,0 +1,19 @@
"""
UK-specific Form helpers
"""
from django.newforms.fields import RegexField
from django.utils.translation import gettext
class UKPostcodeField(RegexField):
"""
A form field that validates its input is a UK postcode.
The regular expression used is sourced from the schema for British Standard
BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
"""
def __init__(self, *args, **kwargs):
super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$',
max_length=None, min_length=None,
error_message=gettext(u'Enter a postcode. A space is required between the two postcode parts.'),
*args, **kwargs)

View File

@ -0,0 +1,44 @@
"""
USA-specific Form helpers
"""
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
from django.utils.translation import gettext
class USZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
max_length=None, min_length=None,
error_message=gettext(u'Enter a zip code in the format XXXXX or XXXXX-XXXX.'),
*args, **kwargs)
class USStateField(Field):
"""
A form field that validates its input is a U.S. state name or abbreviation.
It normalizes the input to the standard two-leter postal service
abbreviation for the given state.
"""
def clean(self, value):
from us_states import STATES_NORMALIZED # relative import
super(USStateField, self).clean(value)
if value in EMPTY_VALUES:
return u''
try:
value = value.strip().lower()
except AttributeError:
pass
else:
try:
return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
except KeyError:
pass
raise ValidationError(u'Enter a U.S. state or territory.')
class USStateSelect(Select):
"""
A Select widget that uses a list of U.S. states/territories as its choices.
"""
def __init__(self, attrs=None):
from us_states import STATE_CHOICES # relative import
super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES)

View File

@ -0,0 +1,238 @@
"""
A mapping of state misspellings/abbreviations to normalized abbreviations, and
an alphabetical list of states for use as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
STATE_CHOICES = (
('AL', 'Alabama'),
('AK', 'Alaska'),
('AS', 'American Samoa'),
('AZ', 'Arizona'),
('AR', 'Arkansas'),
('CA', 'California'),
('CO', 'Colorado'),
('CT', 'Connecticut'),
('DE', 'Deleware'),
('DC', 'District of Columbia'),
('FM', 'Federated States of Micronesia'),
('FL', 'Florida'),
('GA', 'Georgia'),
('GU', 'Guam'),
('HI', 'Hawaii'),
('ID', 'Idaho'),
('IL', 'Illinois'),
('IN', 'Indiana'),
('IA', 'Iowa'),
('KS', 'Kansas'),
('KY', 'Kentucky'),
('LA', 'Louisiana'),
('ME', 'Maine'),
('MH', 'Marshall Islands'),
('MD', 'Maryland'),
('MI', 'Michigan'),
('MN', 'Minnesota'),
('MS', 'Mississippi'),
('MO', 'Missouri'),
('MT', 'Montana'),
('NE', 'Nebraska'),
('NV', 'Nevada'),
('NH', 'New Hampshire'),
('NJ', 'New Jersey'),
('NM', 'New Mexico'),
('NY', 'New York'),
('NC', 'North Carolina'),
('ND', 'North Dakota'),
('MP', 'Northern Mariana Islands'),
('OH', 'Ohio'),
('OK', 'Oklahoma'),
('OR', 'Oregon'),
('PW', 'Palau'),
('PA', 'Pennsylvania'),
('PR', 'Puerto Rico'),
('RI', 'Rhode Island'),
('SC', 'South Carolina'),
('SD', 'South Dakota'),
('TN', 'Tennessee'),
('TX', 'Texas'),
('UT', 'Utah'),
('VT', 'Vermont'),
('VI', 'Virgin Islands'),
('VA', 'Virginia'),
('WA', 'Washington'),
('WV', 'West Virginia'),
('WI', 'Wisconsin'),
('WY', 'Wyoming'),
)
STATES_NORMALIZED = {
'ak': 'AK',
'al': 'AL',
'ala': 'AL',
'alabama': 'AL',
'alaska': 'AK',
'american samao': 'AS',
'american samoa': 'AS',
'ar': 'AR',
'ariz': 'AZ',
'arizona': 'AZ',
'ark': 'AR',
'arkansas': 'AR',
'as': 'AS',
'az': 'AZ',
'ca': 'CA',
'calf': 'CA',
'calif': 'CA',
'california': 'CA',
'co': 'CO',
'colo': 'CO',
'colorado': 'CO',
'conn': 'CT',
'connecticut': 'CT',
'ct': 'CT',
'dc': 'DC',
'de': 'DE',
'del': 'DE',
'delaware': 'DE',
'district of columbia': 'DC',
'federated states of micronesia': 'FM',
'fl': 'FL',
'fla': 'FL',
'florida': 'FL',
'fm': 'FM',
'ga': 'GA',
'georgia': 'GA',
'gu': 'GU',
'guam': 'GU',
'hawaii': 'HI',
'hi': 'HI',
'ia': 'IA',
'id': 'ID',
'idaho': 'ID',
'il': 'IL',
'ill': 'IL',
'illinois': 'IL',
'in': 'IN',
'ind': 'IN',
'indiana': 'IN',
'iowa': 'IA',
'kan': 'KS',
'kans': 'KS',
'kansas': 'KS',
'kentucky': 'KY',
'ks': 'KS',
'ky': 'KY',
'la': 'LA',
'louisiana': 'LA',
'ma': 'MA',
'maine': 'ME',
'marianas islands': 'MP',
'marianas islands of the pacific': 'MP',
'marinas islands of the pacific': 'MP',
'maryland': 'MD',
'mass': 'MA',
'massachusetts': 'MA',
'massachussetts': 'MA',
'md': 'MD',
'me': 'ME',
'mi': 'MI',
'mich': 'MI',
'michigan': 'MI',
'micronesia': 'FM',
'minn': 'MN',
'minnesota': 'MN',
'miss': 'MS',
'mississippi': 'MS',
'missouri': 'MO',
'mn': 'MN',
'mo': 'MO',
'mont': 'MT',
'montana': 'MT',
'mp': 'MP',
'ms': 'MS',
'mt': 'MT',
'n d': 'ND',
'n dak': 'ND',
'n h': 'NH',
'n j': 'NJ',
'n m': 'NM',
'n mex': 'NM',
'nc': 'NC',
'nd': 'ND',
'ne': 'NE',
'neb': 'NE',
'nebr': 'NE',
'nebraska': 'NE',
'nev': 'NV',
'nevada': 'NV',
'new hampshire': 'NH',
'new jersey': 'NJ',
'new mexico': 'NM',
'new york': 'NY',
'nh': 'NH',
'nj': 'NJ',
'nm': 'NM',
'nmex': 'NM',
'north carolina': 'NC',
'north dakota': 'ND',
'northern mariana islands': 'MP',
'nv': 'NV',
'ny': 'NY',
'oh': 'OH',
'ohio': 'OH',
'ok': 'OK',
'okla': 'OK',
'oklahoma': 'OK',
'or': 'OR',
'ore': 'OR',
'oreg': 'OR',
'oregon': 'OR',
'pa': 'PA',
'penn': 'PA',
'pennsylvania': 'PA',
'pr': 'PR',
'puerto rico': 'PR',
'rhode island': 'RI',
'ri': 'RI',
's dak': 'SD',
'sc': 'SC',
'sd': 'SD',
'sdak': 'SD',
'south carolina': 'SC',
'south dakota': 'SD',
'tenn': 'TN',
'tennessee': 'TN',
'territory of hawaii': 'HI',
'tex': 'TX',
'texas': 'TX',
'tn': 'TN',
'tx': 'TX',
'us virgin islands': 'VI',
'usvi': 'VI',
'ut': 'UT',
'utah': 'UT',
'va': 'VA',
'vermont': 'VT',
'vi': 'VI',
'viginia': 'VA',
'virgin islands': 'VI',
'virgina': 'VA',
'virginia': 'VA',
'vt': 'VT',
'w va': 'WV',
'wa': 'WA',
'wash': 'WA',
'washington': 'WA',
'west virginia': 'WV',
'wi': 'WI',
'wis': 'WI',
'wisc': 'WI',
'wisconsin': 'WI',
'wv': 'WV',
'wva': 'WV',
'wy': 'WY',
'wyo': 'WY',
'wyoming': 'WY',
}

View File

@ -8,7 +8,18 @@ import socket
import time import time
import random import random
DNS_NAME = socket.getfqdn() # Cache the hostname # Cache the hostname, but do it lazily: socket.getfqdn() can take a couple of
# seconds, which slows down the restart of the server.
class CachedDnsName(object):
def __str__(self):
return self.get_fqdn()
def get_fqdn(self):
if not hasattr(self, '_fqdn'):
self._fqdn = socket.getfqdn()
return self._fqdn
DNS_NAME = CachedDnsName()
class BadHeaderError(ValueError): class BadHeaderError(ValueError):
pass pass

View File

@ -1177,6 +1177,11 @@ createcachetable.args = "[tablename]"
def run_shell(use_plain=False): def run_shell(use_plain=False):
"Runs a Python interactive interpreter. Tries to use IPython, if it's available." "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
# XXX: (Temporary) workaround for ticket #1796: force early loading of all
# models from installed apps.
from django.db.models.loading import get_models
loaded_models = get_models()
try: try:
if use_plain: if use_plain:
# Don't bother loading IPython, because the user wants plain Python. # Don't bother loading IPython, because the user wants plain Python.

View File

@ -161,7 +161,7 @@ class Field(object):
def get_db_prep_lookup(self, lookup_type, value): def get_db_prep_lookup(self, lookup_type, value):
"Returns field's value prepared for database lookup." "Returns field's value prepared for database lookup."
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'year', 'month', 'day', 'search'): if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):
return [value] return [value]
elif lookup_type in ('range', 'in'): elif lookup_type in ('range', 'in'):
return value return value
@ -175,7 +175,13 @@ class Field(object):
return ["%%%s" % prep_for_like_query(value)] return ["%%%s" % prep_for_like_query(value)]
elif lookup_type == 'isnull': elif lookup_type == 'isnull':
return [] return []
raise TypeError, "Field has invalid lookup: %s" % lookup_type elif lookup_type == 'year':
try:
value = int(value)
except ValueError:
raise ValueError("The __year lookup type requires an integer argument")
return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value]
raise TypeError("Field has invalid lookup: %s" % lookup_type)
def has_default(self): def has_default(self):
"Returns a boolean of whether this field has a default value." "Returns a boolean of whether this field has a default value."

View File

@ -198,17 +198,17 @@ class QuerySet(object):
counter = self._clone() counter = self._clone()
counter._order_by = () counter._order_by = ()
counter._select_related = False counter._select_related = False
offset = counter._offset offset = counter._offset
limit = counter._limit limit = counter._limit
counter._offset = None counter._offset = None
counter._limit = None counter._limit = None
try: try:
select, sql, params = counter._get_sql_clause() select, sql, params = counter._get_sql_clause()
except EmptyResultSet: except EmptyResultSet:
return 0 return 0
cursor = connection.cursor() cursor = connection.cursor()
if self._distinct: if self._distinct:
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
@ -553,7 +553,7 @@ class ValuesQuerySet(QuerySet):
else: # Default to all fields. else: # Default to all fields.
columns = [f.column for f in self.model._meta.fields] columns = [f.column for f in self.model._meta.fields]
field_names = [f.attname for f in self.model._meta.fields] field_names = [f.attname for f in self.model._meta.fields]
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
@ -576,12 +576,12 @@ class DateQuerySet(QuerySet):
if self._field.null: if self._field.null:
self._where.append('%s.%s IS NOT NULL' % \ self._where.append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column))) (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
try: try:
select, sql, params = self._get_sql_clause() select, sql, params = self._get_sql_clause()
except EmptyResultSet: except EmptyResultSet:
raise StopIteration raise StopIteration
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \ sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
(backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
backend.quote_name(self._field.column))), sql, self._order) backend.quote_name(self._field.column))), sql, self._order)
@ -598,15 +598,15 @@ class DateQuerySet(QuerySet):
c._kind = self._kind c._kind = self._kind
c._order = self._order c._order = self._order
return c return c
class EmptyQuerySet(QuerySet): class EmptyQuerySet(QuerySet):
def __init__(self, model=None): def __init__(self, model=None):
super(EmptyQuerySet, self).__init__(model) super(EmptyQuerySet, self).__init__(model)
self._result_cache = [] self._result_cache = []
def count(self): def count(self):
return 0 return 0
def delete(self): def delete(self):
pass pass
@ -708,9 +708,9 @@ def get_where_clause(lookup_type, table_prefix, field_name, value):
return '%s%s IN (%s)' % (table_prefix, field_name, in_string) return '%s%s IN (%s)' % (table_prefix, field_name, in_string)
else: else:
raise EmptyResultSet raise EmptyResultSet
elif lookup_type == 'range': elif lookup_type in ('range', 'year'):
return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name) return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name)
elif lookup_type in ('year', 'month', 'day'): elif lookup_type in ('month', 'day'):
return "%s = %%s" % backend.get_date_extract_sql(lookup_type, table_prefix + field_name) return "%s = %%s" % backend.get_date_extract_sql(lookup_type, table_prefix + field_name)
elif lookup_type == 'isnull': elif lookup_type == 'isnull':
return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or '')) return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or ''))
@ -791,7 +791,7 @@ def parse_lookup(kwarg_items, opts):
if len(path) < 1: if len(path) < 1:
raise TypeError, "Cannot parse keyword query %r" % kwarg raise TypeError, "Cannot parse keyword query %r" % kwarg
if value is None: if value is None:
# Interpret '__exact=None' as the sql '= NULL'; otherwise, reject # Interpret '__exact=None' as the sql '= NULL'; otherwise, reject
# all uses of None as a query value. # all uses of None as a query value.
@ -1007,7 +1007,7 @@ def delete_objects(seen_objs):
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
for f in cls._meta.many_to_many: for f in cls._meta.many_to_many:
if isinstance(f, GenericRelation): if isinstance(f, GenericRelation):
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column
args_extra = [ContentType.objects.get_for_model(cls).id] args_extra = [ContentType.objects.get_for_model(cls).id]
else: else:

View File

@ -104,12 +104,12 @@ class RelatedObject(object):
attr = getattr(manipulator.original_object, self.get_accessor_name()) attr = getattr(manipulator.original_object, self.get_accessor_name())
count = attr.count() count = attr.count()
count += self.field.rel.num_extra_on_change count += self.field.rel.num_extra_on_change
if self.field.rel.min_num_in_admin:
count = max(count, self.field.rel.min_num_in_admin)
if self.field.rel.max_num_in_admin:
count = min(count, self.field.rel.max_num_in_admin)
else: else:
count = self.field.rel.num_in_admin count = self.field.rel.num_in_admin
if self.field.rel.min_num_in_admin:
count = max(count, self.field.rel.min_num_in_admin)
if self.field.rel.max_num_in_admin:
count = min(count, self.field.rel.max_num_in_admin)
else: else:
count = 1 count = 1

View File

@ -51,7 +51,7 @@ class Field(object):
if label is not None: if label is not None:
label = smart_unicode(label) label = smart_unicode(label)
self.required, self.label, self.initial = required, label, initial self.required, self.label, self.initial = required, label, initial
self.help_text = help_text self.help_text = smart_unicode(help_text or '')
widget = widget or self.widget widget = widget or self.widget
if isinstance(widget, type): if isinstance(widget, type):
widget = widget() widget = widget()

View File

@ -7,6 +7,7 @@ from django.utils.html import escape
from fields import Field from fields import Field
from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput
from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError
import copy
__all__ = ('BaseForm', 'Form') __all__ = ('BaseForm', 'Form')
@ -27,13 +28,24 @@ class SortedDictFromList(SortedDict):
dict.__init__(self, dict(data)) dict.__init__(self, dict(data))
def copy(self): def copy(self):
return SortedDictFromList(self.items()) return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
class DeclarativeFieldsMetaclass(type): class DeclarativeFieldsMetaclass(type):
"Metaclass that converts Field attributes to a dictionary called 'base_fields'." """
Metaclass that converts Field attributes to a dictionary called
'base_fields', taking into account parent class 'base_fields' as well.
"""
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
# If this class is subclassing another Form, add that Form's fields.
# Note that we loop over the bases in *reverse*. This is necessary in
# order to preserve the correct order of fields.
for base in bases[::-1]:
if hasattr(base, 'base_fields'):
fields = base.base_fields.items() + fields
attrs['base_fields'] = SortedDictFromList(fields) attrs['base_fields'] = SortedDictFromList(fields)
return type.__new__(cls, name, bases, attrs) return type.__new__(cls, name, bases, attrs)
@ -49,6 +61,7 @@ class BaseForm(StrAndUnicode):
self.prefix = prefix self.prefix = prefix
self.initial = initial or {} self.initial = initial or {}
self.__errors = None # Stores the errors after clean() has been called. self.__errors = None # Stores the errors after clean() has been called.
# The base_fields class attribute is the *class-wide* definition of # The base_fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to # fields. Because a particular *instance* of the class might want to
# alter self.fields, we create self.fields here by copying base_fields. # alter self.fields, we create self.fields here by copying base_fields.
@ -100,7 +113,7 @@ class BaseForm(StrAndUnicode):
output, hidden_fields = [], [] output, hidden_fields = [], []
for name, field in self.fields.items(): for name, field in self.fields.items():
bf = BoundField(self, field, name) bf = BoundField(self, field, name)
bf_errors = bf.errors # Cache in local variable. bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
if bf.is_hidden: if bf.is_hidden:
if bf_errors: if bf_errors:
top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors]) top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
@ -205,6 +218,7 @@ class BoundField(StrAndUnicode):
self.label = pretty_name(name) self.label = pretty_name(name)
else: else:
self.label = self.field.label self.label = self.field.label
self.help_text = field.help_text or ''
def __unicode__(self): def __unicode__(self):
"Renders this field as an HTML widget." "Renders this field as an HTML widget."

View File

@ -7,7 +7,10 @@ flatatt = lambda attrs: u''.join([u' %s="%s"' % (k, escape(v)) for k, v in attrs
def smart_unicode(s): def smart_unicode(s):
if not isinstance(s, basestring): if not isinstance(s, basestring):
s = unicode(str(s)) if hasattr(s, '__unicode__'):
s = unicode(s)
else:
s = unicode(str(s), settings.DEFAULT_CHARSET)
elif not isinstance(s, unicode): elif not isinstance(s, unicode):
s = unicode(s, settings.DEFAULT_CHARSET) s = unicode(s, settings.DEFAULT_CHARSET)
return s return s

View File

@ -81,6 +81,14 @@ class TextInput(Input):
class PasswordInput(Input): class PasswordInput(Input):
input_type = 'password' input_type = 'password'
def __init__(self, attrs=None, render_value=True):
self.attrs = attrs or {}
self.render_value = render_value
def render(self, name, value, attrs=None):
if not self.render_value: value=None
return super(PasswordInput, self).render(name, value, attrs)
class HiddenInput(Input): class HiddenInput(Input):
input_type = 'hidden' input_type = 'hidden'
is_hidden = True is_hidden = True

View File

@ -1,5 +1,6 @@
import sys import sys
from cStringIO import StringIO from cStringIO import StringIO
from urlparse import urlparse
from django.conf import settings from django.conf import settings
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.wsgi import WSGIRequest
@ -9,6 +10,9 @@ from django.http import urlencode, SimpleCookie
from django.test import signals from django.test import signals
from django.utils.functional import curry from django.utils.functional import curry
BOUNDARY = 'BoUnDaRyStRiNg'
MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
class ClientHandler(BaseHandler): class ClientHandler(BaseHandler):
""" """
A HTTP Handler that can be used for testing purposes. A HTTP Handler that can be used for testing purposes.
@ -184,19 +188,20 @@ class Client:
return self.request(**r) return self.request(**r)
def post(self, path, data={}, **extra): def post(self, path, data={}, content_type=MULTIPART_CONTENT, **extra):
"Request a response from the server using POST." "Request a response from the server using POST."
BOUNDARY = 'BoUnDaRyStRiNg' if content_type is MULTIPART_CONTENT:
post_data = encode_multipart(BOUNDARY, data)
else:
post_data = data
encoded = encode_multipart(BOUNDARY, data)
stream = StringIO(encoded)
r = { r = {
'CONTENT_LENGTH': len(encoded), 'CONTENT_LENGTH': len(post_data),
'CONTENT_TYPE': 'multipart/form-data; boundary=%s' % BOUNDARY, 'CONTENT_TYPE': content_type,
'PATH_INFO': path, 'PATH_INFO': path,
'REQUEST_METHOD': 'POST', 'REQUEST_METHOD': 'POST',
'wsgi.input': stream, 'wsgi.input': StringIO(post_data),
} }
r.update(extra) r.update(extra)
@ -218,7 +223,7 @@ class Client:
if response.status_code != 302: if response.status_code != 302:
return False return False
login_path, data = response['Location'].split('?') _, _, login_path, _, data, _= urlparse(response['Location'])
next = data.split('=')[1] next = data.split('=')[1]
# Second, GET the login page; required to set up cookies # Second, GET the login page; required to set up cookies
@ -235,7 +240,8 @@ class Client:
response = self.post(login_path, data=form_data, **extra) response = self.post(login_path, data=form_data, **extra)
# Login page should 302 redirect to the originally requested page # Login page should 302 redirect to the originally requested page
if response.status_code != 302 or response['Location'] != path: if (response.status_code != 302 or
urlparse(response['Location'])[2] != path):
return False return False
# Since we are logged in, request the actual page again # Since we are logged in, request the actual page again

View File

@ -1,6 +1,5 @@
import unittest, doctest import unittest, doctest
from django.conf import settings from django.conf import settings
from django.core import management
from django.test.utils import setup_test_environment, teardown_test_environment from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.utils import create_test_db, destroy_test_db from django.test.utils import create_test_db, destroy_test_db
from django.test.testcases import OutputChecker, DocTestRunner from django.test.testcases import OutputChecker, DocTestRunner
@ -78,7 +77,6 @@ def run_tests(module_list, verbosity=1, extra_tests=[]):
old_name = settings.DATABASE_NAME old_name = settings.DATABASE_NAME
create_test_db(verbosity) create_test_db(verbosity)
management.syncdb(verbosity, interactive=False)
unittest.TextTestRunner(verbosity=verbosity).run(suite) unittest.TextTestRunner(verbosity=verbosity).run(suite)
destroy_test_db(old_name, verbosity) destroy_test_db(old_name, verbosity)

View File

@ -1,6 +1,7 @@
import sys, time import sys, time
from django.conf import settings from django.conf import settings
from django.db import connection, transaction, backend from django.db import connection, transaction, backend
from django.core import management
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.test import signals from django.test import signals
from django.template import Template from django.template import Template
@ -84,6 +85,8 @@ def create_test_db(verbosity=1, autoclobber=False):
connection.close() connection.close()
settings.DATABASE_NAME = TEST_DATABASE_NAME settings.DATABASE_NAME = TEST_DATABASE_NAME
management.syncdb(verbosity, interactive=False)
# Get a cursor (even though we don't need one yet). This has # Get a cursor (even though we don't need one yet). This has
# the side effect of initializing the test database. # the side effect of initializing the test database.
cursor = connection.cursor() cursor = connection.cursor()

View File

@ -139,6 +139,15 @@ See the `flatpages documentation`_.
.. _flatpages documentation: ../flatpages/ .. _flatpages documentation: ../flatpages/
localflavor
===========
**New in Django development version**
A collection of various Django snippets that are useful only for a particular
country or culture. For example, ``django.contrib.localflavor.usa.forms``
contains a ``USZipCodeField`` that you can use to validate U.S. zip codes.
markup markup
====== ======

View File

@ -874,8 +874,8 @@ the relationship should work. All are optional:
force Django to add the descriptor for the reverse force Django to add the descriptor for the reverse
relationship, allowing ``ManyToMany`` relationships to be relationship, allowing ``ManyToMany`` relationships to be
non-symmetrical. non-symmetrical.
``db_table`` The name of the table to create for storing the many-to-many ``db_table`` The name of the table to create for storing the many-to-many
data. If this is not provided, Django will assume a default data. If this is not provided, Django will assume a default
name based upon the names of the two tables being joined. name based upon the names of the two tables being joined.
@ -1272,8 +1272,8 @@ A few special cases to note about ``list_display``:
return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)
colored_name.allow_tags = True colored_name.allow_tags = True
* If the string given is a method of the model that returns True or False * If the string given is a method of the model that returns True or False
Django will display a pretty "on" or "off" icon if you give the method a Django will display a pretty "on" or "off" icon if you give the method a
``boolean`` attribute whose value is ``True``. ``boolean`` attribute whose value is ``True``.
Here's a full example model:: Here's a full example model::
@ -1412,7 +1412,7 @@ This should be set to a list of field names that will be searched whenever
somebody submits a search query in that text box. somebody submits a search query in that text box.
These fields should be some kind of text field, such as ``CharField`` or These fields should be some kind of text field, such as ``CharField`` or
``TextField``. You can also perform a related lookup on a ``ForeignKey`` with ``TextField``. You can also perform a related lookup on a ``ForeignKey`` with
the lookup API "follow" notation:: the lookup API "follow" notation::
search_fields = ['foreign_key__related_fieldname'] search_fields = ['foreign_key__related_fieldname']
@ -1721,11 +1721,29 @@ But this template code is good::
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a> <a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
(Yes, we know ``get_absolute_url()`` couples URLs to models, which violates the The ``permalink`` decorator
DRY principle, because URLs are defined both in a URLconf and in the model. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is a rare case in which we've intentionally violated that principle for
the sake of convenience. With that said, we're working on an even cleaner way **New in Django development version.**
of specifying URLs in a more DRY fashion.)
The problem with the way we wrote ``get_absolute_url()`` above is that it
slightly violates the DRY principle: the URL for this object is defined both
in the URLConf file and in the model.
You can further decouple your models from the URLconf using the ``permalink``
decorator. This decorator is passed the view function and any parameters you
would use for accessing this instance directly. Django then works out the
correct full URL path using the URLconf. For example::
from django.db.models import permalink
def get_absolute_url(self):
return ('people.views.details', str(self.id))
get_absolute_url = permalink(get_absolute_url)
In this way, you're tying the model's absolute URL to the view that is used
to display it, without repeating the URL information anywhere. You can still
use the ``get_absolute_url`` method in templates, as before.
Executing custom SQL Executing custom SQL
-------------------- --------------------

View File

@ -51,9 +51,10 @@ too messy. The choice is yours.
Overview Overview
======== ========
As with the ``django.forms`` ("manipulators") system before it, ``django.newforms`` As with the ``django.forms`` ("manipulators") system before it,
is intended to handle HTML form display, validation and redisplay. It's what ``django.newforms`` is intended to handle HTML form display, data processing
you use if you want to perform server-side validation for an HTML form. (validation) and redisplay. It's what you use if you want to perform
server-side validation for an HTML form.
For example, if your Web site has a contact form that visitors can use to For example, if your Web site has a contact form that visitors can use to
send you e-mail, you'd use this library to implement the display of the HTML send you e-mail, you'd use this library to implement the display of the HTML
@ -571,6 +572,46 @@ is a list-like object that is displayed as an HTML ``<ul>`` when printed::
>>> str(f['subject'].errors) >>> str(f['subject'].errors)
'' ''
Subclassing forms
-----------------
If you subclass a custom ``Form`` class, the resulting ``Form`` class will
include all fields of the parent class(es), followed by the fields you define
in the subclass.
In this example, ``ContactFormWithPriority`` contains all the fields from
``ContactForm``, plus an additional field, ``priority``. The ``ContactForm``
fields are ordered first::
>>> class ContactFormWithPriority(ContactForm):
... priority = forms.CharField()
>>> f = ContactFormWithPriority(auto_id=False)
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
<li>Priority: <input type="text" name="priority" /></li>
It's possible to subclass multiple forms, treating forms as "mix-ins." In this
example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm``
(in that order), and its field list includes the fields from the parent
classes::
>>> class PersonForm(Form):
... first_name = CharField()
... last_name = CharField()
>>> class InstrumentForm(Form):
... instrument = CharField()
>>> class BeatleForm(PersonForm, InstrumentForm):
... haircut_type = CharField()
>>> b = BeatleForm(auto_id=False)
>>> print b.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>
Fields Fields
====== ======

View File

@ -432,3 +432,118 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
``HttpResponseServerError`` ``HttpResponseServerError``
Acts just like ``HttpResponse`` but uses a 500 status code. Acts just like ``HttpResponse`` but uses a 500 status code.
Returning errors
================
Returning HTTP error codes in Django is easy. We've already mentioned the
``HttpResponseNotFound``, ``HttpResponseForbidden``,
``HttpResponseServerError``, etc., subclasses; just return an instance of one
of those subclasses instead of a normal ``HttpResponse`` in order to signify
an error. For example::
def my_view(request):
# ...
if foo:
return HttpResponseNotFound('<h1>Page not found</h1>')
else:
return HttpResponse('<h1>Page was found</h1>')
Because 404 errors are by far the most common HTTP error, there's an easier way
to handle those errors.
The Http404 exception
---------------------
When you return an error such as ``HttpResponseNotFound``, you're responsible
for defining the HTML of the resulting error page::
return HttpResponseNotFound('<h1>Page not found</h1>')
For convenience, and because it's a good idea to have a consistent 404 error page
across your site, Django provides an ``Http404`` exception. If you raise
``Http404`` at any point in a view function, Django will catch it and return the
standard error page for your application, along with an HTTP error code 404.
Example usage::
from django.http import Http404
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p})
In order to use the ``Http404`` exception to its fullest, you should create a
template that is displayed when a 404 error is raised. This template should be
called ``404.html`` and located in the top level of your template tree.
Customing error views
---------------------
The 404 (page not found) view
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When you raise an ``Http404`` exception, Django loads a special view devoted
to handling 404 errors. By default, it's the view
``django.views.defaults.page_not_found``, which loads and renders the template
``404.html``.
This means you need to define a ``404.html`` template in your root template
directory. This template will be used for all 404 errors.
This ``page_not_found`` view should suffice for 99% of Web applications, but if
you want to override the 404 view, you can specify ``handler404`` in your
URLconf, like so::
handler404 = 'mysite.views.my_custom_404_view'
Behind the scenes, Django determines the 404 view by looking for ``handler404``.
By default, URLconfs contain the following line::
from django.conf.urls.defaults import *
That takes care of setting ``handler404`` in the current module. As you can see
in ``django/conf/urls/defaults.py``, ``handler404`` is set to
``'django.views.defaults.page_not_found'`` by default.
Three things to note about 404 views:
* The 404 view is also called if Django doesn't find a match after checking
every regular expression in the URLconf.
* If you don't define your own 404 view -- and simply use the default,
which is recommended -- you still have one obligation: To create a
``404.html`` template in the root of your template directory. The default
404 view will use that template for all 404 errors.
* If ``DEBUG`` is set to ``True`` (in your settings module) then your 404
view will never be used, and the traceback will be displayed instead.
The 500 (server error) view
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Similarly, Django executes special-case behavior in the case of runtime errors
in view code. If a view results in an exception, Django will, by default, call
the view ``django.views.defaults.server_error``, which loads and renders the
template ``500.html``.
This means you need to define a ``500.html`` template in your root template
directory. This template will be used for all server errors.
This ``server_error`` view should suffice for 99% of Web applications, but if
you want to override the view, you can specify ``handler500`` in your
URLconf, like so::
handler500 = 'mysite.views.my_custom_error_view'
Behind the scenes, Django determines the error view by looking for ``handler500``.
By default, URLconfs contain the following line::
from django.conf.urls.defaults import *
That takes care of setting ``handler500`` in the current module. As you can see
in ``django/conf/urls/defaults.py``, ``handler500`` is set to
``'django.views.defaults.server_error'`` by default.

View File

@ -92,7 +92,7 @@ Writing unittests
Like doctests, Django's unit tests use a standard library module: unittest_. Like doctests, Django's unit tests use a standard library module: unittest_.
As with doctests, Django's test runner looks for any unit test cases defined As with doctests, Django's test runner looks for any unit test cases defined
in ``models.py``, or in a ``tests.py`` file stored in the application in ``models.py``, or in a ``tests.py`` file stored in the application
directory. directory.
An equivalent unittest test case for the above example would look like:: An equivalent unittest test case for the above example would look like::
@ -111,8 +111,8 @@ An equivalent unittest test case for the above example would look like::
self.assertEquals(self.cat.speak(), 'The cat says "meow"') self.assertEquals(self.cat.speak(), 'The cat says "meow"')
When you `run your tests`_, the test utility will find all the test cases When you `run your tests`_, the test utility will find all the test cases
(that is, subclasses of ``unittest.TestCase``) in ``models.py`` and (that is, subclasses of ``unittest.TestCase``) in ``models.py`` and
``tests.py``, automatically build a test suite out of those test cases, ``tests.py``, automatically build a test suite out of those test cases,
and run that suite. and run that suite.
For more details about ``unittest``, see the `standard library unittest For more details about ``unittest``, see the `standard library unittest
@ -164,12 +164,12 @@ in different circumstances.
Testing Tools Testing Tools
============= =============
To assist in testing various features of your application, Django provides To assist in testing various features of your application, Django provides
tools that can be used to establish tests and test conditions. tools that can be used to establish tests and test conditions.
* `Test Client`_ * `Test Client`_
* Fixtures_ * Fixtures_
Test Client Test Client
----------- -----------
@ -178,23 +178,23 @@ GET and POST requests on a URL, and observe the response that is received.
This allows you to test that the correct view is executed for a given URL, This allows you to test that the correct view is executed for a given URL,
and that the view constructs the correct response. and that the view constructs the correct response.
As the response is generated, the Test Client gathers details on the As the response is generated, the Test Client gathers details on the
Template and Context objects that were used to generate the response. These Template and Context objects that were used to generate the response. These
Templates and Contexts are then provided as part of the response, and can be Templates and Contexts are then provided as part of the response, and can be
used as test conditions. used as test conditions.
.. admonition:: Test Client vs Browser Automation? .. admonition:: Test Client vs Browser Automation?
The Test Client is not intended as a replacement for Twill_, Selenium_, The Test Client is not intended as a replacement for Twill_, Selenium_,
or other browser automation frameworks - it is intended to allow or other browser automation frameworks - it is intended to allow
testing of the contexts and templates produced by a view, testing of the contexts and templates produced by a view,
rather than the HTML rendered to the end-user. rather than the HTML rendered to the end-user.
A comprehensive test suite should use a combination of both: Test Client A comprehensive test suite should use a combination of both: Test Client
tests to establish that the correct view is being called and that tests to establish that the correct view is being called and that
the view is collecting the correct context data, and Browser Automation the view is collecting the correct context data, and Browser Automation
tests to check that user interface behaves as expected. tests to check that user interface behaves as expected.
.. _Twill: http://twill.idyll.org/ .. _Twill: http://twill.idyll.org/
.. _Selenium: http://www.openqa.org/selenium/ .. _Selenium: http://www.openqa.org/selenium/
@ -202,7 +202,7 @@ used as test conditions.
Making requests Making requests
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Creating an instance of ``Client`` (``django.test.client.Client``) requires Creating an instance of ``Client`` (``django.test.client.Client``) requires
no arguments at time of construction. Once constructed, the following methods no arguments at time of construction. Once constructed, the following methods
can be invoked on the ``Client`` instance. can be invoked on the ``Client`` instance.
@ -217,23 +217,29 @@ can be invoked on the ``Client`` instance.
http://yoursite.com/customers/details/?name=fred&age=7 http://yoursite.com/customers/details/?name=fred&age=7
``post(path, data={})`` ``post(path, data={}, content_type=MULTIPART_CONTENT)``
Make a POST request on the provided ``path``. The key-value pairs in the Make a POST request on the provided ``path``. If you provide a content type
data dictionary will be used to create the POST data payload. This payload (e.g., ``text/xml`` for an XML payload), the contents of ``data`` will be
will be transmitted with the mimetype ``multipart/form-data``. sent as-is in the POST request, using the content type in the HTTP
``Content-Type`` header.
However submitting files is a special case. To POST a file, you need only
provide the file field name as a key, and a file handle to the file you wish to If you do not provide a value for ``content_type``, the values in
upload as a value. The Test Client will populate the two POST fields (i.e., ``data`` will be transmitted with a content type of ``multipart/form-data``.
``field`` and ``field_file``) required by FileField. For example:: The key-value pairs in the data dictionary will be encoded as a multipart
message and used to create the POST data payload.
Submitting files is a special case. To POST a file, you need only
provide the file field name as a key, and a file handle to the file you wish to
upload as a value. The Test Client will populate the two POST fields (i.e.,
``field`` and ``field_file``) required by Django's FileField. For example::
c = Client() c = Client()
f = open('wishlist.doc') f = open('wishlist.doc')
c.post('/customers/wishes/', {'name':'fred', 'attachment':f}) c.post('/customers/wishes/', {'name':'fred', 'attachment':f})
f.close() f.close()
will result in the evaluation of a POST request on ``/customers/wishes/``, will result in the evaluation of a POST request on ``/customers/wishes/``,
with a POST dictionary that contains `name`, `attachment` (containing the with a POST dictionary that contains `name`, `attachment` (containing the
file name), and `attachment_file` (containing the file data). Note that you file name), and `attachment_file` (containing the file data). Note that you
need to manually close the file after it has been provided to the POST. need to manually close the file after it has been provided to the POST.
@ -245,48 +251,48 @@ can be invoked on the ``Client`` instance.
call to ``login()`` stimulates the series of GET and POST calls required call to ``login()`` stimulates the series of GET and POST calls required
to log a user into a @login_required protected view. to log a user into a @login_required protected view.
If login is possible, the final return value of ``login()`` is the response If login is possible, the final return value of ``login()`` is the response
that is generated by issuing a GET request on the protected URL. If login that is generated by issuing a GET request on the protected URL. If login
is not possible, ``login()`` returns False. is not possible, ``login()`` returns False.
Note that since the test suite will be executed using the test database, Note that since the test suite will be executed using the test database,
which contains no users by default. As a result, logins for your production which contains no users by default. As a result, logins for your production
site will not work. You will need to create users as part of the test suite site will not work. You will need to create users as part of the test suite
to be able to test logins to your application. to be able to test logins to your application.
Testing Responses Testing Responses
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
The ``get()``, ``post()`` and ``login()`` methods all return a Response The ``get()``, ``post()`` and ``login()`` methods all return a Response
object. This Response object has the following properties that can be used object. This Response object has the following properties that can be used
for testing purposes: for testing purposes:
=============== ========================================================== =============== ==========================================================
Property Description Property Description
=============== ========================================================== =============== ==========================================================
``status_code`` The HTTP status of the response. See RFC2616_ for a ``status_code`` The HTTP status of the response. See RFC2616_ for a
full list of HTTP status codes. full list of HTTP status codes.
``content`` The body of the response. The is the final page ``content`` The body of the response. The is the final page
content as rendered by the view, or any error message content as rendered by the view, or any error message
(such as the URL for a 302 redirect). (such as the URL for a 302 redirect).
``template`` The Template instance that was used to render the final ``template`` The Template instance that was used to render the final
content. Testing ``template.name`` can be particularly content. Testing ``template.name`` can be particularly
useful; if the template was loaded from a file, useful; if the template was loaded from a file,
``template.name`` will be the file name that was loaded. ``template.name`` will be the file name that was loaded.
If multiple templates were rendered, (e.g., if one If multiple templates were rendered, (e.g., if one
template includes another template),``template`` will template includes another template),``template`` will
be a list of Template objects, in the order in which be a list of Template objects, in the order in which
they were rendered. they were rendered.
``context`` The Context that was used to render the template that ``context`` The Context that was used to render the template that
produced the response content. produced the response content.
As with ``template``, if multiple templates were rendered As with ``template``, if multiple templates were rendered
``context`` will be a list of Context objects, stored in ``context`` will be a list of Context objects, stored in
the order in which they were rendered. the order in which they were rendered.
=============== ========================================================== =============== ==========================================================
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
@ -295,11 +301,11 @@ Exceptions
~~~~~~~~~~ ~~~~~~~~~~
If you point the Test Client at a view that raises an exception, that exception If you point the Test Client at a view that raises an exception, that exception
will be visible in the test case. You can then use a standard ``try...catch`` will be visible in the test case. You can then use a standard ``try...catch``
block, or ``unittest.TestCase.assertRaises()`` to test for exceptions. block, or ``unittest.TestCase.assertRaises()`` to test for exceptions.
The only exceptions that are not visible in a Test Case are ``Http404``, The only exceptions that are not visible in a Test Case are ``Http404``,
``PermissionDenied`` and ``SystemExit``. Django catches these exceptions ``PermissionDenied`` and ``SystemExit``. Django catches these exceptions
internally and converts them into the appropriate HTTP responses codes. internally and converts them into the appropriate HTTP responses codes.
Persistent state Persistent state
@ -307,8 +313,8 @@ Persistent state
The Test Client is stateful; if a cookie is returned as part of a response, The Test Client is stateful; if a cookie is returned as part of a response,
that cookie is provided as part of the next request issued by that Client that cookie is provided as part of the next request issued by that Client
instance. Expiry policies for these cookies are not followed; if you want instance. Expiry policies for these cookies are not followed; if you want
a cookie to expire, either delete it manually or create a new Client a cookie to expire, either delete it manually or create a new Client
instance (which will effectively delete all cookies). instance (which will effectively delete all cookies).
There are two properties of the Test Client which are used to store persistent There are two properties of the Test Client which are used to store persistent
@ -323,25 +329,26 @@ part of a test condition.
``session`` A dictionary-like object containing session information. ``session`` A dictionary-like object containing session information.
See the `session documentation`_ for full details. See the `session documentation`_ for full details.
=============== ==========================================================
.. _`session documentation`: ../sessions/ .. _`session documentation`: ../sessions/
Example Example
~~~~~~~ ~~~~~~~
The following is a simple unit test using the Test Client:: The following is a simple unit test using the Test Client::
import unittest import unittest
from django.test.client import Client from django.test.client import Client
class SimpleTest(unittest.TestCase): class SimpleTest(unittest.TestCase):
def setUp(self): def setUp(self):
# Every test needs a client # Every test needs a client
self.client = Client() self.client = Client()
def test_details(self): def test_details(self):
# Issue a GET request # Issue a GET request
response = self.client.get('/customer/details/') response = self.client.get('/customer/details/')
# Check that the respose is 200 OK # Check that the respose is 200 OK
self.failUnlessEqual(response.status_code, 200) self.failUnlessEqual(response.status_code, 200)
# Check that the rendered context contains 5 customers # Check that the rendered context contains 5 customers
@ -368,13 +375,13 @@ but you only want to run the animals unit tests, run::
When you run your tests, you'll see a bunch of text flow by as the test When you run your tests, you'll see a bunch of text flow by as the test
database is created and models are initialized. This test database is database is created and models are initialized. This test database is
created from scratch every time you run your tests. created from scratch every time you run your tests.
By default, the test database gets its name by prepending ``test_`` to By default, the test database gets its name by prepending ``test_`` to
the database name specified by the ``DATABASE_NAME`` setting; all other the database name specified by the ``DATABASE_NAME`` setting; all other
database settings will the same as they would be for the project normally. database settings will the same as they would be for the project normally.
If you wish to use a name other than the default for the test database, If you wish to use a name other than the default for the test database,
you can use the ``TEST_DATABASE_NAME`` setting to provide a name. you can use the ``TEST_DATABASE_NAME`` setting to provide a name.
Once the test database has been established, Django will run your tests. Once the test database has been established, Django will run your tests.
If everything goes well, at the end you'll see:: If everything goes well, at the end you'll see::
@ -447,7 +454,7 @@ arguments:
The module list is the list of Python modules that contain the models to be The module list is the list of Python modules that contain the models to be
tested. This is the same format returned by ``django.db.models.get_apps()`` tested. This is the same format returned by ``django.db.models.get_apps()``
Verbosity determines the amount of notification and debug information that Verbosity determines the amount of notification and debug information that
will be printed to the console; `0` is no output, `1` is normal output, will be printed to the console; `0` is no output, `1` is normal output,
and `2` is verbose output. and `2` is verbose output.
@ -458,12 +465,12 @@ To assist in the creation of your own test runner, Django provides
a number of utility methods in the ``django.test.utils`` module. a number of utility methods in the ``django.test.utils`` module.
``setup_test_environment()`` ``setup_test_environment()``
Performs any global pre-test setup, such as the installing the Performs any global pre-test setup, such as the installing the
instrumentation of the template rendering system. instrumentation of the template rendering system.
``teardown_test_environment()`` ``teardown_test_environment()``
Performs any global post-test teardown, such as removing the instrumentation Performs any global post-test teardown, such as removing the instrumentation
of the template rendering system. of the template rendering system.
``create_test_db(verbosity=1, autoclobber=False)`` ``create_test_db(verbosity=1, autoclobber=False)``
Creates a new test database, and run ``syncdb`` against it. Creates a new test database, and run ``syncdb`` against it.

View File

@ -12,7 +12,7 @@ class Article(models.Model):
class Meta: class Meta:
ordering = ('pub_date','headline') ordering = ('pub_date','headline')
def __str__(self): def __str__(self):
return self.headline return self.headline
@ -319,7 +319,6 @@ AttributeError: Manager isn't accessible via Article instances
>>> Article.objects.filter(id__lte=4).delete() >>> Article.objects.filter(id__lte=4).delete()
>>> Article.objects.all() >>> Article.objects.all()
[<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>] [<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
"""} """}
from django.conf import settings from django.conf import settings
@ -358,4 +357,11 @@ __test__['API_TESTS'] += """
>>> a10 = Article.objects.create(headline="Article 10", pub_date=datetime(2005, 7, 31, 12, 30, 45)) >>> a10 = Article.objects.create(headline="Article 10", pub_date=datetime(2005, 7, 31, 12, 30, 45))
>>> Article.objects.get(headline="Article 10") >>> Article.objects.get(headline="Article 10")
<Article: Article 10> <Article: Article 10>
# Edge-case test: A year lookup should retrieve all objects in the given
year, including Jan. 1 and Dec. 31.
>>> a11 = Article.objects.create(headline='Article 11', pub_date=datetime(2008, 1, 1))
>>> a12 = Article.objects.create(headline='Article 12', pub_date=datetime(2008, 12, 31, 23, 59, 59, 999999))
>>> Article.objects.filter(pub_date__year=2008)
[<Article: Article 11>, <Article: Article 12>]
""" """

View File

@ -43,7 +43,7 @@ class ClientTest(unittest.TestCase):
# Check some response details # Check some response details
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, 'Empty POST Template') self.assertEqual(response.template.name, 'Empty GET Template')
def test_empty_post(self): def test_empty_post(self):
"POST an empty dictionary to a view" "POST an empty dictionary to a view"
@ -53,7 +53,7 @@ class ClientTest(unittest.TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, 'Empty POST Template') self.assertEqual(response.template.name, 'Empty POST Template')
def test_post_view(self): def test_post(self):
"POST some data to a view" "POST some data to a view"
post_data = { post_data = {
'value': 37 'value': 37
@ -66,6 +66,14 @@ class ClientTest(unittest.TestCase):
self.assertEqual(response.template.name, 'POST Template') self.assertEqual(response.template.name, 'POST Template')
self.failUnless('Data received' in response.content) self.failUnless('Data received' in response.content)
def test_raw_post(self):
test_doc = """<?xml version="1.0" encoding="utf-8"?><library><book><title>Blink</title><author>Malcolm Gladwell</author></book></library>"""
response = self.client.post("/test_client/raw_post_view/", test_doc,
content_type="text/xml")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.template.name, "Book template")
self.assertEqual(response.content, "Blink - Malcolm Gladwell")
def test_redirect(self): def test_redirect(self):
"GET a URL that redirects elsewhere" "GET a URL that redirects elsewhere"
response = self.client.get('/test_client/redirect_view/') response = self.client.get('/test_client/redirect_view/')

View File

@ -4,6 +4,7 @@ import views
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^get_view/$', views.get_view), (r'^get_view/$', views.get_view),
(r'^post_view/$', views.post_view), (r'^post_view/$', views.post_view),
(r'^raw_post_view/$', views.raw_post_view),
(r'^redirect_view/$', views.redirect_view), (r'^redirect_view/$', views.redirect_view),
(r'^login_protected_view/$', views.login_protected_view), (r'^login_protected_view/$', views.login_protected_view),
(r'^session_view/$', views.session_view), (r'^session_view/$', views.session_view),

View File

@ -1,3 +1,4 @@
from xml.dom.minidom import parseString
from django.template import Context, Template from django.template import Context, Template
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@ -13,15 +14,34 @@ def post_view(request):
"""A view that expects a POST, and returns a different template depending """A view that expects a POST, and returns a different template depending
on whether any POST data is available on whether any POST data is available
""" """
if request.POST: if request.method == 'POST':
t = Template('Data received: {{ data }} is the value.', name='POST Template') if request.POST:
c = Context({'data': request.POST['value']}) t = Template('Data received: {{ data }} is the value.', name='POST Template')
c = Context({'data': request.POST['value']})
else:
t = Template('Viewing POST page.', name='Empty POST Template')
c = Context()
else: else:
t = Template('Viewing POST page.', name='Empty POST Template') t = Template('Viewing GET page.', name='Empty GET Template')
c = Context() c = Context()
return HttpResponse(t.render(c)) return HttpResponse(t.render(c))
def raw_post_view(request):
"""A view which expects raw XML to be posted and returns content extracted
from the XML"""
if request.method == 'POST':
root = parseString(request.raw_post_data)
first_book = root.firstChild.firstChild
title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
t = Template("{{ title }} - {{ author }}", name="Book template")
c = Context({"title": title, "author": author})
else:
t = Template("GET request.", name="Book GET template")
c = Context()
return HttpResponse(t.render(c))
def redirect_view(request): def redirect_view(request):
"A view that redirects all requests to the GET view" "A view that redirects all requests to the GET view"
return HttpResponseRedirect('/test_client/get_view/') return HttpResponseRedirect('/test_client/get_view/')

View File

@ -72,6 +72,22 @@ u'<input type="password" class="special" name="email" />'
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}) >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />' u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
The render_value argument lets you specify whether the widget should render
its value. You may want to do this for security reasons.
>>> w = PasswordInput(render_value=True)
>>> w.render('email', 'secret')
u'<input type="password" name="email" value="secret" />'
>>> w = PasswordInput(render_value=False)
>>> w.render('email', '')
u'<input type="password" name="email" />'
>>> w.render('email', None)
u'<input type="password" name="email" />'
>>> w.render('email', 'secret')
u'<input type="password" name="email" />'
>>> w = PasswordInput(attrs={'class': 'fun'}, render_value=False)
>>> w.render('email', 'secret')
u'<input type="password" class="fun" name="email" />'
# HiddenInput Widget ############################################################ # HiddenInput Widget ############################################################
>>> w = HiddenInput() >>> w = HiddenInput()
@ -2201,6 +2217,19 @@ returns a list of input.
>>> f.clean_data >>> f.clean_data
{'composers': [u'J', u'P'], 'name': u'Yesterday'} {'composers': [u'J', u'P'], 'name': u'Yesterday'}
Validation errors are HTML-escaped when output as HTML.
>>> class EscapingForm(Form):
... special_name = CharField()
... def clean_special_name(self):
... raise ValidationError("Something's wrong with '%s'" % self.clean_data['special_name'])
>>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
>>> print f
<tr><th>Special name:</th><td><ul class="errorlist"><li>Something&#39;s wrong with &#39;Nothing to escape&#39;</li></ul><input type="text" name="special_name" value="Nothing to escape" /></td></tr>
>>> f = EscapingForm({'special_name': "Should escape < & > and <script>alert('xss')</script>"}, auto_id=False)
>>> print f
<tr><th>Special name:</th><td><ul class="errorlist"><li>Something&#39;s wrong with &#39;Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;&#39;</li></ul><input type="text" name="special_name" value="Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" /></td></tr>
# Validating multiple fields in relation to another ########################### # Validating multiple fields in relation to another ###########################
There are a couple of ways to do multiple-field validation. If you want the There are a couple of ways to do multiple-field validation. If you want the
@ -2334,6 +2363,43 @@ the next.
<tr><th>Field3:</th><td><input type="text" name="field3" /></td></tr> <tr><th>Field3:</th><td><input type="text" name="field3" /></td></tr>
<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr> <tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>
Similarly, changes to field attributes do not persist from one Form instance
to the next.
>>> class Person(Form):
... first_name = CharField(required=False)
... last_name = CharField(required=False)
... def __init__(self, names_required=False, *args, **kwargs):
... super(Person, self).__init__(*args, **kwargs)
... if names_required:
... self.fields['first_name'].required = True
... self.fields['last_name'].required = True
>>> f = Person(names_required=False)
>>> f['first_name'].field.required, f['last_name'].field.required
(False, False)
>>> f = Person(names_required=True)
>>> f['first_name'].field.required, f['last_name'].field.required
(True, True)
>>> f = Person(names_required=False)
>>> f['first_name'].field.required, f['last_name'].field.required
(False, False)
>>> class Person(Form):
... first_name = CharField(max_length=30)
... last_name = CharField(max_length=30)
... def __init__(self, name_max_length=None, *args, **kwargs):
... super(Person, self).__init__(*args, **kwargs)
... if name_max_length:
... self.fields['first_name'].max_length = name_max_length
... self.fields['last_name'].max_length = name_max_length
>>> f = Person(name_max_length=None)
>>> f['first_name'].field.max_length, f['last_name'].field.max_length
(30, 30)
>>> f = Person(name_max_length=20)
>>> f['first_name'].field.max_length, f['last_name'].field.max_length
(20, 20)
>>> f = Person(name_max_length=None)
>>> f['first_name'].field.max_length, f['last_name'].field.max_length
(30, 30)
HiddenInput widgets are displayed differently in the as_table(), as_ul() HiddenInput widgets are displayed differently in the as_table(), as_ul()
and as_p() output of a Form -- their verbose names are not displayed, and a and as_p() output of a Form -- their verbose names are not displayed, and a
separate row is not displayed. They're displayed in the last row of the separate row is not displayed. They're displayed in the last row of the
@ -2645,6 +2711,54 @@ purposes, though.
<li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li> <li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
<li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li> <li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li>
Help text can include arbitrary Unicode characters.
>>> class UserRegistration(Form):
... username = CharField(max_length=10, help_text='ŠĐĆŽćžšđ')
>>> p = UserRegistration(auto_id=False)
>>> p.as_ul()
u'<li>Username: <input type="text" name="username" maxlength="10" /> \u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</li>'
# Subclassing forms ###########################################################
You can subclass a Form to add fields. The resulting form subclass will have
all of the fields of the parent Form, plus whichever fields you define in the
subclass.
>>> class Person(Form):
... first_name = CharField()
... last_name = CharField()
... birthday = DateField()
>>> class Musician(Person):
... instrument = CharField()
>>> p = Person(auto_id=False)
>>> print p.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Birthday: <input type="text" name="birthday" /></li>
>>> m = Musician(auto_id=False)
>>> print m.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Birthday: <input type="text" name="birthday" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
Yes, you can subclass multiple forms. The fields are added in the order in
which the parent classes are listed.
>>> class Person(Form):
... first_name = CharField()
... last_name = CharField()
... birthday = DateField()
>>> class Instrument(Form):
... instrument = CharField()
>>> class Beatle(Person, Instrument):
... haircut_type = CharField()
>>> b = Beatle(auto_id=False)
>>> print b.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Birthday: <input type="text" name="birthday" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>
# Forms with prefixes ######################################################### # Forms with prefixes #########################################################
Sometimes it's necessary to have multiple forms display on the same HTML page, Sometimes it's necessary to have multiple forms display on the same HTML page,
@ -2858,7 +2972,7 @@ VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}
# Some ideas for using templates with forms ################################### # Some ideas for using templates with forms ###################################
>>> class UserRegistration(Form): >>> class UserRegistration(Form):
... username = CharField(max_length=10) ... username = CharField(max_length=10, help_text="Good luck picking a username that doesn't already exist.")
... password1 = CharField(widget=PasswordInput) ... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput)
... def clean(self): ... def clean(self):
@ -2935,6 +3049,24 @@ field an "id" attribute.
<input type="submit" /> <input type="submit" />
</form> </form>
User form.[field].help_text to output a field's help text. If the given field
does not have help text, nothing will be output.
>>> t = Template('''<form action="">
... <p>{{ form.username.label_tag }}: {{ form.username }}<br />{{ form.username.help_text }}</p>
... <p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
... <p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
... <input type="submit" />
... </form>''')
>>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
<form action="">
<p>Username: <input type="text" name="username" maxlength="10" /><br />Good luck picking a username that doesn't already exist.</p>
<p>Password1: <input type="password" name="password1" /></p>
<p>Password2: <input type="password" name="password2" /></p>
<input type="submit" />
</form>
>>> Template('{{ form.password1.help_text }}').render(Context({'form': UserRegistration(auto_id=False)}))
''
The label_tag() method takes an optional attrs argument: a dictionary of HTML The label_tag() method takes an optional attrs argument: a dictionary of HTML
attributes to add to the <label> tag. attributes to add to the <label> tag.
>>> f = UserRegistration(auto_id='id_%s') >>> f = UserRegistration(auto_id='id_%s')
@ -2977,12 +3109,12 @@ the list of errors is empty). You can also use it in {% if %} statements.
<input type="submit" /> <input type="submit" />
</form> </form>
################# ###############
# Extra widgets # # Extra stuff #
################# ###############
The newforms library comes with some extra, higher-level Widget classes that The newforms library comes with some extra, higher-level Field and Widget
demonstrate some of the library's abilities. classes that demonstrate some of the library's abilities.
# SelectDateWidget ############################################################ # SelectDateWidget ############################################################
@ -3111,6 +3243,246 @@ True
<option value="2016">2016</option> <option value="2016">2016</option>
</select> </select>
# USZipCodeField ##############################################################
USZipCodeField validates that the data is either a five-digit U.S. zip code or
a zip+4.
>>> from django.contrib.localflavor.usa.forms import USZipCodeField
>>> f = USZipCodeField()
>>> f.clean('60606')
u'60606'
>>> f.clean(60606)
u'60606'
>>> f.clean('04000')
u'04000'
>>> f.clean('4000')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean('60606-1234')
u'60606-1234'
>>> f.clean('6060-1234')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean('60606-')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f = USZipCodeField(required=False)
>>> f.clean('60606')
u'60606'
>>> f.clean(60606)
u'60606'
>>> f.clean('04000')
u'04000'
>>> f.clean('4000')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean('60606-1234')
u'60606-1234'
>>> f.clean('6060-1234')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean('60606-')
Traceback (most recent call last):
...
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
>>> f.clean(None)
u''
>>> f.clean('')
u''
# USStateField ################################################################
USStateField validates that the data is either an abbreviation or name of a
U.S. state.
>>> from django.contrib.localflavor.usa.forms import USStateField
>>> f = USStateField()
>>> f.clean('il')
u'IL'
>>> f.clean('IL')
u'IL'
>>> f.clean('illinois')
u'IL'
>>> f.clean(' illinois ')
u'IL'
>>> f.clean(60606)
Traceback (most recent call last):
...
ValidationError: [u'Enter a U.S. state or territory.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f = USStateField(required=False)
>>> f.clean('il')
u'IL'
>>> f.clean('IL')
u'IL'
>>> f.clean('illinois')
u'IL'
>>> f.clean(' illinois ')
u'IL'
>>> f.clean(60606)
Traceback (most recent call last):
...
ValidationError: [u'Enter a U.S. state or territory.']
>>> f.clean(None)
u''
>>> f.clean('')
u''
# USStateSelect ###############################################################
USStateSelect is a Select widget that uses a list of U.S. states/territories
as its choices.
>>> from django.contrib.localflavor.usa.forms import USStateSelect
>>> w = USStateSelect()
>>> print w.render('state', 'IL')
<select name="state">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AS">American Samoa</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
<option value="CO">Colorado</option>
<option value="CT">Connecticut</option>
<option value="DE">Deleware</option>
<option value="DC">District of Columbia</option>
<option value="FM">Federated States of Micronesia</option>
<option value="FL">Florida</option>
<option value="GA">Georgia</option>
<option value="GU">Guam</option>
<option value="HI">Hawaii</option>
<option value="ID">Idaho</option>
<option value="IL" selected="selected">Illinois</option>
<option value="IN">Indiana</option>
<option value="IA">Iowa</option>
<option value="KS">Kansas</option>
<option value="KY">Kentucky</option>
<option value="LA">Louisiana</option>
<option value="ME">Maine</option>
<option value="MH">Marshall Islands</option>
<option value="MD">Maryland</option>
<option value="MI">Michigan</option>
<option value="MN">Minnesota</option>
<option value="MS">Mississippi</option>
<option value="MO">Missouri</option>
<option value="MT">Montana</option>
<option value="NE">Nebraska</option>
<option value="NV">Nevada</option>
<option value="NH">New Hampshire</option>
<option value="NJ">New Jersey</option>
<option value="NM">New Mexico</option>
<option value="NY">New York</option>
<option value="NC">North Carolina</option>
<option value="ND">North Dakota</option>
<option value="MP">Northern Mariana Islands</option>
<option value="OH">Ohio</option>
<option value="OK">Oklahoma</option>
<option value="OR">Oregon</option>
<option value="PW">Palau</option>
<option value="PA">Pennsylvania</option>
<option value="PR">Puerto Rico</option>
<option value="RI">Rhode Island</option>
<option value="SC">South Carolina</option>
<option value="SD">South Dakota</option>
<option value="TN">Tennessee</option>
<option value="TX">Texas</option>
<option value="UT">Utah</option>
<option value="VT">Vermont</option>
<option value="VI">Virgin Islands</option>
<option value="VA">Virginia</option>
<option value="WA">Washington</option>
<option value="WV">West Virginia</option>
<option value="WI">Wisconsin</option>
<option value="WY">Wyoming</option>
</select>
# UKPostcodeField #############################################################
UKPostcodeField validates that the data is a valid UK postcode.
>>> from django.contrib.localflavor.uk.forms import UKPostcodeField
>>> f = UKPostcodeField()
>>> f.clean('BT32 4PX')
u'BT32 4PX'
>>> f.clean('GIR 0AA')
u'GIR 0AA'
>>> f.clean('BT324PX')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean('1NV 4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f = UKPostcodeField(required=False)
>>> f.clean('BT32 4PX')
u'BT32 4PX'
>>> f.clean('GIR 0AA')
u'GIR 0AA'
>>> f.clean('1NV 4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean('BT324PX')
Traceback (most recent call last):
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean(None)
u''
>>> f.clean('')
u''
#################################
# Tests of underlying functions #
#################################
# smart_unicode tests
>>> from django.newforms.util import smart_unicode
>>> class Test:
... def __str__(self):
... return 'ŠĐĆŽćžšđ'
>>> class TestU:
... def __str__(self):
... return 'Foo'
... def __unicode__(self):
... return u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
>>> smart_unicode(Test())
u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
>>> smart_unicode(TestU())
u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
>>> smart_unicode(1)
u'1'
>>> smart_unicode('foo')
u'foo'
""" """
if __name__ == "__main__": if __name__ == "__main__":