1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +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:
Jason Pellerin 2006-12-04 19:58:49 +00:00
parent 2a58209ff2
commit 040f2272e0
53 changed files with 2939 additions and 1702 deletions

View File

@ -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
View 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

View File

@ -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')),

View File

@ -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 字まで)"

File diff suppressed because it is too large Load Diff

Binary file not shown.

View 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"

View File

@ -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>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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,
@ -126,7 +126,7 @@ class User(models.Model):
def is_anonymous(self):
"Always returns False. This is a way of comparing User objects to anonymous users."
return False
def is_authenticated(self):
"""Always return True. This is a way to tell if the user has been authenticated in templates.
"""
@ -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
@ -301,6 +310,6 @@ class AnonymousUser(object):
def is_anonymous(self):
return True
def is_authenticated(self):
return False

View File

@ -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'):

View File

@ -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'
}

View File

@ -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,21 +243,9 @@ 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."
return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app)
@ -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,13 +482,14 @@ 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'
if confirm == 'yes':
try:
cursor = connection.cursor()
@ -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()
shutil.copymode(path_old, path_new)
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."

View File

@ -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

View File

@ -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

View File

@ -727,30 +727,35 @@ 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).
# The second-last is the table column on which the lookup_type is
# to be performed. If this name is 'pk', it will be substituted with
# the name of the primary key.
# If there is only one part, or the last part is not a query
# term, assume that the query is an __exact
lookup_type = path.pop()
if lookup_type == 'pk':
lookup_type = 'exact'
path.append(None)
elif len(path) == 0 or lookup_type not in QUERY_TERMS:
path.append(lookup_type)
lookup_type = 'exact'
path = kwarg.split(LOOKUP_SEPARATOR)
# Extract the last elements of the kwarg.
# The very-last is the lookup_type (equals, like, etc).
# The second-last is the table column on which the lookup_type is
# to be performed. If this name is 'pk', it will be substituted with
# the name of the primary key.
# If there is only one part, or the last part is not a query
# term, assume that the query is an __exact
lookup_type = path.pop()
if lookup_type == 'pk':
lookup_type = 'exact'
path.append(None)
elif len(path) == 0 or lookup_type not in QUERY_TERMS:
path.append(lookup_type)
lookup_type = 'exact'
if len(path) < 1:
raise TypeError, "Cannot parse keyword query %r" % kwarg
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)
params.extend(params2)
joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
joins.update(joins2)
where.extend(where2)
params.extend(params2)
return joins, where, params
class FieldFound(Exception):

View 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
View 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
View 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
View 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)

View 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)

View File

@ -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="&lt;unknown source&gt;"
# 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

View File

@ -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()

View File

@ -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.

View File

@ -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
~~~~~~

View File

@ -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.

View File

@ -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``

View File

@ -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:**

View File

@ -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/

View File

@ -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``
~~~~~~~~~~~~~

View File

@ -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::

View File

@ -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

View File

@ -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``.

View File

@ -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
~~~~~~~~~~

View File

@ -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_*

View File

@ -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.

View File

@ -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

View File

@ -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``

View File

@ -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:])

View File

@ -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,
)

View File

View File

View 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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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()

View 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()
[]
"""}

View File

@ -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.
"""

View File

@ -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"),
@ -473,7 +489,7 @@ class Templates(unittest.TestCase):
'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
### HANDLING OF TEMPLATE_TAG_IF_INVALID ###################################
'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')),
'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''),
@ -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'),
@ -606,20 +624,20 @@ class Templates(unittest.TestCase):
# Turn TEMPLATE_DEBUG off, because tests assume that.
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
# Set TEMPLATE_STRING_IF_INVALID to a known string
# Set TEMPLATE_STRING_IF_INVALID to a known string
old_invalid = settings.TEMPLATE_STRING_IF_INVALID
for name, vals in tests:
install()
if isinstance(vals[2], tuple):
normal_string_result = vals[2][0]
invalid_string_result = vals[2][1]
else:
normal_string_result = vals[2]
invalid_string_result = vals[2]
if 'LANGUAGE_CODE' in vals[1]:
activate(vals[1]['LANGUAGE_CODE'])
else:
@ -636,10 +654,10 @@ class Templates(unittest.TestCase):
continue
if output != result:
failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output))
if 'LANGUAGE_CODE' in vals[1]:
deactivate()
loader.template_source_loaders = old_template_loaders
deactivate()
settings.TEMPLATE_DEBUG = old_td

View File

@ -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.
"""