mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
[multi-db] Merged trunk to 3950. Some tests still failing.
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@4155 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
2a58209ff2
commit
040f2272e0
7
AUTHORS
7
AUTHORS
@ -83,6 +83,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Simon Greenhill <dev@simon.net.nz>
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
Brant Harris
|
||||
Hawkeye
|
||||
heckj@mac.com
|
||||
Joel Heenan <joelh-django@planetjoel.com>
|
||||
hipertracker@gmail.com
|
||||
@ -98,23 +99,26 @@ answer newbie questions, and generally made Django that much better:
|
||||
kilian <kilian.cavalotti@lip6.fr>
|
||||
Sune Kirkeby <http://ibofobi.dk/>
|
||||
Cameron Knight (ckknight)
|
||||
Meir Kriheli <http://mksoft.co.il/>
|
||||
Bruce Kroeze <http://coderseye.com/>
|
||||
Joseph Kocherhans
|
||||
konrad@gwu.edu
|
||||
lakin.wecker@gmail.com
|
||||
Stuart Langridge <http://www.kryogenix.org/>
|
||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||
Jeong-Min Lee
|
||||
Jeong-Min Lee <falsetru@gmail.com>
|
||||
Christopher Lenz <http://www.cmlenz.net/>
|
||||
lerouxb@gmail.com
|
||||
limodou
|
||||
mattmcc
|
||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||
masonsimon+django@gmail.com
|
||||
Manuzhai
|
||||
Petar Marić
|
||||
mark@junklight.com
|
||||
mattycakes@gmail.com
|
||||
Jason McBrayer <http://www.carcosa.net/jason/>
|
||||
mccutchen@gmail.com
|
||||
michael.mcewan@gmail.com
|
||||
mmarshall
|
||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||
@ -156,6 +160,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Amit Upadhyay
|
||||
Geert Vanderkelen
|
||||
Milton Waddams
|
||||
wam-djangobug@wamber.net
|
||||
Dan Watson <http://theidioteque.net/>
|
||||
Rachel Willmer <http://www.willmer.com/kb/>
|
||||
Gary Wilson <gary.wilson@gmail.com>
|
||||
|
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
@ -0,0 +1,8 @@
|
||||
include AUTHORS
|
||||
include INSTALL
|
||||
include LICENSE
|
||||
recursive-include django/conf/locale *
|
||||
recursive-include django/contrib/admin/templates
|
||||
recursive-include django/contrib/admin/media
|
||||
recursive-include django/contrib/comments/templates
|
||||
recursive-include django/contrib/sitemaps/templates
|
@ -56,6 +56,7 @@ LANGUAGES = (
|
||||
('ja', gettext_noop('Japanese')),
|
||||
('nl', gettext_noop('Dutch')),
|
||||
('no', gettext_noop('Norwegian')),
|
||||
('pl', gettext_noop('Polish')),
|
||||
('pt-br', gettext_noop('Brazilian')),
|
||||
('ro', gettext_noop('Romanian')),
|
||||
('ru', gettext_noop('Russian')),
|
||||
|
Binary file not shown.
@ -1,14 +1,13 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# Translation of django.po to japanese.
|
||||
# Copyright (C) 2005,2006 THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
# makoto tsuyuki <mtsuyuki@gmail.com>, 2005,2006.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-10-05 23:35+0900\n"
|
||||
"POT-Creation-Date: 2006-10-21 20:42+0900\n"
|
||||
"PO-Revision-Date: 2006-05-18 00:28+0900\n"
|
||||
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
|
||||
"Language-Team: Japanese <django-ja@googlegroups.com>\n"
|
||||
@ -57,9 +56,8 @@ msgid "Argentinean Spanish"
|
||||
msgstr "アルゼンチンスペイン語"
|
||||
|
||||
#: conf/global_settings.py:49
|
||||
#, fuzzy
|
||||
msgid "Finnish"
|
||||
msgstr "デンマーク語"
|
||||
msgstr "フィンランド語"
|
||||
|
||||
#: conf/global_settings.py:50
|
||||
msgid "French"
|
||||
@ -98,52 +96,54 @@ msgid "Norwegian"
|
||||
msgstr "ノルウェー語"
|
||||
|
||||
#: conf/global_settings.py:59
|
||||
msgid "Polish"
|
||||
msgstr "ポーランド語"
|
||||
|
||||
#: conf/global_settings.py:60
|
||||
msgid "Brazilian"
|
||||
msgstr "ブラジル語"
|
||||
|
||||
#: conf/global_settings.py:60
|
||||
#: conf/global_settings.py:61
|
||||
msgid "Romanian"
|
||||
msgstr "ルーマニア語"
|
||||
|
||||
#: conf/global_settings.py:61
|
||||
#: conf/global_settings.py:62
|
||||
msgid "Russian"
|
||||
msgstr "ロシア語"
|
||||
|
||||
#: conf/global_settings.py:62
|
||||
#: conf/global_settings.py:63
|
||||
msgid "Slovak"
|
||||
msgstr "スロバキア語"
|
||||
|
||||
#: conf/global_settings.py:63
|
||||
#, fuzzy
|
||||
#: conf/global_settings.py:64
|
||||
msgid "Slovenian"
|
||||
msgstr "スロヴェニア語"
|
||||
|
||||
#: conf/global_settings.py:64
|
||||
#: conf/global_settings.py:65
|
||||
msgid "Serbian"
|
||||
msgstr "セルビア語"
|
||||
|
||||
#: conf/global_settings.py:65
|
||||
#: conf/global_settings.py:66
|
||||
msgid "Swedish"
|
||||
msgstr "スウェーデン語"
|
||||
|
||||
#: conf/global_settings.py:66
|
||||
#: conf/global_settings.py:67
|
||||
msgid "Tamil"
|
||||
msgstr "タミル語"
|
||||
|
||||
#: conf/global_settings.py:67
|
||||
#: conf/global_settings.py:68
|
||||
msgid "Turkish"
|
||||
msgstr "トルコ語"
|
||||
|
||||
#: conf/global_settings.py:68
|
||||
#, fuzzy
|
||||
#: conf/global_settings.py:69
|
||||
msgid "Ukrainian"
|
||||
msgstr "ウクライナ語"
|
||||
|
||||
#: conf/global_settings.py:69
|
||||
#: conf/global_settings.py:70
|
||||
msgid "Simplified Chinese"
|
||||
msgstr "簡体字中国語"
|
||||
|
||||
#: conf/global_settings.py:70
|
||||
#: conf/global_settings.py:71
|
||||
msgid "Traditional Chinese"
|
||||
msgstr "繁体字中国語"
|
||||
|
||||
@ -369,33 +369,33 @@ msgid "Delete"
|
||||
msgstr "削除"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:14
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
|
||||
"related objects, but your account doesn't have permission to delete the "
|
||||
"following types of objects:"
|
||||
msgstr ""
|
||||
"%(object_name)s '%(object)s' の削除時に関連づけられたオブジェクトも削除しよう"
|
||||
"としましたが、あなたのアカウントには以下のタイプのオブジェクトを削除するパー"
|
||||
"ミッションがありません:"
|
||||
"%(object_name)s '%(escaped_object)s' の削除時に関連づけられたオブジェクトも削"
|
||||
"除しようとしましたが、あなたのアカウントには以下のタイプのオブジェクトを削除"
|
||||
"するパーミッションがありません:"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:21
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
|
||||
"All of the following related items will be deleted:"
|
||||
msgstr ""
|
||||
"%(object_name)s \"%(object)s\"を削除しますか? 関連づけられている以下のオブ"
|
||||
"ジェクトも全て削除されます:"
|
||||
"%(object_name)s \"%(escaped_object)s\"を削除しますか? 関連づけられている以下"
|
||||
"のオブジェクトも全て削除されます:"
|
||||
|
||||
#: contrib/admin/templates/admin/delete_confirmation.html:26
|
||||
msgid "Yes, I'm sure"
|
||||
msgstr "はい。"
|
||||
|
||||
#: contrib/admin/templates/admin/filter.html:2
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid " By %(filter_title)s "
|
||||
msgstr "%(title)s で絞り込む"
|
||||
msgstr "%(filter_title)s で絞り込む"
|
||||
|
||||
#: contrib/admin/templates/admin/filters.html:4
|
||||
msgid "Filter"
|
||||
@ -407,9 +407,9 @@ msgid "Models available in the %(name)s application."
|
||||
msgstr "%(name)s アプリケーションで利用可能なモデル"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:18
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "%(name)s"
|
||||
msgstr "%(name)s を追加"
|
||||
msgstr "%(name)s"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:34
|
||||
msgid "Change"
|
||||
@ -436,9 +436,9 @@ msgid ""
|
||||
"Something's wrong with your database installation. Make sure the appropriate "
|
||||
"database tables have been created, and make sure the database is readable by "
|
||||
"the appropriate user."
|
||||
msgstr "データベースの設定に問題があるようです。"
|
||||
"適切なテーブルが作られていること、適切なユーザで"
|
||||
"データベースのデータを読み込めることを確認してください。"
|
||||
msgstr ""
|
||||
"データベースの設定に問題があるようです。適切なテーブルが作られていること、適"
|
||||
"切なユーザでデータベースのデータを読み込めることを確認してください。"
|
||||
|
||||
#: contrib/admin/templates/admin/login.html:17
|
||||
#: contrib/comments/templates/comments/form.html:6
|
||||
@ -525,23 +525,20 @@ msgid ""
|
||||
"First, enter a username and password. Then, you'll be able to edit more user "
|
||||
"options."
|
||||
msgstr ""
|
||||
"まずユーザ名とパスワードを登録してください。"
|
||||
"その後詳細情報が編集可能になります。"
|
||||
"まずユーザ名とパスワードを登録してください。その後詳細情報が編集可能になりま"
|
||||
"す。"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:12
|
||||
#, fuzzy
|
||||
msgid "Username"
|
||||
msgstr "ユーザ名:"
|
||||
msgstr "ユーザ名"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:18
|
||||
#, fuzzy
|
||||
msgid "Password"
|
||||
msgstr "パスワード:"
|
||||
msgstr "パスワード"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:23
|
||||
#, fuzzy
|
||||
msgid "Password (again)"
|
||||
msgstr "パスワードの変更"
|
||||
msgstr "パスワード(確認用)"
|
||||
|
||||
#: contrib/admin/templates/admin/auth/user/add_form.html:24
|
||||
msgid "Enter the same password as above, for verification."
|
||||
@ -761,9 +758,8 @@ msgid "You may edit it again below."
|
||||
msgstr "続けて編集できます。"
|
||||
|
||||
#: contrib/admin/views/auth.py:28
|
||||
#, fuzzy
|
||||
msgid "Add user"
|
||||
msgstr "%s を追加"
|
||||
msgstr "ユーザを追加"
|
||||
|
||||
#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59
|
||||
msgid ""
|
||||
@ -813,9 +809,9 @@ msgid "view:"
|
||||
msgstr "ビュー"
|
||||
|
||||
#: contrib/admin/views/doc.py:164
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "App %r not found"
|
||||
msgstr "ページが見つかりません"
|
||||
msgstr "アプリケーション %r が見つかりません"
|
||||
|
||||
#: contrib/admin/views/doc.py:171
|
||||
#, python-format
|
||||
@ -1030,9 +1026,8 @@ msgid "The two password fields didn't match."
|
||||
msgstr "確認用パスワードが一致しません。"
|
||||
|
||||
#: contrib/auth/forms.py:24
|
||||
#, fuzzy
|
||||
msgid "A user with that username already exists."
|
||||
msgstr "%(fieldname)s に %(optname)s は既に存在します。"
|
||||
msgstr "同じユーザ名が既に登録済みです。"
|
||||
|
||||
#: contrib/auth/forms.py:52
|
||||
msgid ""
|
||||
@ -1048,11 +1043,9 @@ msgstr "アカウントが無効です。"
|
||||
|
||||
#: contrib/auth/forms.py:84
|
||||
msgid ""
|
||||
"That e-mail address doesn't have an associated user acount. Are you sure "
|
||||
"That e-mail address doesn't have an associated user account. Are you sure "
|
||||
"you've registered?"
|
||||
msgstr ""
|
||||
"メールアドレスの一致するユーザはいません。"
|
||||
"本当に登録しましたか?"
|
||||
msgstr "メールアドレスの一致するユーザはいません。本当に登録しましたか?"
|
||||
|
||||
#: contrib/auth/forms.py:116
|
||||
msgid "The two 'new password' fields didn't match."
|
||||
@ -1071,22 +1064,18 @@ msgid "codename"
|
||||
msgstr "コード名"
|
||||
|
||||
#: contrib/auth/models.py:42
|
||||
#, fuzzy
|
||||
msgid "permission"
|
||||
msgstr "パーミッション"
|
||||
|
||||
#: contrib/auth/models.py:43 contrib/auth/models.py:58
|
||||
#, fuzzy
|
||||
msgid "permissions"
|
||||
msgstr "パーミッション"
|
||||
|
||||
#: contrib/auth/models.py:60
|
||||
#, fuzzy
|
||||
msgid "group"
|
||||
msgstr "グループ"
|
||||
|
||||
#: contrib/auth/models.py:61 contrib/auth/models.py:100
|
||||
#, fuzzy
|
||||
msgid "groups"
|
||||
msgstr "グループ"
|
||||
|
||||
@ -1099,8 +1088,8 @@ msgid ""
|
||||
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
||||
"digits and underscores)."
|
||||
msgstr ""
|
||||
"この項目は必須です。"
|
||||
"半角アルファベット、半角数字、半角アンダーバーで30文字以下にしてください。"
|
||||
"この項目は必須です。半角アルファベット、半角数字、半角アンダーバーで30文字以"
|
||||
"下にしてください。"
|
||||
|
||||
#: contrib/auth/models.py:91
|
||||
msgid "first name"
|
||||
@ -1138,9 +1127,7 @@ msgstr "有効"
|
||||
msgid ""
|
||||
"Designates whether this user can log into the Django admin. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
"ユーザが管理サイトにログイン可能か"
|
||||
"どうかを示します。"
|
||||
msgstr "ユーザが管理サイトにログイン可能かどうかを示します。"
|
||||
|
||||
#: contrib/auth/models.py:97
|
||||
msgid "superuser status"
|
||||
@ -1169,17 +1156,14 @@ msgstr ""
|
||||
"パーミッションを獲得します。"
|
||||
|
||||
#: contrib/auth/models.py:102
|
||||
#, fuzzy
|
||||
msgid "user permissions"
|
||||
msgstr "ユーザパーミッション"
|
||||
|
||||
#: contrib/auth/models.py:105
|
||||
#, fuzzy
|
||||
msgid "user"
|
||||
msgstr "ユーザ"
|
||||
|
||||
#: contrib/auth/models.py:106
|
||||
#, fuzzy
|
||||
msgid "users"
|
||||
msgstr "ユーザ"
|
||||
|
||||
@ -1188,7 +1172,6 @@ msgid "Personal info"
|
||||
msgstr "個人情報"
|
||||
|
||||
#: contrib/auth/models.py:112
|
||||
#, fuzzy
|
||||
msgid "Permissions"
|
||||
msgstr "パーミッション"
|
||||
|
||||
@ -1201,12 +1184,10 @@ msgid "Groups"
|
||||
msgstr "グループ"
|
||||
|
||||
#: contrib/auth/models.py:258
|
||||
#, fuzzy
|
||||
msgid "message"
|
||||
msgstr "メッセージ"
|
||||
|
||||
#: contrib/auth/views.py:39
|
||||
#, fuzzy
|
||||
msgid "Logged out"
|
||||
msgstr "ログアウト"
|
||||
|
||||
@ -1280,7 +1261,6 @@ msgstr ""
|
||||
"た」と表示されるようになります。"
|
||||
|
||||
#: contrib/comments/models.py:91
|
||||
#, fuzzy
|
||||
msgid "comments"
|
||||
msgstr "コメント"
|
||||
|
||||
@ -1316,12 +1296,10 @@ msgid "approved by staff"
|
||||
msgstr "スタッフの承認済み"
|
||||
|
||||
#: contrib/comments/models.py:176
|
||||
#, fuzzy
|
||||
msgid "free comment"
|
||||
msgstr "フリーコメント"
|
||||
|
||||
#: contrib/comments/models.py:177
|
||||
#, fuzzy
|
||||
msgid "free comments"
|
||||
msgstr "フリーコメント"
|
||||
|
||||
@ -1334,12 +1312,10 @@ msgid "score date"
|
||||
msgstr "スコアされた日"
|
||||
|
||||
#: contrib/comments/models.py:237
|
||||
#, fuzzy
|
||||
msgid "karma score"
|
||||
msgstr "カルマスコア"
|
||||
|
||||
#: contrib/comments/models.py:238
|
||||
#, fuzzy
|
||||
msgid "karma scores"
|
||||
msgstr "カルマスコア"
|
||||
|
||||
@ -1364,12 +1340,10 @@ msgid "flag date"
|
||||
msgstr "フラグ日"
|
||||
|
||||
#: contrib/comments/models.py:268
|
||||
#, fuzzy
|
||||
msgid "user flag"
|
||||
msgstr "ユーザフラグ"
|
||||
|
||||
#: contrib/comments/models.py:269
|
||||
#, fuzzy
|
||||
msgid "user flags"
|
||||
msgstr "ユーザフラグ"
|
||||
|
||||
@ -1383,12 +1357,10 @@ msgid "deletion date"
|
||||
msgstr "削除日"
|
||||
|
||||
#: contrib/comments/models.py:280
|
||||
#, fuzzy
|
||||
msgid "moderator deletion"
|
||||
msgstr "モデレータ削除"
|
||||
|
||||
#: contrib/comments/models.py:281
|
||||
#, fuzzy
|
||||
msgid "moderator deletions"
|
||||
msgstr "モデレータ削除"
|
||||
|
||||
@ -1398,12 +1370,10 @@ msgid "Moderator deletion by %r"
|
||||
msgstr "%r によるモデレータ削除"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:8
|
||||
#, fuzzy
|
||||
msgid "Forgotten your password?"
|
||||
msgstr "パスワードをお忘れですか?"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:12
|
||||
#, fuzzy
|
||||
msgid "Ratings"
|
||||
msgstr "レーティング"
|
||||
|
||||
@ -1423,18 +1393,15 @@ msgstr "写真を登録"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:28
|
||||
#: contrib/comments/templates/comments/freeform.html:5
|
||||
#, fuzzy
|
||||
msgid "Comment:"
|
||||
msgstr "コメント:"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:35
|
||||
#: contrib/comments/templates/comments/freeform.html:10
|
||||
#, fuzzy
|
||||
msgid "Preview comment"
|
||||
msgstr "コメントをプレビュー"
|
||||
|
||||
#: contrib/comments/templates/comments/freeform.html:4
|
||||
#, fuzzy
|
||||
msgid "Your name:"
|
||||
msgstr "ユーザ名:"
|
||||
|
||||
@ -1512,7 +1479,6 @@ msgid "No voting for yourself"
|
||||
msgstr "自分には投票できません。"
|
||||
|
||||
#: contrib/contenttypes/models.py:20
|
||||
#, fuzzy
|
||||
msgid "python model class name"
|
||||
msgstr "Python モデルクラス名"
|
||||
|
||||
@ -1547,13 +1513,12 @@ msgid "template name"
|
||||
msgstr "テンプレート名"
|
||||
|
||||
#: contrib/flatpages/models.py:13
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
||||
"will use 'flatpages/default.html'."
|
||||
msgstr ""
|
||||
"例: 'flatpages/contact_page'. 指定しなければ、デフォルト設定の'flatpages/"
|
||||
"default' を使います。"
|
||||
"例: 'flatpages/contact_page.html'. 指定しなければ、デフォルト設定"
|
||||
"の'flatpages/default.html' を使います。"
|
||||
|
||||
#: contrib/flatpages/models.py:14
|
||||
msgid "registration required"
|
||||
@ -1640,16 +1605,15 @@ msgid "This value must contain only letters, numbers and underscores."
|
||||
msgstr "半角の英数字およびアンダースコア以外は使用できません。"
|
||||
|
||||
#: core/validators.py:67
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"This value must contain only letters, numbers, underscores, dashes or "
|
||||
"slashes."
|
||||
msgstr "半角の英数字、アンダースコア、ダッシュ、ラッシュ以外は使用できません。"
|
||||
msgstr ""
|
||||
"半角の英数字、アンダースコア、ダッシュ、スラッシュ以外は使用できません。"
|
||||
|
||||
#: core/validators.py:71
|
||||
#, fuzzy
|
||||
msgid "This value must contain only letters, numbers, underscores or hyphens."
|
||||
msgstr "半角の英数字、アンダースコア、ダッシュ、ラッシュ以外は使用できません。"
|
||||
msgstr "半角の英数字、アンダースコア、ハイフン以外は使用できません。"
|
||||
|
||||
#: core/validators.py:75
|
||||
msgid "Uppercase letters are not allowed here."
|
||||
@ -1696,9 +1660,9 @@ msgid "Year must be 1900 or later."
|
||||
msgstr "1900年以降を指定してください。"
|
||||
|
||||
#: core/validators.py:142
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "Invalid date: %s."
|
||||
msgstr "無効なURL: %s"
|
||||
msgstr "無効な日付: %s"
|
||||
|
||||
#: core/validators.py:146 db/models/fields/__init__.py:424
|
||||
msgid "Enter a valid date in YYYY-MM-DD format."
|
||||
@ -1718,7 +1682,8 @@ msgstr "有効なメールアドレスを入力してください。"
|
||||
|
||||
#: core/validators.py:172 core/validators.py:401 forms/__init__.py:662
|
||||
msgid "No file was submitted. Check the encoding type on the form."
|
||||
msgstr "ファイルが取得できませんでした。formのencoding typeを確認してください。"
|
||||
msgstr ""
|
||||
"ファイルが取得できませんでした。formのencoding typeを確認してください。"
|
||||
|
||||
#: core/validators.py:176
|
||||
msgid ""
|
||||
@ -1825,25 +1790,25 @@ msgstr "有効な 10 進数を入力してください。"
|
||||
msgid "Please enter a valid decimal number with at most %s total digit."
|
||||
msgid_plural ""
|
||||
"Please enter a valid decimal number with at most %s total digits."
|
||||
msgstr[0] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。"
|
||||
msgstr[1] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。"
|
||||
msgstr[0] "全体で %s 文字以下の数字を入力してください。"
|
||||
msgstr[1] "全体で %s 文字以下の数字を入力してください。"
|
||||
|
||||
#: core/validators.py:381
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please enter a valid decimal number with a whole part of at most %s digit."
|
||||
msgid_plural ""
|
||||
"Please enter a valid decimal number with a whole part of at most %s digits."
|
||||
msgstr[0] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。"
|
||||
msgstr[1] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。"
|
||||
msgstr[0] "整数部は %s 文字以下の数字を入力してください。"
|
||||
msgstr[1] "整数部は %s 文字以下の数字を入力してください。"
|
||||
|
||||
#: core/validators.py:384
|
||||
#, python-format
|
||||
msgid "Please enter a valid decimal number with at most %s decimal place."
|
||||
msgid_plural ""
|
||||
"Please enter a valid decimal number with at most %s decimal places."
|
||||
msgstr[0] "小数点以下が %s 桁までの有効な 10 進数を入力してください。"
|
||||
msgstr[1] "小数点以下が %s 桁までの有効な 10 進数を入力してください。"
|
||||
msgstr[0] "小数部は %s 文字以下の数字を入力してください。"
|
||||
msgstr[1] "小数部は %s 文字以下の数字を入力してください。"
|
||||
|
||||
#: core/validators.py:394
|
||||
#, python-format
|
||||
@ -1947,17 +1912,14 @@ msgid "This field is required."
|
||||
msgstr "このフィールドは必須です。"
|
||||
|
||||
#: db/models/fields/__init__.py:349
|
||||
#, fuzzy
|
||||
msgid "This value must be an integer."
|
||||
msgstr "値は整数でなければなりません。"
|
||||
|
||||
#: db/models/fields/__init__.py:381
|
||||
#, fuzzy
|
||||
msgid "This value must be either True or False."
|
||||
msgstr "値は真: True または偽: False でなければなりません。"
|
||||
|
||||
#: db/models/fields/__init__.py:397
|
||||
#, fuzzy
|
||||
msgid "This field cannot be null."
|
||||
msgstr "このフィールドには NULL を指定できません。"
|
||||
|
||||
@ -1971,7 +1933,6 @@ msgid "Please enter a valid %s."
|
||||
msgstr "正しい %s を入力してください。"
|
||||
|
||||
#: db/models/fields/related.py:618
|
||||
#, fuzzy
|
||||
msgid "Separate multiple IDs with commas."
|
||||
msgstr "複数の ID はカンマで区切ってください。"
|
||||
|
||||
@ -1979,7 +1940,8 @@ msgstr "複数の ID はカンマで区切ってください。"
|
||||
msgid ""
|
||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||
msgstr ""
|
||||
"複数選択するときには Control キーを押したまま選択してください。Mac は Command キーを使ってください"
|
||||
"複数選択するときには Control キーを押したまま選択してください。Mac は "
|
||||
"Command キーを使ってください"
|
||||
|
||||
#: db/models/fields/related.py:664
|
||||
#, python-format
|
||||
@ -2102,7 +2064,6 @@ msgid "December"
|
||||
msgstr "12月"
|
||||
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "jan"
|
||||
msgstr "1月"
|
||||
|
||||
@ -2119,7 +2080,6 @@ msgid "apr"
|
||||
msgstr "4月"
|
||||
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "may"
|
||||
msgstr "5月"
|
||||
|
||||
@ -2228,29 +2188,27 @@ msgid "TIME_FORMAT"
|
||||
msgstr "H:i"
|
||||
|
||||
#: utils/translation/trans_real.py:380
|
||||
#, fuzzy
|
||||
msgid "YEAR_MONTH_FORMAT"
|
||||
msgstr "Y/m/d"
|
||||
|
||||
#: utils/translation/trans_real.py:381
|
||||
#, fuzzy
|
||||
msgid "MONTH_DAY_FORMAT"
|
||||
msgstr "Y/m/d"
|
||||
msgstr "m/d"
|
||||
|
||||
#: views/generic/create_update.py:43
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "The %(verbose_name)s was created successfully."
|
||||
msgstr "%(name)s \"%(obj)s\" を変更しました。"
|
||||
msgstr "%(verbose_name)s を作成しました。"
|
||||
|
||||
#: views/generic/create_update.py:117
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "The %(verbose_name)s was updated successfully."
|
||||
msgstr "%(name)s \"%(obj)s\" を削除しました。"
|
||||
msgstr "%(verbose_name)s を更新しました。"
|
||||
|
||||
#: views/generic/create_update.py:184
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "The %(verbose_name)s was deleted."
|
||||
msgstr " %(site_name)s チーム"
|
||||
msgstr " %(verbose_name)s を削除しました。"
|
||||
|
||||
#~ msgid "String (up to 50)"
|
||||
#~ msgstr "文字列 (50 字まで)"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/tr/LC_MESSAGES/djangojs.mo
Normal file
BIN
django/conf/locale/tr/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
109
django/conf/locale/tr/LC_MESSAGES/djangojs.po
Normal file
109
django/conf/locale/tr/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,109 @@
|
||||
# Django 0.95
|
||||
# Copyright (C) 2006 Django
|
||||
# This file is distributed under the same license as the Django package.
|
||||
# Bahadır Kandemir <bahadir@pardus.org.tr>, 2006.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django 0.95\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-09-30 01:31+0300\n"
|
||||
"PO-Revision-Date: 2006-09-30 01:31+0300\n"
|
||||
"Last-Translator: Bahadır Kandemir <bahadir@pardus.org.tr>\n"
|
||||
"Language-Team: Bahadır Kandemir <bahadir@pardus.org.tr>\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 "Mevcut %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
msgstr "Hepsini seç"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||
msgid "Add"
|
||||
msgstr "Ekle"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
msgstr "Kaldır"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Seçilen %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Seçiminizi yapın ve tıklayın "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "Hepsini temizle"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:26
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr "Ocak Şubat Mart Nisan Mayıs Haziran Temmuz Ağustos Eylül Ekim Kasım "
|
||||
"Aralık"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Pazar Pazartesi Salı Çarşamba Perşembe Cuma Cumartesi"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "P P S Ç P C C"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
msgid "Now"
|
||||
msgstr "Şimdi"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
msgid "Clock"
|
||||
msgstr "Saat"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
msgid "Choose a time"
|
||||
msgstr "Saat seçin"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Midnight"
|
||||
msgstr "Geceyarısı"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "6 a.m."
|
||||
msgstr "Sabah 6"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "Noon"
|
||||
msgstr "Öğle"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
msgid "Cancel"
|
||||
msgstr "İptal"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
msgid "Today"
|
||||
msgstr "Bugün"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
msgid "Calendar"
|
||||
msgstr "Takvim"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
msgid "Yesterday"
|
||||
msgstr "Dün"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
msgid "Tomorrow"
|
||||
msgstr "Yarın"
|
@ -19,7 +19,7 @@
|
||||
<div class="form-row">
|
||||
<label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
|
||||
<input type="hidden" name="this_is_the_login_form" value="1" />
|
||||
<input type="hidden" name="post_data" value="{{ post_data }}" /> {% comment %}<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %}
|
||||
<input type="hidden" name="post_data" value="{{ post_data }}" /> {#<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>#}
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<label> </label><input type="submit" value="{% trans 'Log in' %}" />
|
||||
|
@ -197,8 +197,8 @@ def filter_interface_script_maybe(bound_field):
|
||||
f = bound_field.field
|
||||
if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface:
|
||||
return '<script type="text/javascript">addEvent(window, "load", function(e) {' \
|
||||
' SelectFilter.init("id_%s", %r, %s, "%s"); });</script>\n' % (
|
||||
f.name, f.verbose_name, f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX)
|
||||
' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
|
||||
f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX)
|
||||
else:
|
||||
return ''
|
||||
filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe)
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django import forms, template
|
||||
from django.shortcuts import render_to_response
|
||||
from django.http import HttpResponseRedirect
|
||||
|
@ -454,7 +454,7 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
|
||||
if related.opts.admin and has_related_objs:
|
||||
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
|
||||
if not user.has_perm(p):
|
||||
perms_needed.add(rel_opts_name)
|
||||
perms_needed.add(related.opts.verbose_name)
|
||||
for related in opts.get_all_related_many_to_many_objects():
|
||||
if related.opts in opts_seen:
|
||||
continue
|
||||
|
@ -81,7 +81,7 @@ class PasswordResetForm(forms.Manipulator):
|
||||
try:
|
||||
self.user_cache = User.objects.get(email__iexact=new_data)
|
||||
except User.DoesNotExist:
|
||||
raise validators.ValidationError, _("That e-mail address doesn't have an associated user acount. Are you sure you've registered?")
|
||||
raise validators.ValidationError, _("That e-mail address doesn't have an associated user account. Are you sure you've registered?")
|
||||
|
||||
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html'):
|
||||
"Calculates a new password randomly and sends it to the user"
|
||||
|
@ -92,9 +92,9 @@ class User(models.Model):
|
||||
last_name = models.CharField(_('last name'), maxlength=30, blank=True)
|
||||
email = models.EmailField(_('e-mail address'), blank=True)
|
||||
password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]'"))
|
||||
is_staff = models.BooleanField(_('staff status'), help_text=_("Designates whether the user can log into this admin site."))
|
||||
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
|
||||
is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."))
|
||||
is_superuser = models.BooleanField(_('superuser status'), help_text=_("Designates that this user has all permissions without explicitly assigning them."))
|
||||
is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
|
||||
last_login = models.DateTimeField(_('last login'), default=models.LazyDate())
|
||||
date_joined = models.DateTimeField(_('date joined'), default=models.LazyDate())
|
||||
groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
|
||||
@ -270,6 +270,15 @@ class AnonymousUser(object):
|
||||
def __str__(self):
|
||||
return 'AnonymousUser'
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
return 1 # instances always return the same hash value
|
||||
|
||||
def save(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -109,7 +109,7 @@ class PublicCommentManipulator(AuthenticationForm):
|
||||
# send the comment to the managers.
|
||||
if self.user_cache.comment_set.count() <= settings.COMMENTS_FIRST_FEW:
|
||||
message = ngettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s',
|
||||
'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s') % \
|
||||
'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s', settings.COMMENTS_FIRST_FEW) % \
|
||||
{'count': settings.COMMENTS_FIRST_FEW, 'text': c.get_as_text()}
|
||||
mail_managers("Comment posted by rookie user", message)
|
||||
if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]:
|
||||
@ -217,7 +217,7 @@ def post_comment(request):
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
# If user gave correct username/password and wasn't already logged in, log them in
|
||||
# so they don't have to enter a username/password again.
|
||||
if manipulator.get_user() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']):
|
||||
if manipulator.get_user() and not manipulator.get_user().is_authenticated() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']):
|
||||
from django.contrib.auth import login
|
||||
login(request, manipulator.get_user())
|
||||
if errors or request.POST.has_key('preview'):
|
||||
|
@ -41,6 +41,7 @@ class ModPythonRequest(http.HttpRequest):
|
||||
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
|
||||
|
||||
def is_secure(self):
|
||||
# Note: modpython 3.2.10+ has req.is_https(), but we need to support previous versions
|
||||
return self._req.subprocess_env.has_key('HTTPS') and self._req.subprocess_env['HTTPS'] == 'on'
|
||||
|
||||
def _load_post_and_files(self):
|
||||
@ -102,7 +103,7 @@ class ModPythonRequest(http.HttpRequest):
|
||||
'REQUEST_METHOD': self._req.method,
|
||||
'SCRIPT_NAME': None, # Not supported
|
||||
'SERVER_NAME': self._req.server.server_hostname,
|
||||
'SERVER_PORT': str(self._req.connection.local_addr[1]),
|
||||
'SERVER_PORT': self._req.server.port,
|
||||
'SERVER_PROTOCOL': self._req.protocol,
|
||||
'SERVER_SOFTWARE': 'mod_python'
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class dummy: pass
|
||||
style = dummy()
|
||||
style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
|
||||
style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
|
||||
style.NOTICE = termcolors.make_style(fg='red')
|
||||
style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
|
||||
style.SQL_COLTYPE = termcolors.make_style(fg='green')
|
||||
style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
|
||||
@ -234,8 +235,7 @@ def get_sql_indexes(app):
|
||||
opts = model._meta
|
||||
connection_name = model_connection_name(model)
|
||||
output = connection_output.setdefault(connection_name, [])
|
||||
builder = model._default_manager.db.get_creation_module().builder
|
||||
output.extend(map(str, builder.get_create_indexes(model, style)))
|
||||
output.extend(map(str, get_sql_indexes_for_model(model)))
|
||||
return _collate(connection_output)
|
||||
|
||||
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
|
||||
@ -243,20 +243,8 @@ get_sql_indexes.args = APP_ARGS
|
||||
|
||||
def get_sql_indexes_for_model(model):
|
||||
"Returns the CREATE INDEX SQL statements for a single model"
|
||||
from django.db import backend
|
||||
output = []
|
||||
|
||||
for f in model._meta.fields:
|
||||
if f.db_index:
|
||||
unique = f.unique and 'UNIQUE ' or ''
|
||||
output.append(
|
||||
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
|
||||
style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \
|
||||
style.SQL_KEYWORD('ON') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
|
||||
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
|
||||
)
|
||||
return output
|
||||
builder = model._default_manager.db.get_creation_module().builder
|
||||
return builder.get_create_indexes(model, style)
|
||||
|
||||
def get_sql_all(app):
|
||||
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
|
||||
@ -346,25 +334,6 @@ def syncdb(verbosity=1, interactive=True):
|
||||
else:
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
# Install SQL indicies for all newly created models
|
||||
for app in models.get_apps():
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
for model in models.get_models(app):
|
||||
if model in created_models:
|
||||
index_sql = get_sql_indexes_for_model(model)
|
||||
if index_sql:
|
||||
if verbosity >= 1:
|
||||
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
|
||||
try:
|
||||
for sql in index_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed to install index for %s.%s model: %s" % \
|
||||
(app_name, model._meta.object_name, e))
|
||||
transaction.rollback_unless_managed()
|
||||
else:
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
syncdb.args = ''
|
||||
|
||||
def get_admin_index(app):
|
||||
@ -501,6 +470,7 @@ def _post_syncdb(app, created_models, verbosity=1, interactive=True):
|
||||
def reset(app, interactive=True):
|
||||
"Executes the equivalent of 'get_sql_reset' in the current database."
|
||||
from django.db import connection, transaction
|
||||
from django.conf import settings
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
|
||||
disable_termcolors()
|
||||
@ -512,10 +482,11 @@ def reset(app, interactive=True):
|
||||
if interactive:
|
||||
confirm = raw_input("""
|
||||
You have requested a database reset.
|
||||
This will IRREVERSIBLY DESTROY any data in your database.
|
||||
This will IRREVERSIBLY DESTROY any data for
|
||||
the "%s" application in the database "%s".
|
||||
Are you sure you want to do this?
|
||||
|
||||
Type 'yes' to continue, or 'no' to cancel: """)
|
||||
Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
|
||||
else:
|
||||
confirm = 'yes'
|
||||
|
||||
@ -568,7 +539,10 @@ def _start_helper(app_or_project, name, directory, other_name=''):
|
||||
fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
|
||||
fp_old.close()
|
||||
fp_new.close()
|
||||
try:
|
||||
shutil.copymode(path_old, path_new)
|
||||
except OSError:
|
||||
sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
|
||||
|
||||
def startproject(project_name, directory):
|
||||
"Creates a Django project for the given project_name in the given directory."
|
||||
|
@ -2,7 +2,7 @@ from django.db import transaction
|
||||
from django.db.models import signals, get_model
|
||||
from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class
|
||||
from django.db.models.related import RelatedObject
|
||||
from django.utils.translation import gettext_lazy, string_concat
|
||||
from django.utils.translation import gettext_lazy, string_concat, ngettext
|
||||
from django.utils.functional import curry
|
||||
from django.core import validators
|
||||
from django import forms
|
||||
|
@ -303,7 +303,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
|
||||
pass
|
||||
else:
|
||||
raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \
|
||||
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], 'and')}
|
||||
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], _('and'))}
|
||||
|
||||
def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data):
|
||||
from django.db.models.fields.related import ManyToOneRel
|
||||
|
@ -727,7 +727,6 @@ def parse_lookup(kwarg_items, opts):
|
||||
joins, where, params = SortedDict(), [], []
|
||||
|
||||
for kwarg, value in kwarg_items:
|
||||
if value is not None:
|
||||
path = kwarg.split(LOOKUP_SEPARATOR)
|
||||
# Extract the last elements of the kwarg.
|
||||
# The very-last is the lookup_type (equals, like, etc).
|
||||
@ -747,6 +746,12 @@ def parse_lookup(kwarg_items, opts):
|
||||
if len(path) < 1:
|
||||
raise TypeError, "Cannot parse keyword query %r" % kwarg
|
||||
|
||||
if value is None:
|
||||
# Interpret '__exact=None' as the sql '= NULL'; otherwise, reject
|
||||
# all uses of None as a query value.
|
||||
if lookup_type != 'exact':
|
||||
raise ValueError, "Cannot use None as a query value"
|
||||
|
||||
joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
|
||||
joins.update(joins2)
|
||||
where.extend(where2)
|
||||
|
29
django/newforms/__init__.py
Normal file
29
django/newforms/__init__.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""
|
||||
Django validation and HTML form handling.
|
||||
|
||||
TODO:
|
||||
Validation not tied to a particular field
|
||||
<select> and validation of lists
|
||||
Default value for field
|
||||
Field labels
|
||||
Nestable Forms
|
||||
FatalValidationError -- short-circuits all other validators on a form
|
||||
ValidationWarning
|
||||
"This form field requires foo.js" and form.js_includes()
|
||||
"""
|
||||
|
||||
from widgets import *
|
||||
from fields import *
|
||||
from forms import Form
|
||||
|
||||
##########################
|
||||
# DATABASE API SHORTCUTS #
|
||||
##########################
|
||||
|
||||
def form_for_model(model):
|
||||
"Returns a Form instance for the given Django model class."
|
||||
raise NotImplementedError
|
||||
|
||||
def form_for_fields(field_list):
|
||||
"Returns a Form instance for the given list of Django database field instances."
|
||||
raise NotImplementedError
|
184
django/newforms/fields.py
Normal file
184
django/newforms/fields.py
Normal file
@ -0,0 +1,184 @@
|
||||
"""
|
||||
Field classes
|
||||
"""
|
||||
|
||||
from util import ValidationError, DEFAULT_ENCODING
|
||||
from widgets import TextInput, CheckboxInput
|
||||
import datetime
|
||||
import re
|
||||
import time
|
||||
|
||||
__all__ = (
|
||||
'Field', 'CharField', 'IntegerField',
|
||||
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
||||
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
||||
'RegexField', 'EmailField', 'BooleanField',
|
||||
)
|
||||
|
||||
# These values, if given to to_python(), will trigger the self.required check.
|
||||
EMPTY_VALUES = (None, '')
|
||||
|
||||
class Field(object):
|
||||
widget = TextInput # Default widget to use when rendering this type of Field.
|
||||
|
||||
def __init__(self, required=True, widget=None):
|
||||
self.required = required
|
||||
widget = widget or self.widget
|
||||
if isinstance(widget, type):
|
||||
widget = widget()
|
||||
self.widget = widget
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates the given value and returns its "normalized" value as an
|
||||
appropriate Python object.
|
||||
|
||||
Raises ValidationError for any errors.
|
||||
"""
|
||||
if self.required and value in EMPTY_VALUES:
|
||||
raise ValidationError(u'This field is required.')
|
||||
return value
|
||||
|
||||
class CharField(Field):
|
||||
def __init__(self, max_length=None, min_length=None, required=True, widget=None):
|
||||
Field.__init__(self, required, widget)
|
||||
self.max_length, self.min_length = max_length, min_length
|
||||
|
||||
def to_python(self, value):
|
||||
"Validates max_length and min_length. Returns a Unicode object."
|
||||
Field.to_python(self, value)
|
||||
if value in EMPTY_VALUES: value = u''
|
||||
if not isinstance(value, basestring):
|
||||
value = unicode(str(value), DEFAULT_ENCODING)
|
||||
elif not isinstance(value, unicode):
|
||||
value = unicode(value, DEFAULT_ENCODING)
|
||||
if self.max_length is not None and len(value) > self.max_length:
|
||||
raise ValidationError(u'Ensure this value has at most %d characters.' % self.max_length)
|
||||
if self.min_length is not None and len(value) < self.min_length:
|
||||
raise ValidationError(u'Ensure this value has at least %d characters.' % self.min_length)
|
||||
return value
|
||||
|
||||
class IntegerField(Field):
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates that int() can be called on the input. Returns the result
|
||||
of int().
|
||||
"""
|
||||
super(IntegerField, self).to_python(value)
|
||||
try:
|
||||
return int(value)
|
||||
except (ValueError, TypeError):
|
||||
raise ValidationError(u'Enter a whole number.')
|
||||
|
||||
DEFAULT_DATE_INPUT_FORMATS = (
|
||||
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
|
||||
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
|
||||
'%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
|
||||
'%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
|
||||
'%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
|
||||
)
|
||||
|
||||
class DateField(Field):
|
||||
def __init__(self, input_formats=None, required=True, widget=None):
|
||||
Field.__init__(self, required, widget)
|
||||
self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates that the input can be converted to a date. Returns a Python
|
||||
datetime.date object.
|
||||
"""
|
||||
Field.to_python(self, value)
|
||||
if value in EMPTY_VALUES:
|
||||
return None
|
||||
if isinstance(value, datetime.datetime):
|
||||
return value.date()
|
||||
if isinstance(value, datetime.date):
|
||||
return value
|
||||
for format in self.input_formats:
|
||||
try:
|
||||
return datetime.date(*time.strptime(value, format)[:3])
|
||||
except ValueError:
|
||||
continue
|
||||
raise ValidationError(u'Enter a valid date.')
|
||||
|
||||
DEFAULT_DATETIME_INPUT_FORMATS = (
|
||||
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
|
||||
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
|
||||
'%Y-%m-%d', # '2006-10-25'
|
||||
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
|
||||
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
|
||||
'%m/%d/%Y', # '10/25/2006'
|
||||
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
|
||||
'%m/%d/%y %H:%M', # '10/25/06 14:30'
|
||||
'%m/%d/%y', # '10/25/06'
|
||||
)
|
||||
|
||||
class DateTimeField(Field):
|
||||
def __init__(self, input_formats=None, required=True, widget=None):
|
||||
Field.__init__(self, required, widget)
|
||||
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates that the input can be converted to a datetime. Returns a
|
||||
Python datetime.datetime object.
|
||||
"""
|
||||
Field.to_python(self, value)
|
||||
if value in EMPTY_VALUES:
|
||||
return None
|
||||
if isinstance(value, datetime.datetime):
|
||||
return value
|
||||
if isinstance(value, datetime.date):
|
||||
return datetime.datetime(value.year, value.month, value.day)
|
||||
for format in self.input_formats:
|
||||
try:
|
||||
return datetime.datetime(*time.strptime(value, format)[:6])
|
||||
except ValueError:
|
||||
continue
|
||||
raise ValidationError(u'Enter a valid date/time.')
|
||||
|
||||
class RegexField(Field):
|
||||
def __init__(self, regex, error_message=None, required=True, widget=None):
|
||||
"""
|
||||
regex can be either a string or a compiled regular expression object.
|
||||
error_message is an optional error message to use, if
|
||||
'Enter a valid value' is too generic for you.
|
||||
"""
|
||||
Field.__init__(self, required, widget)
|
||||
if isinstance(regex, basestring):
|
||||
regex = re.compile(regex)
|
||||
self.regex = regex
|
||||
self.error_message = error_message or u'Enter a valid value.'
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates that the input matches the regular expression. Returns a
|
||||
Unicode object.
|
||||
"""
|
||||
Field.to_python(self, value)
|
||||
if value in EMPTY_VALUES: value = u''
|
||||
if not isinstance(value, basestring):
|
||||
value = unicode(str(value), DEFAULT_ENCODING)
|
||||
elif not isinstance(value, unicode):
|
||||
value = unicode(value, DEFAULT_ENCODING)
|
||||
if not self.regex.search(value):
|
||||
raise ValidationError(self.error_message)
|
||||
return value
|
||||
|
||||
email_re = re.compile(
|
||||
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
|
||||
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
|
||||
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
|
||||
|
||||
class EmailField(RegexField):
|
||||
def __init__(self, required=True, widget=None):
|
||||
RegexField.__init__(self, email_re, u'Enter a valid e-mail address.', required, widget)
|
||||
|
||||
class BooleanField(Field):
|
||||
widget = CheckboxInput
|
||||
|
||||
def to_python(self, value):
|
||||
"Returns a Python boolean object."
|
||||
Field.to_python(self, value)
|
||||
return bool(value)
|
103
django/newforms/forms.py
Normal file
103
django/newforms/forms.py
Normal file
@ -0,0 +1,103 @@
|
||||
"""
|
||||
Form classes
|
||||
"""
|
||||
|
||||
from fields import Field
|
||||
from widgets import TextInput, Textarea
|
||||
from util import ErrorDict, ErrorList, ValidationError
|
||||
|
||||
class DeclarativeFieldsMetaclass(type):
|
||||
"Metaclass that converts Field attributes to a dictionary called 'fields'."
|
||||
def __new__(cls, name, bases, attrs):
|
||||
attrs['fields'] = dict([(name, attrs.pop(name)) for name, obj in attrs.items() if isinstance(obj, Field)])
|
||||
return type.__new__(cls, name, bases, attrs)
|
||||
|
||||
class Form(object):
|
||||
"A collection of Fields, plus their associated data."
|
||||
__metaclass__ = DeclarativeFieldsMetaclass
|
||||
|
||||
def __init__(self, data=None): # TODO: prefix stuff
|
||||
self.data = data or {}
|
||||
self.__data_python = None # Stores the data after to_python() has been called.
|
||||
self.__errors = None # Stores the errors after to_python() has been called.
|
||||
|
||||
def __iter__(self):
|
||||
for name, field in self.fields.items():
|
||||
yield BoundField(self, field, name)
|
||||
|
||||
def to_python(self):
|
||||
if self.__errors is None:
|
||||
self._validate()
|
||||
return self.__data_python
|
||||
|
||||
def errors(self):
|
||||
"Returns an ErrorDict for self.data"
|
||||
if self.__errors is None:
|
||||
self._validate()
|
||||
return self.__errors
|
||||
|
||||
def is_valid(self):
|
||||
"""
|
||||
Returns True if the form has no errors. Otherwise, False. This exists
|
||||
solely for convenience, so client code can use positive logic rather
|
||||
than confusing negative logic ("if not form.errors()").
|
||||
"""
|
||||
return not bool(self.errors())
|
||||
|
||||
def __getitem__(self, name):
|
||||
"Returns a BoundField with the given name."
|
||||
try:
|
||||
field = self.fields[name]
|
||||
except KeyError:
|
||||
raise KeyError('Key %r not found in Form' % name)
|
||||
return BoundField(self, field, name)
|
||||
|
||||
def _validate(self):
|
||||
data_python = {}
|
||||
errors = ErrorDict()
|
||||
for name, field in self.fields.items():
|
||||
try:
|
||||
value = field.to_python(self.data.get(name, None))
|
||||
data_python[name] = value
|
||||
except ValidationError, e:
|
||||
errors[name] = e.messages
|
||||
if not errors: # Only set self.data_python if there weren't errors.
|
||||
self.__data_python = data_python
|
||||
self.__errors = errors
|
||||
|
||||
class BoundField(object):
|
||||
"A Field plus data"
|
||||
def __init__(self, form, field, name):
|
||||
self._form = form
|
||||
self._field = field
|
||||
self._name = name
|
||||
|
||||
def __str__(self):
|
||||
"Renders this field as an HTML widget."
|
||||
# Use the 'widget' attribute on the field to determine which type
|
||||
# of HTML widget to use.
|
||||
return self.as_widget(self._field.widget)
|
||||
|
||||
def _errors(self):
|
||||
"""
|
||||
Returns an ErrorList for this field. Returns an empty ErrorList
|
||||
if there are none.
|
||||
"""
|
||||
try:
|
||||
return self._form.errors()[self._name]
|
||||
except KeyError:
|
||||
return ErrorList()
|
||||
errors = property(_errors)
|
||||
|
||||
def as_widget(self, widget, attrs=None):
|
||||
return widget.render(self._name, self._form.data.get(self._name, None), attrs=attrs)
|
||||
|
||||
def as_text(self, attrs=None):
|
||||
"""
|
||||
Returns a string of HTML for representing this as an <input type="text">.
|
||||
"""
|
||||
return self.as_widget(TextInput(), attrs)
|
||||
|
||||
def as_textarea(self, attrs=None):
|
||||
"Returns a string of HTML for representing this as a <textarea>."
|
||||
return self.as_widget(Textarea(), attrs)
|
55
django/newforms/util.py
Normal file
55
django/newforms/util.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Default encoding for input byte strings.
|
||||
DEFAULT_ENCODING = 'utf-8' # TODO: First look at django.conf.settings, then fall back to this.
|
||||
|
||||
def smart_unicode(s):
|
||||
if not isinstance(s, unicode):
|
||||
s = unicode(s, DEFAULT_ENCODING)
|
||||
return s
|
||||
|
||||
class ErrorDict(dict):
|
||||
"""
|
||||
A collection of errors that knows how to display itself in various formats.
|
||||
|
||||
The dictionary keys are the field names, and the values are the errors.
|
||||
"""
|
||||
def __str__(self):
|
||||
return self.as_ul()
|
||||
|
||||
def as_ul(self):
|
||||
if not self: return u''
|
||||
return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s%s</li>' % (k, v) for k, v in self.items()])
|
||||
|
||||
def as_text(self):
|
||||
return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % i for i in v])) for k, v in self.items()])
|
||||
|
||||
class ErrorList(list):
|
||||
"""
|
||||
A collection of errors that knows how to display itself in various formats.
|
||||
"""
|
||||
def __str__(self):
|
||||
return self.as_ul()
|
||||
|
||||
def as_ul(self):
|
||||
if not self: return u''
|
||||
return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s</li>' % e for e in self])
|
||||
|
||||
def as_text(self):
|
||||
if not self: return u''
|
||||
return u'\n'.join([u'* %s' % e for e in self])
|
||||
|
||||
class ValidationError(Exception):
|
||||
def __init__(self, message):
|
||||
"ValidationError can be passed a string or a list."
|
||||
if isinstance(message, list):
|
||||
self.messages = ErrorList([smart_unicode(msg) for msg in message])
|
||||
else:
|
||||
assert isinstance(message, basestring), ("%s should be a basestring" % repr(message))
|
||||
message = smart_unicode(message)
|
||||
self.messages = ErrorList([message])
|
||||
|
||||
def __str__(self):
|
||||
# This is needed because, without a __str__(), printing an exception
|
||||
# instance would result in this:
|
||||
# AttributeError: ValidationError instance has no attribute 'args'
|
||||
# See http://www.python.org/doc/current/tut/node10.html#handling
|
||||
return repr(self.messages)
|
43
django/newforms/widgets.py
Normal file
43
django/newforms/widgets.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""
|
||||
HTML Widget classes
|
||||
"""
|
||||
|
||||
__all__ = ('Widget', 'TextInput', 'Textarea', 'CheckboxInput')
|
||||
|
||||
from django.utils.html import escape
|
||||
|
||||
# Converts a dictionary to a single string with key="value", XML-style.
|
||||
# Assumes keys do not need to be XML-escaped.
|
||||
flatatt = lambda attrs: ' '.join(['%s="%s"' % (k, escape(v)) for k, v in attrs.items()])
|
||||
|
||||
class Widget(object):
|
||||
def __init__(self, attrs=None):
|
||||
self.attrs = attrs or {}
|
||||
|
||||
def render(self, name, value):
|
||||
raise NotImplementedError
|
||||
|
||||
class TextInput(Widget):
|
||||
def render(self, name, value, attrs=None):
|
||||
if value is None: value = ''
|
||||
final_attrs = dict(self.attrs, type='text', name=name)
|
||||
if attrs:
|
||||
final_attrs.update(attrs)
|
||||
if value != '': final_attrs['value'] = value # Only add the 'value' attribute if a value is non-empty.
|
||||
return u'<input %s />' % flatatt(final_attrs)
|
||||
|
||||
class Textarea(Widget):
|
||||
def render(self, name, value, attrs=None):
|
||||
if value is None: value = ''
|
||||
final_attrs = dict(self.attrs, name=name)
|
||||
if attrs:
|
||||
final_attrs.update(attrs)
|
||||
return u'<textarea %s>%s</textarea>' % (flatatt(final_attrs), escape(value))
|
||||
|
||||
class CheckboxInput(Widget):
|
||||
def render(self, name, value, attrs=None):
|
||||
final_attrs = dict(self.attrs, type='checkbox', name=name)
|
||||
if attrs:
|
||||
final_attrs.update(attrs)
|
||||
if value: final_attrs['checked'] = 'checked'
|
||||
return u'<input %s />' % flatatt(final_attrs)
|
@ -66,6 +66,7 @@ __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
|
||||
TOKEN_TEXT = 0
|
||||
TOKEN_VAR = 1
|
||||
TOKEN_BLOCK = 2
|
||||
TOKEN_COMMENT = 3
|
||||
|
||||
# template syntax constants
|
||||
FILTER_SEPARATOR = '|'
|
||||
@ -75,6 +76,8 @@ BLOCK_TAG_START = '{%'
|
||||
BLOCK_TAG_END = '%}'
|
||||
VARIABLE_TAG_START = '{{'
|
||||
VARIABLE_TAG_END = '}}'
|
||||
COMMENT_TAG_START = '{#'
|
||||
COMMENT_TAG_END = '#}'
|
||||
SINGLE_BRACE_START = '{'
|
||||
SINGLE_BRACE_END = '}'
|
||||
|
||||
@ -85,8 +88,9 @@ ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01
|
||||
UNKNOWN_SOURCE="<unknown source>"
|
||||
|
||||
# match a variable or block tag and capture the entire tag, including start/end delimiters
|
||||
tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
|
||||
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END)))
|
||||
tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
|
||||
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
|
||||
re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
|
||||
|
||||
# global dictionary of libraries that have been loaded using get_library
|
||||
libraries = {}
|
||||
@ -163,12 +167,12 @@ def compile_string(template_string, origin):
|
||||
|
||||
class Token(object):
|
||||
def __init__(self, token_type, contents):
|
||||
"The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK"
|
||||
"The token_type must be TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK or TOKEN_COMMENT"
|
||||
self.token_type, self.contents = token_type, contents
|
||||
|
||||
def __str__(self):
|
||||
return '<%s token: "%s...">' % \
|
||||
({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
|
||||
({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block', TOKEN_COMMENT: 'Comment'}[self.token_type],
|
||||
self.contents[:20].replace('\n', ''))
|
||||
|
||||
def split_contents(self):
|
||||
@ -191,6 +195,8 @@ class Lexer(object):
|
||||
token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip())
|
||||
elif token_string.startswith(BLOCK_TAG_START):
|
||||
token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip())
|
||||
elif token_string.startswith(COMMENT_TAG_START):
|
||||
token = Token(TOKEN_COMMENT, '')
|
||||
else:
|
||||
token = Token(TOKEN_TEXT, token_string)
|
||||
return token
|
||||
|
@ -1,7 +1,7 @@
|
||||
"Default tags used by the template system, available to all templates."
|
||||
|
||||
from django.template import Node, NodeList, Template, Context, resolve_variable
|
||||
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END
|
||||
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
|
||||
from django.template import get_library, Library, InvalidTemplateLibrary
|
||||
from django.conf import settings
|
||||
import sys
|
||||
@ -295,6 +295,8 @@ class TemplateTagNode(Node):
|
||||
'closevariable': VARIABLE_TAG_END,
|
||||
'openbrace': SINGLE_BRACE_START,
|
||||
'closebrace': SINGLE_BRACE_END,
|
||||
'opencomment': COMMENT_TAG_START,
|
||||
'closecomment': COMMENT_TAG_END,
|
||||
}
|
||||
|
||||
def __init__(self, tagtype):
|
||||
@ -831,6 +833,8 @@ def templatetag(parser, token):
|
||||
``closevariable`` ``}}``
|
||||
``openbrace`` ``{``
|
||||
``closebrace`` ``}``
|
||||
``opencomment`` ``{#``
|
||||
``closecomment`` ``#}``
|
||||
================== =======
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
|
@ -2,12 +2,18 @@ from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.http import HttpResponse, HttpResponsePermanentRedirect, HttpResponseGone
|
||||
|
||||
def direct_to_template(request, template, **kwargs):
|
||||
def direct_to_template(request, template, extra_context={}, **kwargs):
|
||||
"""
|
||||
Render a given template with any extra URL parameters in the context as
|
||||
``{{ params }}``.
|
||||
"""
|
||||
return render_to_response(template, {'params' : kwargs}, context_instance=RequestContext(request))
|
||||
dictionary = {'params': kwargs}
|
||||
for key, value in extra_context.items():
|
||||
if callable(value):
|
||||
dictionary[key] = value()
|
||||
else:
|
||||
dictionary[key] = value
|
||||
return render_to_response(template, dictionary, context_instance=RequestContext(request))
|
||||
|
||||
def redirect_to(request, url, **kwargs):
|
||||
"""
|
||||
@ -18,7 +24,7 @@ def redirect_to(request, url, **kwargs):
|
||||
``/foo/<id>/`` to ``/bar/<id>/``, you could use the following URLconf::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
('^foo/(?p<id>\d+)/$', 'django.views.generic.simple.redirect_to', {'url' : '/bar/%(id)s/'}),
|
||||
('^foo/(?P<id>\d+)/$', 'django.views.generic.simple.redirect_to', {'url' : '/bar/%(id)s/'}),
|
||||
)
|
||||
|
||||
If the given url is ``None``, a HttpResponseGone (410) will be issued.
|
||||
|
@ -876,15 +876,18 @@ The database API supports the following lookup types:
|
||||
exact
|
||||
~~~~~
|
||||
|
||||
Exact match.
|
||||
Exact match. If the value provided for comparison is ``None``, it will
|
||||
be interpreted as an SQL ``NULL`` (See isnull_ for more details).
|
||||
|
||||
Example::
|
||||
Examples::
|
||||
|
||||
Entry.objects.get(id__exact=14)
|
||||
Entry.objects.get(id__exact=None)
|
||||
|
||||
SQL equivalent::
|
||||
SQL equivalents::
|
||||
|
||||
SELECT ... WHERE id = 14;
|
||||
SELECT ... WHERE id = NULL;
|
||||
|
||||
iexact
|
||||
~~~~~~
|
||||
@ -1103,8 +1106,8 @@ such as January 3, July 3, etc.
|
||||
isnull
|
||||
~~~~~~
|
||||
|
||||
``NULL`` or ``IS NOT NULL`` match. Takes either ``True`` or ``False``, which
|
||||
correspond to ``IS NULL`` and ``IS NOT NULL``, respectively.
|
||||
Takes either ``True`` or ``False``, which correspond to SQL queries of
|
||||
``IS NULL`` and ``IS NOT NULL``, respectively.
|
||||
|
||||
Example::
|
||||
|
||||
@ -1114,6 +1117,14 @@ SQL equivalent::
|
||||
|
||||
SELECT ... WHERE pub_date IS NULL;
|
||||
|
||||
.. admonition:: ``__isnull=True`` vs ``__exact=None``
|
||||
|
||||
There is an important difference between ``__isnull=True`` and
|
||||
``__exact=None``. ``__exact=None`` will *always* return an empty result
|
||||
set, because SQL requires that no value is equal to ``NULL``.
|
||||
``__isnull`` determines if the field is currently holding the value
|
||||
of ``NULL`` without performing a comparison.
|
||||
|
||||
search
|
||||
~~~~~~
|
||||
|
||||
|
@ -227,9 +227,7 @@ When will you release Django 1.0?
|
||||
|
||||
Short answer: When we're comfortable with Django's APIs, have added all
|
||||
features that we feel are necessary to earn a "1.0" status, and are ready to
|
||||
begin maintaining backwards compatibility. This should happen in a couple of
|
||||
months or so, although it's entirely possible that it could happen earlier.
|
||||
That translates into summer 2006.
|
||||
begin maintaining backwards compatibility.
|
||||
|
||||
The merging of Django's `magic-removal branch`_ went a long way toward Django
|
||||
1.0.
|
||||
|
@ -211,7 +211,7 @@ Below is the finished view::
|
||||
def create_place(request):
|
||||
manipulator = Place.AddManipulator()
|
||||
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
# If data was POSTed, we're trying to create a new Place.
|
||||
new_data = request.POST.copy()
|
||||
|
||||
@ -309,7 +309,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
|
||||
# Grab the Place object in question for future use.
|
||||
place = manipulator.original_object
|
||||
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
new_data = request.POST.copy()
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
@ -391,7 +391,7 @@ Here's a simple function that might drive the above form::
|
||||
|
||||
def contact_form(request):
|
||||
manipulator = ContactManipulator()
|
||||
if request.POST:
|
||||
if request.method == 'POST':
|
||||
new_data = request.POST.copy()
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
@ -579,7 +579,7 @@ fails. If no message is passed in, a default message is used.
|
||||
``ValidateIfOtherFieldEquals``
|
||||
Takes three parameters: ``other_field``, ``other_value`` and
|
||||
``validator_list``, in that order. If ``other_field`` has a value of
|
||||
``other_vaue``, then the validators in ``validator_list`` are all run
|
||||
``other_value``, then the validators in ``validator_list`` are all run
|
||||
against the current field.
|
||||
|
||||
``RequiredIfOtherFieldNotGiven``
|
||||
|
@ -92,6 +92,13 @@ which is a dictionary of the parameters captured in the URL.
|
||||
|
||||
* ``template``: The full name of a template to use.
|
||||
|
||||
**Optional arguments:**
|
||||
|
||||
* ``extra_context``: A dictionary of values to add to the template
|
||||
context. By default, this is an empty dictionary. If a value in the
|
||||
dictionary is callable, the generic view will call it
|
||||
just before rendering the template.
|
||||
|
||||
**Example:**
|
||||
|
||||
Given the following URL patterns::
|
||||
@ -171,7 +178,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
|
||||
template. By default, it's ``django.template.loader``.
|
||||
|
||||
* ``extra_context``: A dictionary of values to add to the template
|
||||
context. By default, this is an empty dictionary.
|
||||
context. By default, this is an empty dictionary. If a value in the
|
||||
dictionary is callable, the generic view will call it
|
||||
just before rendering the template.
|
||||
|
||||
@ -184,7 +191,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
|
||||
the view's template. See the `RequestContext docs`_.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -270,7 +277,7 @@ to ``True``.
|
||||
this is ``False``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -357,7 +364,7 @@ date in the *future* are not displayed unless you set ``allow_future`` to
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -438,7 +445,7 @@ in the *future* are not displayed unless you set ``allow_future`` to ``True``.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -523,7 +530,7 @@ you set ``allow_future`` to ``True``.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -633,7 +640,7 @@ future, the view will throw a 404 error by default, unless you set
|
||||
to use in the template context. By default, this is ``'object'``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
* ``allow_future``: A boolean specifying whether to include "future"
|
||||
objects on this page, where "future" means objects in which the field
|
||||
@ -707,7 +714,7 @@ A page representing a list of objects.
|
||||
determining the variable's name.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
**Template name:**
|
||||
|
||||
@ -819,7 +826,7 @@ A page representing an individual object.
|
||||
to use in the template context. By default, this is ``'object'``.
|
||||
|
||||
* ``mimetype``: The MIME type to use for the resulting document. Defaults
|
||||
to the value of the ``DEFAULT_MIME_TYPE`` setting.
|
||||
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
|
||||
|
||||
**Template name:**
|
||||
|
||||
|
@ -84,9 +84,12 @@ Installing the official version
|
||||
|
||||
Note that the last command will automatically download and install setuptools_
|
||||
if you don't already have it installed. This requires a working Internet
|
||||
connection and may cause problems on Python 2.5. If you run into problems,
|
||||
try using our development version by following the instructions below. The
|
||||
development version no longer uses setuptools nor requires an Internet
|
||||
connection.
|
||||
|
||||
This will install Django in your Python installation's ``site-packages``
|
||||
The command will install Django in your Python installation's ``site-packages``
|
||||
directory.
|
||||
|
||||
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
|
||||
@ -94,19 +97,34 @@ directory.
|
||||
Installing the development version
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. Make sure you have Subversion_ installed.
|
||||
2. ``svn co http://code.djangoproject.com/svn/django/trunk/ django_src``
|
||||
3. Symlink ``django_src/django`` so that ``django`` is within your Python
|
||||
``site-packages`` directory:
|
||||
If you'd like to be able to update your Django code occasionally with the
|
||||
latest bug fixes and improvements, follow these instructions:
|
||||
|
||||
``ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django``
|
||||
1. Make sure you have Subversion_ installed.
|
||||
2. Check out the Django code into your Python ``site-packages`` directory.
|
||||
On Linux / Mac OSX / Unix, do this::
|
||||
|
||||
svn co http://code.djangoproject.com/svn/django/trunk/ django_src
|
||||
ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django
|
||||
|
||||
(In the above line, change ``python2.3`` to match your current Python version.)
|
||||
|
||||
You don't have to run ``python setup.py install``.
|
||||
On Windows, do this::
|
||||
|
||||
When you want to update your code, just run the command ``svn update`` from
|
||||
within the ``django_src`` directory.
|
||||
svn co http://code.djangoproject.com/svn/django/trunk/django c:\Python24\lib\site-packages\django
|
||||
|
||||
4. Copy the file ``django_src/django/bin/django-admin.py`` to somewhere on your
|
||||
system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
|
||||
(Windows). This step simply lets you type ``django-admin.py`` from within
|
||||
any directory, rather than having to qualify the command with the full path
|
||||
to the file.
|
||||
|
||||
You *don't* have to run ``python setup.py install``, because that command
|
||||
takes care of steps 3 and 4 for you.
|
||||
|
||||
When you want to update your copy of the Django source code, just run the
|
||||
command ``svn update`` from within the ``django`` directory. When you do this,
|
||||
Subversion will automatically download any changes.
|
||||
|
||||
.. _`download page`: http://www.djangoproject.com/download/
|
||||
.. _Subversion: http://subversion.tigris.org/
|
||||
|
@ -188,7 +188,8 @@ JavaScript shortcuts.
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
A ``CharField`` that checks that the value is a valid e-mail address.
|
||||
This doesn't accept ``maxlength``.
|
||||
This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to
|
||||
75.
|
||||
|
||||
``FileField``
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -43,6 +43,11 @@ This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
|
||||
Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE``
|
||||
so mod_python knows which settings to use.
|
||||
|
||||
Note that we're using the ``<Location>`` directive, not the ``<Directory>``
|
||||
directive. The latter is used for pointing at places on your filesystem,
|
||||
whereas ``<Location>`` points at places in the URL structure of a Web site.
|
||||
``<Directory>`` would be meaningless here.
|
||||
|
||||
Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
|
||||
on it, you'll need to tell mod_python::
|
||||
|
||||
|
@ -341,9 +341,9 @@ hard-coded strings. If you use this technique, follow these guidelines:
|
||||
Methods
|
||||
-------
|
||||
|
||||
``__init__(content='', mimetype=DEFAULT_MIME_TYPE)``
|
||||
``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)``
|
||||
Instantiates an ``HttpResponse`` object with the given page content (a
|
||||
string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``'text/html'``.
|
||||
string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``.
|
||||
|
||||
``content`` can be an iterator or a string. If it's an iterator, it should
|
||||
return strings, and those strings will be joined together to form the
|
||||
|
@ -528,7 +528,7 @@ any code that uses ``LANGUAGES`` at runtime.
|
||||
MANAGERS
|
||||
--------
|
||||
|
||||
Default: ``ADMINS`` (Whatever ``ADMINS`` is set to)
|
||||
Default: ``()`` (Empty tuple)
|
||||
|
||||
A tuple in the same format as ``ADMINS`` that specifies who should get
|
||||
broken-link notifications when ``SEND_BROKEN_LINK_EMAILS=True``.
|
||||
|
@ -109,6 +109,21 @@ Some tags require beginning and ending tags (i.e.
|
||||
below describes all the built-in tags. You can create your own tags, if you
|
||||
know how to write Python code.
|
||||
|
||||
Comments
|
||||
========
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
To comment-out part of a template, use the comment syntax: ``{# #}``.
|
||||
|
||||
For example, this template would render as ``'hello'``::
|
||||
|
||||
{# greeting #}hello
|
||||
|
||||
A comment can contain any template code, invalid or not. For example::
|
||||
|
||||
{# {% if foo %}bar{% else %} #}
|
||||
|
||||
Template inheritance
|
||||
====================
|
||||
|
||||
@ -785,8 +800,12 @@ The argument tells which template bit to output:
|
||||
``closevariable`` ``}}``
|
||||
``openbrace`` ``{``
|
||||
``closebrace`` ``}``
|
||||
``opencomment`` ``{#``
|
||||
``closecomment`` ``#}``
|
||||
================== =======
|
||||
|
||||
Note: ``opencomment`` and ``closecomment`` are new in the Django development version.
|
||||
|
||||
widthratio
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -212,6 +212,21 @@ template tags. If an invalid variable is provided to one of these template
|
||||
tags, the variable will be interpreted as ``None``. Filters are always
|
||||
applied to invalid variables within these template tags.
|
||||
|
||||
.. admonition:: For debug purposes only!
|
||||
|
||||
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
|
||||
it is a bad idea to turn it on as a 'development default'.
|
||||
|
||||
Many templates, including those in the Admin site, rely upon the
|
||||
silence of the template system when a non-existent variable is
|
||||
encountered. If you assign a value other than ``''`` to
|
||||
``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
|
||||
problems with these templates and sites.
|
||||
|
||||
Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
|
||||
in order to debug a specific template problem, then cleared
|
||||
once debugging is complete.
|
||||
|
||||
Playing with Context objects
|
||||
----------------------------
|
||||
|
||||
@ -296,6 +311,20 @@ optional, third positional argument, ``processors``. In this example, the
|
||||
'foo': 'bar',
|
||||
}, [ip_address_processor])
|
||||
|
||||
Note::
|
||||
If you're using Django's ``render_to_response()`` shortcut to populate a
|
||||
template with the contents of a dictionary, your template will be passed a
|
||||
``Context`` instance by default (not a ``RequestContext``). To use a
|
||||
``RequestContext`` in your template rendering, pass an optional third
|
||||
argument to ``render_to_response()``: a ``RequestContext``
|
||||
instance. Your code might look like this::
|
||||
|
||||
def some_view(request):
|
||||
# ...
|
||||
return render_to_response('my_template'html',
|
||||
my_data_dictionary,
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
Here's what each of the default processors does:
|
||||
|
||||
.. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects
|
||||
@ -1063,7 +1092,7 @@ Configuring the template system in standalone mode
|
||||
.. note::
|
||||
|
||||
This section is only of interest to people trying to use the template
|
||||
system as an output component in another application. If you are using the
|
||||
system as an output component in another application. If you're using the
|
||||
template system as part of a Django application, nothing here applies to
|
||||
you.
|
||||
|
||||
@ -1080,7 +1109,7 @@ described in the `settings file`_ documentation. Simply import the appropriate
|
||||
pieces of the templating system and then, *before* you call any of the
|
||||
templating functions, call ``django.conf.settings.configure()`` with any
|
||||
settings you wish to specify. You might want to consider setting at least
|
||||
``TEMPLATE_DIRS`` (if you are going to use template loaders),
|
||||
``TEMPLATE_DIRS`` (if you're going to use template loaders),
|
||||
``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
|
||||
``TEMPLATE_DEBUG``. All available settings are described in the
|
||||
`settings documentation`_, and any setting starting with *TEMPLATE_*
|
||||
|
@ -377,16 +377,16 @@ By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
|
||||
Django where our templates live::
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
"/home/mytemplates", # Change this to your own directory.
|
||||
"/home/my_username/mytemplates", # Change this to your own directory.
|
||||
)
|
||||
|
||||
Now copy the template ``admin/base_site.html`` from within the default Django
|
||||
admin template directory (``django/contrib/admin/templates``) into an ``admin``
|
||||
subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For
|
||||
example, if your ``TEMPLATE_DIRS`` includes ``"/home/mytemplates"``, as above,
|
||||
then copy ``django/contrib/admin/templates/admin/base_site.html`` to
|
||||
``/home/mytemplates/admin/base_site.html``. Don't forget that ``admin``
|
||||
subdirectory.
|
||||
example, if your ``TEMPLATE_DIRS`` includes ``"/home/my_username/mytemplates"``,
|
||||
as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to
|
||||
``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that
|
||||
``admin`` subdirectory.
|
||||
|
||||
Then, just edit the file and replace the generic Django text with your own
|
||||
site's name and URL as you see fit.
|
||||
|
@ -257,7 +257,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
|
||||
from mysite.polls.models import Poll
|
||||
|
||||
def index(request):
|
||||
latest_poll_list = Poll.objects.all().order_by('-pub_date')
|
||||
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
|
||||
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
|
||||
|
||||
Note that we no longer need to import ``loader``, ``Context`` or
|
||||
|
@ -192,13 +192,13 @@ objects" and "display a detail page for a particular type of object."
|
||||
``object_id`` for the generic views.
|
||||
|
||||
By default, the ``object_detail`` generic view uses a template called
|
||||
``<app name>/<module name>_detail.html``. In our case, it'll use the template
|
||||
``<app name>/<model name>_detail.html``. In our case, it'll use the template
|
||||
``"polls/poll_detail.html"``. Thus, rename your ``polls/detail.html`` template to
|
||||
``polls/poll_detail.html``, and change the ``render_to_response()`` line in
|
||||
``vote()``.
|
||||
|
||||
Similarly, the ``object_list`` generic view uses a template called
|
||||
``<app name>/<module name>_list.html``. Thus, rename ``polls/index.html`` to
|
||||
``<app name>/<model name>_list.html``. Thus, rename ``polls/index.html`` to
|
||||
``polls/poll_list.html``.
|
||||
|
||||
Because we have more than one entry in the URLconf that uses ``object_detail``
|
||||
|
217
ez_setup.py
217
ez_setup.py
@ -1,217 +0,0 @@
|
||||
#!python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
If you want to use setuptools in your package's setup.py, just include this
|
||||
file in the same directory with it, and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
If you want to require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, you can do so by supplying
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import sys
|
||||
DEFAULT_VERSION = "0.6c1"
|
||||
DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
||||
|
||||
md5_data = {
|
||||
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
||||
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
|
||||
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
|
||||
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
|
||||
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
|
||||
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
|
||||
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
|
||||
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
|
||||
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
|
||||
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
|
||||
}
|
||||
|
||||
import sys, os
|
||||
|
||||
def _validate_md5(egg_name, data):
|
||||
if egg_name in md5_data:
|
||||
from md5 import md5
|
||||
digest = md5(data).hexdigest()
|
||||
if digest != md5_data[egg_name]:
|
||||
print >>sys.stderr, (
|
||||
"md5 validation of %s failed! (Possible download problem?)"
|
||||
% egg_name
|
||||
)
|
||||
sys.exit(2)
|
||||
return data
|
||||
|
||||
|
||||
def use_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
download_delay=15
|
||||
):
|
||||
"""Automatically find/download setuptools and make it available on sys.path
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end with
|
||||
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
|
||||
it is not already available. If `download_delay` is specified, it should
|
||||
be the number of seconds that will be paused before initiating a download,
|
||||
should one be required. If an older version of setuptools is installed,
|
||||
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
||||
an attempt to abort the calling script.
|
||||
"""
|
||||
try:
|
||||
import setuptools
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
print >>sys.stderr, (
|
||||
"You have an obsolete version of setuptools installed. Please\n"
|
||||
"remove it from your system entirely before rerunning this script."
|
||||
)
|
||||
sys.exit(2)
|
||||
except ImportError:
|
||||
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
||||
sys.path.insert(0, egg)
|
||||
import setuptools; setuptools.bootstrap_install_from = egg
|
||||
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require("setuptools>="+version)
|
||||
|
||||
except pkg_resources.VersionConflict:
|
||||
# XXX could we install in a subprocess here?
|
||||
print >>sys.stderr, (
|
||||
"The required version of setuptools (>=%s) is not available, and\n"
|
||||
"can't be installed while this script is running. Please install\n"
|
||||
" a more recent version first."
|
||||
) % version
|
||||
sys.exit(2)
|
||||
|
||||
def download_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
delay = 15
|
||||
):
|
||||
"""Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download attempt.
|
||||
"""
|
||||
import urllib2, shutil
|
||||
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
|
||||
url = download_base + egg_name
|
||||
saveto = os.path.join(to_dir, egg_name)
|
||||
src = dst = None
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
try:
|
||||
from distutils import log
|
||||
if delay:
|
||||
log.warn("""
|
||||
---------------------------------------------------------------------------
|
||||
This script requires setuptools version %s to run (even to display
|
||||
help). I will attempt to download it for you (from
|
||||
%s), but
|
||||
you may need to enable firewall access for this script first.
|
||||
I will start the download in %d seconds.
|
||||
|
||||
(Note: if this machine does not have network access, please obtain the file
|
||||
|
||||
%s
|
||||
|
||||
and place it in this directory before rerunning this script.)
|
||||
---------------------------------------------------------------------------""",
|
||||
version, download_base, delay, url
|
||||
); from time import sleep; sleep(delay)
|
||||
log.warn("Downloading %s", url)
|
||||
src = urllib2.urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
data = _validate_md5(egg_name, src.read())
|
||||
dst = open(saveto,"wb"); dst.write(data)
|
||||
finally:
|
||||
if src: src.close()
|
||||
if dst: dst.close()
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
def main(argv, version=DEFAULT_VERSION):
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
|
||||
try:
|
||||
import setuptools
|
||||
except ImportError:
|
||||
import tempfile, shutil
|
||||
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
|
||||
try:
|
||||
egg = download_setuptools(version, to_dir=tmpdir, delay=0)
|
||||
sys.path.insert(0,egg)
|
||||
from setuptools.command.easy_install import main
|
||||
return main(list(argv)+[egg]) # we're done here
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
else:
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
# tell the user to uninstall obsolete version
|
||||
use_setuptools(version)
|
||||
|
||||
req = "setuptools>="+version
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require(req)
|
||||
except pkg_resources.VersionConflict:
|
||||
try:
|
||||
from setuptools.command.easy_install import main
|
||||
except ImportError:
|
||||
from easy_install import main
|
||||
main(list(argv)+[download_setuptools(delay=0)])
|
||||
sys.exit(0) # try to force an exit
|
||||
else:
|
||||
if argv:
|
||||
from setuptools.command.easy_install import main
|
||||
main(argv)
|
||||
else:
|
||||
print "Setuptools version",version,"or greater has been installed."
|
||||
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
||||
|
||||
|
||||
|
||||
def update_md5(filenames):
|
||||
"""Update our built-in md5 registry"""
|
||||
|
||||
import re
|
||||
from md5 import md5
|
||||
|
||||
for name in filenames:
|
||||
base = os.path.basename(name)
|
||||
f = open(name,'rb')
|
||||
md5_data[base] = md5(f.read()).hexdigest()
|
||||
f.close()
|
||||
|
||||
data = [" %r: %r,\n" % it for it in md5_data.items()]
|
||||
data.sort()
|
||||
repl = "".join(data)
|
||||
|
||||
import inspect
|
||||
srcfile = inspect.getsourcefile(sys.modules[__name__])
|
||||
f = open(srcfile, 'rb'); src = f.read(); f.close()
|
||||
|
||||
match = re.search("\nmd5_data = {\n([^}]+)}", src)
|
||||
if not match:
|
||||
print >>sys.stderr, "Internal error!"
|
||||
sys.exit(2)
|
||||
|
||||
src = src[:match.start(1)] + repl + src[match.end(1):]
|
||||
f = open(srcfile,'w')
|
||||
f.write(src)
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
|
||||
update_md5(sys.argv[2:])
|
||||
else:
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
|
||||
|
||||
|
45
setup.py
45
setup.py
@ -1,7 +1,25 @@
|
||||
import ez_setup # From http://peak.telecommunity.com/DevCenter/setuptools
|
||||
ez_setup.use_setuptools()
|
||||
from distutils.core import setup
|
||||
from distutils.command.install import INSTALL_SCHEMES
|
||||
import os
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
# Tell distutils to put the data_files in platform-specific installation
|
||||
# locations. See here for an explanation:
|
||||
# http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb
|
||||
for scheme in INSTALL_SCHEMES.values():
|
||||
scheme['data'] = scheme['purelib']
|
||||
|
||||
# Compile the list of packages available, because distutils doesn't have
|
||||
# an easy way to do this.
|
||||
packages, data_files = [], []
|
||||
root_dir = os.path.join(os.path.dirname(__file__), 'django')
|
||||
for dirpath, dirnames, filenames in os.walk(root_dir):
|
||||
# Ignore dirnames that start with '.'
|
||||
for i, dirname in enumerate(dirnames):
|
||||
if dirname.startswith('.'): del dirnames[i]
|
||||
if '__init__.py' in filenames:
|
||||
packages.append(dirpath.replace('/', '.'))
|
||||
else:
|
||||
data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames]))
|
||||
|
||||
setup(
|
||||
name = "Django",
|
||||
@ -10,24 +28,7 @@ setup(
|
||||
author = 'Lawrence Journal-World',
|
||||
author_email = 'holovaty@gmail.com',
|
||||
description = 'A high-level Python Web framework that encourages rapid development and clean, pragmatic design.',
|
||||
license = 'BSD',
|
||||
packages = find_packages(exclude=['examples', 'examples.*']),
|
||||
package_data = {
|
||||
'': ['*.TXT'],
|
||||
'django.conf': ['locale/*/LC_MESSAGES/*'],
|
||||
'django.contrib.admin': ['templates/admin/*.html',
|
||||
'templates/admin/auth/user/*.html',
|
||||
'templates/admin_doc/*.html',
|
||||
'templates/registration/*.html',
|
||||
'templates/widget/*.html',
|
||||
'media/css/*.css',
|
||||
'media/img/admin/*.gif',
|
||||
'media/img/admin/*.png',
|
||||
'media/js/*.js',
|
||||
'media/js/admin/*js'],
|
||||
'django.contrib.comments': ['templates/comments/*.html'],
|
||||
'django.contrib.sitemaps': ['templates/*.xml'],
|
||||
},
|
||||
packages = packages,
|
||||
data_files = data_files,
|
||||
scripts = ['django/bin/django-admin.py'],
|
||||
zip_safe = False,
|
||||
)
|
||||
|
0
tests/regressiontests/forms/__init__.py
Normal file
0
tests/regressiontests/forms/__init__.py
Normal file
0
tests/regressiontests/forms/models.py
Normal file
0
tests/regressiontests/forms/models.py
Normal file
481
tests/regressiontests/forms/tests.py
Normal file
481
tests/regressiontests/forms/tests.py
Normal file
@ -0,0 +1,481 @@
|
||||
"""
|
||||
>>> from django.newforms import *
|
||||
>>> import datetime
|
||||
>>> import re
|
||||
|
||||
# TextInput Widget ############################################################
|
||||
|
||||
>>> w = TextInput()
|
||||
>>> w.render('email', '')
|
||||
u'<input type="text" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="text" name="email" />'
|
||||
>>> w.render('email', 'test@example.com')
|
||||
u'<input type="text" name="email" value="test@example.com" />'
|
||||
>>> w.render('email', 'some "quoted" & ampersanded value')
|
||||
u'<input type="text" name="email" value="some "quoted" & ampersanded value" />'
|
||||
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
|
||||
u'<input type="text" name="email" value="test@example.com" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = TextInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', '')
|
||||
u'<input type="text" class="fun" name="email" />'
|
||||
>>> w.render('email', 'foo@example.com')
|
||||
u'<input type="text" class="fun" value="foo@example.com" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = TextInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', '', attrs={'class': 'special'})
|
||||
u'<input type="text" class="special" name="email" />'
|
||||
|
||||
# Textarea Widget #############################################################
|
||||
|
||||
>>> w = Textarea()
|
||||
>>> w.render('msg', '')
|
||||
u'<textarea name="msg"></textarea>'
|
||||
>>> w.render('msg', None)
|
||||
u'<textarea name="msg"></textarea>'
|
||||
>>> w.render('msg', 'value')
|
||||
u'<textarea name="msg">value</textarea>'
|
||||
>>> w.render('msg', 'some "quoted" & ampersanded value')
|
||||
u'<textarea name="msg">some "quoted" & ampersanded value</textarea>'
|
||||
>>> w.render('msg', 'value', attrs={'class': 'pretty'})
|
||||
u'<textarea name="msg" class="pretty">value</textarea>'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = Textarea(attrs={'class': 'pretty'})
|
||||
>>> w.render('msg', '')
|
||||
u'<textarea class="pretty" name="msg"></textarea>'
|
||||
>>> w.render('msg', 'example')
|
||||
u'<textarea class="pretty" name="msg">example</textarea>'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = Textarea(attrs={'class': 'pretty'})
|
||||
>>> w.render('msg', '', attrs={'class': 'special'})
|
||||
u'<textarea class="special" name="msg"></textarea>'
|
||||
|
||||
# CheckboxInput Widget ########################################################
|
||||
|
||||
>>> w = CheckboxInput()
|
||||
>>> w.render('is_cool', '')
|
||||
u'<input type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', False)
|
||||
u'<input type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', True)
|
||||
u'<input checked="checked" type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', False, attrs={'class': 'pretty'})
|
||||
u'<input type="checkbox" name="is_cool" class="pretty" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = CheckboxInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('is_cool', '')
|
||||
u'<input type="checkbox" class="pretty" name="is_cool" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = CheckboxInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('is_cool', '', attrs={'class': 'special'})
|
||||
u'<input type="checkbox" class="special" name="is_cool" />'
|
||||
|
||||
# CharField ###################################################################
|
||||
|
||||
>>> f = CharField(required=False)
|
||||
>>> f.to_python(1)
|
||||
u'1'
|
||||
>>> f.to_python('hello')
|
||||
u'hello'
|
||||
>>> f.to_python(None)
|
||||
u''
|
||||
>>> f.to_python([1, 2, 3])
|
||||
u'[1, 2, 3]'
|
||||
|
||||
CharField accepts an optional max_length parameter:
|
||||
>>> f = CharField(max_length=10, required=False)
|
||||
>>> f.to_python('')
|
||||
u''
|
||||
>>> f.to_python('12345')
|
||||
u'12345'
|
||||
>>> f.to_python('1234567890')
|
||||
u'1234567890'
|
||||
>>> f.to_python('1234567890a')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at most 10 characters.']
|
||||
|
||||
CharField accepts an optional min_length parameter:
|
||||
>>> f = CharField(min_length=10, required=False)
|
||||
>>> f.to_python('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at least 10 characters.']
|
||||
>>> f.to_python('12345')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at least 10 characters.']
|
||||
>>> f.to_python('1234567890')
|
||||
u'1234567890'
|
||||
>>> f.to_python('1234567890a')
|
||||
u'1234567890a'
|
||||
|
||||
# IntegerField ################################################################
|
||||
|
||||
>>> f = IntegerField()
|
||||
>>> f.to_python('1')
|
||||
1
|
||||
>>> isinstance(f.to_python('1'), int)
|
||||
True
|
||||
>>> f.to_python('23')
|
||||
23
|
||||
>>> f.to_python('a')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a whole number.']
|
||||
>>> f.to_python('1 ')
|
||||
1
|
||||
>>> f.to_python(' 1')
|
||||
1
|
||||
>>> f.to_python(' 1 ')
|
||||
1
|
||||
>>> f.to_python('1a')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a whole number.']
|
||||
|
||||
# DateField ###################################################################
|
||||
|
||||
>>> import datetime
|
||||
>>> f = DateField()
|
||||
>>> f.to_python(datetime.date(2006, 10, 25))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('2006-10-25')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('10/25/2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('10/25/06')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('Oct 25 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('October 25 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('October 25, 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('25 October 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('25 October, 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('2006-4-31')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.to_python('200a-10-25')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.to_python('25/10/06')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.to_python(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = DateField(required=False)
|
||||
>>> f.to_python(None)
|
||||
>>> repr(f.to_python(None))
|
||||
'None'
|
||||
>>> f.to_python('')
|
||||
>>> repr(f.to_python(''))
|
||||
'None'
|
||||
|
||||
DateField accepts an optional input_formats parameter:
|
||||
>>> f = DateField(input_formats=['%Y %m %d'])
|
||||
>>> f.to_python(datetime.date(2006, 10, 25))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.to_python('2006 10 25')
|
||||
datetime.date(2006, 10, 25)
|
||||
|
||||
The input_formats parameter overrides all default input formats,
|
||||
so the default formats won't work unless you specify them:
|
||||
>>> f.to_python('2006-10-25')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.to_python('10/25/2006')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.to_python('10/25/06')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
|
||||
# DateTimeField ###############################################################
|
||||
|
||||
>>> import datetime
|
||||
>>> f = DateTimeField()
|
||||
>>> f.to_python(datetime.date(2006, 10, 25))
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
|
||||
>>> f.to_python('2006-10-25 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.to_python('2006-10-25 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('2006-10-25 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('2006-10-25')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.to_python('10/25/2006 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.to_python('10/25/2006 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('10/25/2006 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('10/25/2006')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.to_python('10/25/06 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.to_python('10/25/06 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('10/25/06 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python('10/25/06')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.to_python('hello')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
>>> f.to_python('2006-10-25 4:30 p.m.')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
|
||||
DateField accepts an optional input_formats parameter:
|
||||
>>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
|
||||
>>> f.to_python(datetime.date(2006, 10, 25))
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59)
|
||||
>>> f.to_python(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
|
||||
>>> f.to_python('2006 10 25 2:30 PM')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
|
||||
The input_formats parameter overrides all default input formats,
|
||||
so the default formats won't work unless you specify them:
|
||||
>>> f.to_python('2006-10-25 14:30:45')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
|
||||
# RegexField ##################################################################
|
||||
|
||||
>>> f = RegexField('^\d[A-F]\d$')
|
||||
>>> f.to_python('2A2')
|
||||
u'2A2'
|
||||
>>> f.to_python('3F3')
|
||||
u'3F3'
|
||||
>>> f.to_python('3G3')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
>>> f.to_python(' 2A2')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
>>> f.to_python('2A2 ')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
|
||||
Alternatively, RegexField can take a compiled regular expression:
|
||||
>>> f = RegexField(re.compile('^\d[A-F]\d$'))
|
||||
>>> f.to_python('2A2')
|
||||
u'2A2'
|
||||
>>> f.to_python('3F3')
|
||||
u'3F3'
|
||||
>>> f.to_python('3G3')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
>>> f.to_python(' 2A2')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
>>> f.to_python('2A2 ')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid value.']
|
||||
|
||||
RegexField takes an optional error_message argument:
|
||||
>>> f = RegexField('^\d\d\d\d$', 'Enter a four-digit number.')
|
||||
>>> f.to_python('1234')
|
||||
u'1234'
|
||||
>>> f.to_python('123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a four-digit number.']
|
||||
>>> f.to_python('abcd')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a four-digit number.']
|
||||
|
||||
# EmailField ##################################################################
|
||||
|
||||
>>> f = EmailField()
|
||||
>>> f.to_python('person@example.com')
|
||||
u'person@example.com'
|
||||
>>> f.to_python('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid e-mail address.']
|
||||
>>> f.to_python('foo@')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid e-mail address.']
|
||||
>>> f.to_python('foo@bar')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid e-mail address.']
|
||||
|
||||
# BooleanField ################################################################
|
||||
|
||||
>>> f = BooleanField()
|
||||
>>> f.to_python(True)
|
||||
True
|
||||
>>> f.to_python(False)
|
||||
False
|
||||
>>> f.to_python(1)
|
||||
True
|
||||
>>> f.to_python(0)
|
||||
False
|
||||
>>> f.to_python('Django rocks')
|
||||
True
|
||||
|
||||
# Form ########################################################################
|
||||
|
||||
>>> class Person(Form):
|
||||
... first_name = CharField()
|
||||
... last_name = CharField()
|
||||
... birthday = DateField()
|
||||
>>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'})
|
||||
>>> p.errors()
|
||||
{}
|
||||
>>> p.is_valid()
|
||||
True
|
||||
>>> p.errors().as_ul()
|
||||
u''
|
||||
>>> p.errors().as_text()
|
||||
u''
|
||||
>>> p.to_python()
|
||||
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
|
||||
>>> print p['first_name']
|
||||
<input type="text" name="first_name" value="John" />
|
||||
>>> print p['last_name']
|
||||
<input type="text" name="last_name" value="Lennon" />
|
||||
>>> print p['birthday']
|
||||
<input type="text" name="birthday" value="1940-10-9" />
|
||||
>>> for boundfield in p:
|
||||
... print boundfield
|
||||
<input type="text" name="first_name" value="John" />
|
||||
<input type="text" name="last_name" value="Lennon" />
|
||||
<input type="text" name="birthday" value="1940-10-9" />
|
||||
|
||||
>>> p = Person({'last_name': u'Lennon'})
|
||||
>>> p.errors()
|
||||
{'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
|
||||
>>> p.is_valid()
|
||||
False
|
||||
>>> p.errors().as_ul()
|
||||
u'<ul class="errorlist"><li>first_name<ul class="errorlist"><li>This field is required.</li></ul></li><li>birthday<ul class="errorlist"><li>This field is required.</li></ul></li></ul>'
|
||||
>>> print p.errors().as_text()
|
||||
* first_name
|
||||
* This field is required.
|
||||
* birthday
|
||||
* This field is required.
|
||||
>>> p.to_python()
|
||||
>>> repr(p.to_python())
|
||||
'None'
|
||||
>>> p['first_name'].errors
|
||||
[u'This field is required.']
|
||||
>>> p['first_name'].errors.as_ul()
|
||||
u'<ul class="errorlist"><li>This field is required.</li></ul>'
|
||||
>>> p['first_name'].errors.as_text()
|
||||
u'* This field is required.'
|
||||
|
||||
>>> p = Person()
|
||||
>>> print p['first_name']
|
||||
<input type="text" name="first_name" />
|
||||
>>> print p['last_name']
|
||||
<input type="text" name="last_name" />
|
||||
>>> print p['birthday']
|
||||
<input type="text" name="birthday" />
|
||||
|
||||
>>> class SignupForm(Form):
|
||||
... email = EmailField()
|
||||
... get_spam = BooleanField()
|
||||
>>> f = SignupForm()
|
||||
>>> print f['email']
|
||||
<input type="text" name="email" />
|
||||
>>> print f['get_spam']
|
||||
<input type="checkbox" name="get_spam" />
|
||||
|
||||
>>> f = SignupForm({'email': 'test@example.com', 'get_spam': True})
|
||||
>>> print f['email']
|
||||
<input type="text" name="email" value="test@example.com" />
|
||||
>>> print f['get_spam']
|
||||
<input checked="checked" type="checkbox" name="get_spam" />
|
||||
|
||||
Any Field can have a Widget class passed to its constructor:
|
||||
>>> class ContactForm(Form):
|
||||
... subject = CharField()
|
||||
... message = CharField(widget=Textarea)
|
||||
>>> f = ContactForm()
|
||||
>>> print f['subject']
|
||||
<input type="text" name="subject" />
|
||||
>>> print f['message']
|
||||
<textarea name="message"></textarea>
|
||||
|
||||
as_textarea() and as_text() are shortcuts for changing the output widget type:
|
||||
>>> f['subject'].as_textarea()
|
||||
u'<textarea name="subject"></textarea>'
|
||||
>>> f['message'].as_text()
|
||||
u'<input type="text" name="message" />'
|
||||
|
||||
The 'widget' parameter to a Field can also be an instance:
|
||||
>>> class ContactForm(Form):
|
||||
... subject = CharField()
|
||||
... message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20}))
|
||||
>>> f = ContactForm()
|
||||
>>> print f['message']
|
||||
<textarea rows="80" cols="20" name="message"></textarea>
|
||||
|
||||
Instance-level attrs are *not* carried over to as_textarea() and as_text():
|
||||
>>> f['message'].as_text()
|
||||
u'<input type="text" name="message" />'
|
||||
>>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'})
|
||||
>>> f['subject'].as_textarea()
|
||||
u'<textarea name="subject">Hello</textarea>'
|
||||
>>> f['message'].as_text()
|
||||
u'<input type="text" name="message" value="I love you." />'
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
0
tests/regressiontests/null_queries/__init__.py
Normal file
0
tests/regressiontests/null_queries/__init__.py
Normal file
54
tests/regressiontests/null_queries/models.py
Normal file
54
tests/regressiontests/null_queries/models.py
Normal file
@ -0,0 +1,54 @@
|
||||
from django.db import models
|
||||
|
||||
class Poll(models.Model):
|
||||
question = models.CharField(maxlength=200)
|
||||
|
||||
def __str__(self):
|
||||
return "Q: %s " % self.question
|
||||
|
||||
class Choice(models.Model):
|
||||
poll = models.ForeignKey(Poll)
|
||||
choice = models.CharField(maxlength=200)
|
||||
|
||||
def __str__(self):
|
||||
return "Choice: %s in poll %s" % (self.choice, self.poll)
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Regression test for the use of None as a query value. None is interpreted as
|
||||
# an SQL NULL, but only in __exact queries.
|
||||
# Set up some initial polls and choices
|
||||
>>> p1 = Poll(question='Why?')
|
||||
>>> p1.save()
|
||||
>>> c1 = Choice(poll=p1, choice='Because.')
|
||||
>>> c1.save()
|
||||
>>> c2 = Choice(poll=p1, choice='Why Not?')
|
||||
>>> c2.save()
|
||||
|
||||
# Exact query with value None returns nothing (=NULL in sql)
|
||||
>>> Choice.objects.filter(id__exact=None)
|
||||
[]
|
||||
|
||||
# Valid query, but fails because foo isn't a keyword
|
||||
>>> Choice.objects.filter(foo__exact=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Cannot resolve keyword 'foo' into field
|
||||
|
||||
# Can't use None on anything other than __exact
|
||||
>>> Choice.objects.filter(id__gt=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Cannot use None as a query value
|
||||
|
||||
# Can't use None on anything other than __exact
|
||||
>>> Choice.objects.filter(foo__gt=None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Cannot use None as a query value
|
||||
|
||||
# Related managers use __exact=None implicitly if the object hasn't been saved.
|
||||
>>> p2 = Poll(question="How?")
|
||||
>>> p2.choice_set.all()
|
||||
[]
|
||||
|
||||
"""}
|
@ -16,9 +16,9 @@ class MockHandler(WSGIHandler):
|
||||
self.test = test
|
||||
super(MockHandler, self).__init__()
|
||||
|
||||
def get_response(self, path, request):
|
||||
def get_response(self, request):
|
||||
# debug("mock handler answering %s, %s", path, request)
|
||||
return HttpResponse(self.test(path, request))
|
||||
return HttpResponse(self.test(request))
|
||||
|
||||
|
||||
def debug(*arg):
|
||||
@ -50,7 +50,7 @@ class TestRequestIsolation(unittest.TestCase):
|
||||
env['PATH_INFO'] = '/'
|
||||
env['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
def request_one(path, request):
|
||||
def request_one(request):
|
||||
"""Start out with settings as originally configured"""
|
||||
self.assertEqual(model_connection_name(MX), '_a')
|
||||
self.assertEqual(
|
||||
@ -61,7 +61,7 @@ class TestRequestIsolation(unittest.TestCase):
|
||||
MY._default_manager.db.connection.settings.DATABASE_NAME,
|
||||
settings.OTHER_DATABASES['_b']['DATABASE_NAME'])
|
||||
|
||||
def request_two(path, request):
|
||||
def request_two(request):
|
||||
"""Between the first and second requests, settings change to assign
|
||||
model MY to a different connection
|
||||
"""
|
||||
@ -74,7 +74,7 @@ class TestRequestIsolation(unittest.TestCase):
|
||||
MY._default_manager.db.connection.settings.DATABASE_NAME,
|
||||
settings.DATABASE_NAME)
|
||||
|
||||
def request_three(path, request):
|
||||
def request_three(request):
|
||||
"""Between the 2nd and 3rd requests, the settings at the names in
|
||||
OTHER_DATABASES have changed.
|
||||
"""
|
||||
|
@ -173,6 +173,22 @@ class Templates(unittest.TestCase):
|
||||
# Empty strings can be passed as arguments to filters
|
||||
'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),
|
||||
|
||||
### COMMENT SYNTAX ########################################################
|
||||
'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
|
||||
'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),
|
||||
|
||||
# Comments can contain invalid stuff.
|
||||
'comment-syntax03': ("foo{# {% if %} #}", {}, "foo"),
|
||||
'comment-syntax04': ("foo{# {% endblock %} #}", {}, "foo"),
|
||||
'comment-syntax05': ("foo{# {% somerandomtag %} #}", {}, "foo"),
|
||||
'comment-syntax06': ("foo{# {% #}", {}, "foo"),
|
||||
'comment-syntax07': ("foo{# %} #}", {}, "foo"),
|
||||
'comment-syntax08': ("foo{# %} #}bar", {}, "foobar"),
|
||||
'comment-syntax09': ("foo{# {{ #}", {}, "foo"),
|
||||
'comment-syntax10': ("foo{# }} #}", {}, "foo"),
|
||||
'comment-syntax11': ("foo{# { #}", {}, "foo"),
|
||||
'comment-syntax12': ("foo{# } #}", {}, "foo"),
|
||||
|
||||
### COMMENT TAG ###########################################################
|
||||
'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
|
||||
'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
|
||||
@ -536,6 +552,8 @@ class Templates(unittest.TestCase):
|
||||
'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
|
||||
'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
|
||||
'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
|
||||
'templatetag11': ('{% templatetag opencomment %}', {}, '{#'),
|
||||
'templatetag12': ('{% templatetag closecomment %}', {}, '#}'),
|
||||
|
||||
### WIDTHRATIO TAG ########################################################
|
||||
'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
|
||||
|
@ -147,7 +147,7 @@ class TestThreadIsolation(unittest.TestCase):
|
||||
finally:
|
||||
self.lock.release()
|
||||
|
||||
def request_one(self, path, request):
|
||||
def request_one(self, request):
|
||||
"""Start out with settings as originally configured"""
|
||||
from django.conf import settings
|
||||
debug("request_one: %s", settings.OTHER_DATABASES)
|
||||
@ -169,7 +169,7 @@ class TestThreadIsolation(unittest.TestCase):
|
||||
self.assertEqual(connection.settings.DATABASE_NAME,
|
||||
settings.DATABASE_NAME)
|
||||
|
||||
def request_two(self, path, request):
|
||||
def request_two(self, request):
|
||||
"""Between the first and second requests, settings change to assign
|
||||
model MY to a different connection
|
||||
"""
|
||||
@ -196,7 +196,7 @@ class TestThreadIsolation(unittest.TestCase):
|
||||
except:
|
||||
self.add_thread_error(sys.exc_info())
|
||||
|
||||
def request_three(self, path, request):
|
||||
def request_three(self, request):
|
||||
"""Between the 2nd and 3rd requests, the settings at the names in
|
||||
OTHER_DATABASES have changed.
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user