1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

sqlalchemy: Merged revisions 3918 to 4053 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@4054 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robin Munn 2006-11-08 04:50:01 +00:00
parent 0b059aa4ea
commit dadfca08c0
78 changed files with 2352 additions and 422 deletions

View File

@ -83,6 +83,7 @@ answer newbie questions, and generally made Django that much better:
Simon Greenhill <dev@simon.net.nz> Simon Greenhill <dev@simon.net.nz>
Espen Grindhaug <http://grindhaug.org/> Espen Grindhaug <http://grindhaug.org/>
Brant Harris Brant Harris
Hawkeye
heckj@mac.com heckj@mac.com
Joel Heenan <joelh-django@planetjoel.com> Joel Heenan <joelh-django@planetjoel.com>
hipertracker@gmail.com hipertracker@gmail.com
@ -90,6 +91,7 @@ answer newbie questions, and generally made Django that much better:
Kieran Holland <http://www.kieranholland.com> Kieran Holland <http://www.kieranholland.com>
Robert Rock Howard <http://djangomojo.com/> Robert Rock Howard <http://djangomojo.com/>
Jason Huggins <http://www.jrandolph.com/blog/> Jason Huggins <http://www.jrandolph.com/blog/>
Baurzhan Ismagulov <ibr@radix50.net>
jcrasta@gmail.com jcrasta@gmail.com
Michael Josephson <http://www.sdjournal.com/> Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com jpellerin@gmail.com
@ -105,17 +107,19 @@ answer newbie questions, and generally made Django that much better:
lakin.wecker@gmail.com lakin.wecker@gmail.com
Stuart Langridge <http://www.kryogenix.org/> Stuart Langridge <http://www.kryogenix.org/>
Eugene Lazutkin <http://lazutkin.com/blog/> Eugene Lazutkin <http://lazutkin.com/blog/>
Jeong-Min Lee Jeong-Min Lee <falsetru@gmail.com>
Christopher Lenz <http://www.cmlenz.net/> Christopher Lenz <http://www.cmlenz.net/>
lerouxb@gmail.com lerouxb@gmail.com
limodou limodou
mattmcc mattmcc
Martin Maney <http://www.chipy.org/Martin_Maney> Martin Maney <http://www.chipy.org/Martin_Maney>
masonsimon+django@gmail.com
Manuzhai Manuzhai
Petar Marić Petar Marić
mark@junklight.com mark@junklight.com
mattycakes@gmail.com mattycakes@gmail.com
Jason McBrayer <http://www.carcosa.net/jason/> Jason McBrayer <http://www.carcosa.net/jason/>
mccutchen@gmail.com
michael.mcewan@gmail.com michael.mcewan@gmail.com
mmarshall mmarshall
Eric Moritz <http://eric.themoritzfamily.com/> Eric Moritz <http://eric.themoritzfamily.com/>
@ -157,6 +161,7 @@ answer newbie questions, and generally made Django that much better:
Amit Upadhyay Amit Upadhyay
Geert Vanderkelen Geert Vanderkelen
Milton Waddams Milton Waddams
wam-djangobug@wamber.net
Dan Watson <http://theidioteque.net/> Dan Watson <http://theidioteque.net/>
Rachel Willmer <http://www.willmer.com/kb/> Rachel Willmer <http://www.willmer.com/kb/>
Gary Wilson <gary.wilson@gmail.com> Gary Wilson <gary.wilson@gmail.com>

View File

@ -77,7 +77,7 @@ class Settings(object):
self.SETTINGS_MODULE = settings_module self.SETTINGS_MODULE = settings_module
try: try:
mod = __import__(self.SETTINGS_MODULE, '', '', ['']) mod = __import__(self.SETTINGS_MODULE, {}, {}, [''])
except ImportError, e: except ImportError, e:
raise EnvironmentError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e) raise EnvironmentError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e)
@ -97,7 +97,7 @@ class Settings(object):
new_installed_apps = [] new_installed_apps = []
for app in self.INSTALLED_APPS: for app in self.INSTALLED_APPS:
if app.endswith('.*'): if app.endswith('.*'):
appdir = os.path.dirname(__import__(app[:-2], '', '', ['']).__file__) appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
for d in os.listdir(appdir): for d in os.listdir(appdir):
if d.isalpha() and os.path.isdir(os.path.join(appdir, d)): if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
new_installed_apps.append('%s.%s' % (app[:-2], d)) new_installed_apps.append('%s.%s' % (app[:-2], d))

View File

@ -101,6 +101,7 @@ DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3. DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
DATABASE_OPTIONS = {} # Set to empty dictionary for default.
# Host for sending e-mail. # Host for sending e-mail.
EMAIL_HOST = 'localhost' EMAIL_HOST = 'localhost'
@ -228,6 +229,10 @@ MONTH_DAY_FORMAT = 'F j'
# Hint: you really don't! # Hint: you really don't!
TRANSACTIONS_MANAGED = False TRANSACTIONS_MANAGED = False
# The User-Agent string to use when checking for URL validity through the
# isExistingURL validator.
URL_VALIDATOR_USER_AGENT = "Django/0.96pre (http://www.djangoproject.com)"
############## ##############
# MIDDLEWARE # # MIDDLEWARE #
############## ##############

View File

@ -1,14 +1,13 @@
# SOME DESCRIPTIVE TITLE. # Translation of django.po to japanese.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2005,2006 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # makoto tsuyuki <mtsuyuki@gmail.com>, 2005,2006.
# #
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Django 1.0\n" "Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-10-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" "PO-Revision-Date: 2006-05-18 00:28+0900\n"
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n" "Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
"Language-Team: Japanese <django-ja@googlegroups.com>\n" "Language-Team: Japanese <django-ja@googlegroups.com>\n"
@ -57,9 +56,8 @@ msgid "Argentinean Spanish"
msgstr "アルゼンチンスペイン語" msgstr "アルゼンチンスペイン語"
#: conf/global_settings.py:49 #: conf/global_settings.py:49
#, fuzzy
msgid "Finnish" msgid "Finnish"
msgstr "デンマーク語" msgstr "フィンランド語"
#: conf/global_settings.py:50 #: conf/global_settings.py:50
msgid "French" msgid "French"
@ -98,52 +96,54 @@ msgid "Norwegian"
msgstr "ノルウェー語" msgstr "ノルウェー語"
#: conf/global_settings.py:59 #: conf/global_settings.py:59
msgid "Polish"
msgstr "ポーランド語"
#: conf/global_settings.py:60
msgid "Brazilian" msgid "Brazilian"
msgstr "ブラジル語" msgstr "ブラジル語"
#: conf/global_settings.py:60 #: conf/global_settings.py:61
msgid "Romanian" msgid "Romanian"
msgstr "ルーマニア語" msgstr "ルーマニア語"
#: conf/global_settings.py:61 #: conf/global_settings.py:62
msgid "Russian" msgid "Russian"
msgstr "ロシア語" msgstr "ロシア語"
#: conf/global_settings.py:62 #: conf/global_settings.py:63
msgid "Slovak" msgid "Slovak"
msgstr "スロバキア語" msgstr "スロバキア語"
#: conf/global_settings.py:63 #: conf/global_settings.py:64
#, fuzzy
msgid "Slovenian" msgid "Slovenian"
msgstr "スロヴェニア語" msgstr "スロヴェニア語"
#: conf/global_settings.py:64 #: conf/global_settings.py:65
msgid "Serbian" msgid "Serbian"
msgstr "セルビア語" msgstr "セルビア語"
#: conf/global_settings.py:65 #: conf/global_settings.py:66
msgid "Swedish" msgid "Swedish"
msgstr "スウェーデン語" msgstr "スウェーデン語"
#: conf/global_settings.py:66 #: conf/global_settings.py:67
msgid "Tamil" msgid "Tamil"
msgstr "タミル語" msgstr "タミル語"
#: conf/global_settings.py:67 #: conf/global_settings.py:68
msgid "Turkish" msgid "Turkish"
msgstr "トルコ語" msgstr "トルコ語"
#: conf/global_settings.py:68 #: conf/global_settings.py:69
#, fuzzy
msgid "Ukrainian" msgid "Ukrainian"
msgstr "ウクライナ語" msgstr "ウクライナ語"
#: conf/global_settings.py:69 #: conf/global_settings.py:70
msgid "Simplified Chinese" msgid "Simplified Chinese"
msgstr "簡体字中国語" msgstr "簡体字中国語"
#: conf/global_settings.py:70 #: conf/global_settings.py:71
msgid "Traditional Chinese" msgid "Traditional Chinese"
msgstr "繁体字中国語" msgstr "繁体字中国語"
@ -369,33 +369,33 @@ msgid "Delete"
msgstr "削除" msgstr "削除"
#: contrib/admin/templates/admin/delete_confirmation.html:14 #: contrib/admin/templates/admin/delete_confirmation.html:14
#, fuzzy, python-format #, python-format
msgid "" msgid ""
"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " "Deleting the %(object_name)s '%(escaped_object)s' would result in deleting "
"related objects, but your account doesn't have permission to delete the " "related objects, but your account doesn't have permission to delete the "
"following types of objects:" "following types of objects:"
msgstr "" msgstr ""
"%(object_name)s '%(object)s' の削除時に関連づけられたオブジェクトも削除しよう" "%(object_name)s '%(escaped_object)s' の削除時に関連づけられたオブジェクトも削"
"としましたが、あなたのアカウントには以下のタイプのオブジェクトを削除するパー" "除しようとしましたが、あなたのアカウントには以下のタイプのオブジェクトを削除"
"ミッションがありません:" "するパーミッションがありません:"
#: contrib/admin/templates/admin/delete_confirmation.html:21 #: contrib/admin/templates/admin/delete_confirmation.html:21
#, fuzzy, python-format #, python-format
msgid "" msgid ""
"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? "
"All of the following related items will be deleted:" "All of the following related items will be deleted:"
msgstr "" msgstr ""
"%(object_name)s \"%(object)s\"を削除しますか? 関連づけられている以下のオブ" "%(object_name)s \"%(escaped_object)s\"を削除しますか? 関連づけられている以下"
"ジェクトも全て削除されます:" "のオブジェクトも全て削除されます:"
#: contrib/admin/templates/admin/delete_confirmation.html:26 #: contrib/admin/templates/admin/delete_confirmation.html:26
msgid "Yes, I'm sure" msgid "Yes, I'm sure"
msgstr "はい。" msgstr "はい。"
#: contrib/admin/templates/admin/filter.html:2 #: contrib/admin/templates/admin/filter.html:2
#, fuzzy, python-format #, python-format
msgid " By %(filter_title)s " msgid " By %(filter_title)s "
msgstr "%(title)s で絞り込む" msgstr "%(filter_title)s で絞り込む"
#: contrib/admin/templates/admin/filters.html:4 #: contrib/admin/templates/admin/filters.html:4
msgid "Filter" msgid "Filter"
@ -407,9 +407,9 @@ msgid "Models available in the %(name)s application."
msgstr "%(name)s アプリケーションで利用可能なモデル" msgstr "%(name)s アプリケーションで利用可能なモデル"
#: contrib/admin/templates/admin/index.html:18 #: contrib/admin/templates/admin/index.html:18
#, fuzzy, python-format #, python-format
msgid "%(name)s" msgid "%(name)s"
msgstr "%(name)s を追加" msgstr "%(name)s"
#: contrib/admin/templates/admin/index.html:34 #: contrib/admin/templates/admin/index.html:34
msgid "Change" msgid "Change"
@ -436,9 +436,9 @@ msgid ""
"Something's wrong with your database installation. Make sure the appropriate " "Something's wrong with your database installation. Make sure the appropriate "
"database tables have been created, and make sure the database is readable by " "database tables have been created, and make sure the database is readable by "
"the appropriate user." "the appropriate user."
msgstr "データベースの設定に問題があるようです。" msgstr ""
"適切なテーブルが作られていること、適切なユーザで" "データベースの設定に問題があるようです。適切なテーブルが作られていること、適"
"データベースのデータを読み込めることを確認してください。" "切なユーザでデータベースのデータを読み込めることを確認してください。"
#: contrib/admin/templates/admin/login.html:17 #: contrib/admin/templates/admin/login.html:17
#: contrib/comments/templates/comments/form.html:6 #: 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 " "First, enter a username and password. Then, you'll be able to edit more user "
"options." "options."
msgstr "" msgstr ""
"まずユーザ名とパスワードを登録してください。" "まずユーザ名とパスワードを登録してください。その後詳細情報が編集可能になりま"
"その後詳細情報が編集可能になります。" "す。"
#: contrib/admin/templates/admin/auth/user/add_form.html:12 #: contrib/admin/templates/admin/auth/user/add_form.html:12
#, fuzzy
msgid "Username" msgid "Username"
msgstr "ユーザ名:" msgstr "ユーザ名"
#: contrib/admin/templates/admin/auth/user/add_form.html:18 #: contrib/admin/templates/admin/auth/user/add_form.html:18
#, fuzzy
msgid "Password" msgid "Password"
msgstr "パスワード:" msgstr "パスワード"
#: contrib/admin/templates/admin/auth/user/add_form.html:23 #: contrib/admin/templates/admin/auth/user/add_form.html:23
#, fuzzy
msgid "Password (again)" msgid "Password (again)"
msgstr "パスワードの変更" msgstr "パスワード(確認用)"
#: contrib/admin/templates/admin/auth/user/add_form.html:24 #: contrib/admin/templates/admin/auth/user/add_form.html:24
msgid "Enter the same password as above, for verification." msgid "Enter the same password as above, for verification."
@ -761,9 +758,8 @@ msgid "You may edit it again below."
msgstr "続けて編集できます。" msgstr "続けて編集できます。"
#: contrib/admin/views/auth.py:28 #: contrib/admin/views/auth.py:28
#, fuzzy
msgid "Add user" msgid "Add user"
msgstr "%s を追加" msgstr "ユーザを追加"
#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59 #: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59
msgid "" msgid ""
@ -813,9 +809,9 @@ msgid "view:"
msgstr "ビュー" msgstr "ビュー"
#: contrib/admin/views/doc.py:164 #: contrib/admin/views/doc.py:164
#, fuzzy, python-format #, python-format
msgid "App %r not found" msgid "App %r not found"
msgstr "ページが見つかりません" msgstr "アプリケーション %r が見つかりません"
#: contrib/admin/views/doc.py:171 #: contrib/admin/views/doc.py:171
#, python-format #, python-format
@ -1030,9 +1026,8 @@ msgid "The two password fields didn't match."
msgstr "確認用パスワードが一致しません。" msgstr "確認用パスワードが一致しません。"
#: contrib/auth/forms.py:24 #: contrib/auth/forms.py:24
#, fuzzy
msgid "A user with that username already exists." msgid "A user with that username already exists."
msgstr "%(fieldname)s に %(optname)s は既に存在します。" msgstr "同じユーザ名が既に登録済みです。"
#: contrib/auth/forms.py:52 #: contrib/auth/forms.py:52
msgid "" msgid ""
@ -1048,11 +1043,9 @@ msgstr "アカウントが無効です。"
#: contrib/auth/forms.py:84 #: contrib/auth/forms.py:84
msgid "" 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?" "you've registered?"
msgstr "" msgstr "メールアドレスの一致するユーザはいません。本当に登録しましたか?"
"メールアドレスの一致するユーザはいません。"
"本当に登録しましたか?"
#: contrib/auth/forms.py:116 #: contrib/auth/forms.py:116
msgid "The two 'new password' fields didn't match." msgid "The two 'new password' fields didn't match."
@ -1071,22 +1064,18 @@ msgid "codename"
msgstr "コード名" msgstr "コード名"
#: contrib/auth/models.py:42 #: contrib/auth/models.py:42
#, fuzzy
msgid "permission" msgid "permission"
msgstr "パーミッション" msgstr "パーミッション"
#: contrib/auth/models.py:43 contrib/auth/models.py:58 #: contrib/auth/models.py:43 contrib/auth/models.py:58
#, fuzzy
msgid "permissions" msgid "permissions"
msgstr "パーミッション" msgstr "パーミッション"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
#, fuzzy
msgid "group" msgid "group"
msgstr "グループ" msgstr "グループ"
#: contrib/auth/models.py:61 contrib/auth/models.py:100 #: contrib/auth/models.py:61 contrib/auth/models.py:100
#, fuzzy
msgid "groups" msgid "groups"
msgstr "グループ" msgstr "グループ"
@ -1099,8 +1088,8 @@ msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, " "Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)." "digits and underscores)."
msgstr "" msgstr ""
"この項目は必須です。" "この項目は必須です。半角アルファベット、半角数字、半角アンダーバーで30文字以"
"半角アルファベット、半角数字、半角アンダーバーで30文字以下にしてください。" "下にしてください。"
#: contrib/auth/models.py:91 #: contrib/auth/models.py:91
msgid "first name" msgid "first name"
@ -1138,9 +1127,7 @@ msgstr "有効"
msgid "" msgid ""
"Designates whether this user can log into the Django admin. Unselect this " "Designates whether this user can log into the Django admin. Unselect this "
"instead of deleting accounts." "instead of deleting accounts."
msgstr "" msgstr "ユーザが管理サイトにログイン可能かどうかを示します。"
"ユーザが管理サイトにログイン可能か"
"どうかを示します。"
#: contrib/auth/models.py:97 #: contrib/auth/models.py:97
msgid "superuser status" msgid "superuser status"
@ -1169,17 +1156,14 @@ msgstr ""
"パーミッションを獲得します。" "パーミッションを獲得します。"
#: contrib/auth/models.py:102 #: contrib/auth/models.py:102
#, fuzzy
msgid "user permissions" msgid "user permissions"
msgstr "ユーザパーミッション" msgstr "ユーザパーミッション"
#: contrib/auth/models.py:105 #: contrib/auth/models.py:105
#, fuzzy
msgid "user" msgid "user"
msgstr "ユーザ" msgstr "ユーザ"
#: contrib/auth/models.py:106 #: contrib/auth/models.py:106
#, fuzzy
msgid "users" msgid "users"
msgstr "ユーザ" msgstr "ユーザ"
@ -1188,7 +1172,6 @@ msgid "Personal info"
msgstr "個人情報" msgstr "個人情報"
#: contrib/auth/models.py:112 #: contrib/auth/models.py:112
#, fuzzy
msgid "Permissions" msgid "Permissions"
msgstr "パーミッション" msgstr "パーミッション"
@ -1201,12 +1184,10 @@ msgid "Groups"
msgstr "グループ" msgstr "グループ"
#: contrib/auth/models.py:258 #: contrib/auth/models.py:258
#, fuzzy
msgid "message" msgid "message"
msgstr "メッセージ" msgstr "メッセージ"
#: contrib/auth/views.py:39 #: contrib/auth/views.py:39
#, fuzzy
msgid "Logged out" msgid "Logged out"
msgstr "ログアウト" msgstr "ログアウト"
@ -1280,7 +1261,6 @@ msgstr ""
"た」と表示されるようになります。" "た」と表示されるようになります。"
#: contrib/comments/models.py:91 #: contrib/comments/models.py:91
#, fuzzy
msgid "comments" msgid "comments"
msgstr "コメント" msgstr "コメント"
@ -1316,12 +1296,10 @@ msgid "approved by staff"
msgstr "スタッフの承認済み" msgstr "スタッフの承認済み"
#: contrib/comments/models.py:176 #: contrib/comments/models.py:176
#, fuzzy
msgid "free comment" msgid "free comment"
msgstr "フリーコメント" msgstr "フリーコメント"
#: contrib/comments/models.py:177 #: contrib/comments/models.py:177
#, fuzzy
msgid "free comments" msgid "free comments"
msgstr "フリーコメント" msgstr "フリーコメント"
@ -1334,12 +1312,10 @@ msgid "score date"
msgstr "スコアされた日" msgstr "スコアされた日"
#: contrib/comments/models.py:237 #: contrib/comments/models.py:237
#, fuzzy
msgid "karma score" msgid "karma score"
msgstr "カルマスコア" msgstr "カルマスコア"
#: contrib/comments/models.py:238 #: contrib/comments/models.py:238
#, fuzzy
msgid "karma scores" msgid "karma scores"
msgstr "カルマスコア" msgstr "カルマスコア"
@ -1364,12 +1340,10 @@ msgid "flag date"
msgstr "フラグ日" msgstr "フラグ日"
#: contrib/comments/models.py:268 #: contrib/comments/models.py:268
#, fuzzy
msgid "user flag" msgid "user flag"
msgstr "ユーザフラグ" msgstr "ユーザフラグ"
#: contrib/comments/models.py:269 #: contrib/comments/models.py:269
#, fuzzy
msgid "user flags" msgid "user flags"
msgstr "ユーザフラグ" msgstr "ユーザフラグ"
@ -1383,12 +1357,10 @@ msgid "deletion date"
msgstr "削除日" msgstr "削除日"
#: contrib/comments/models.py:280 #: contrib/comments/models.py:280
#, fuzzy
msgid "moderator deletion" msgid "moderator deletion"
msgstr "モデレータ削除" msgstr "モデレータ削除"
#: contrib/comments/models.py:281 #: contrib/comments/models.py:281
#, fuzzy
msgid "moderator deletions" msgid "moderator deletions"
msgstr "モデレータ削除" msgstr "モデレータ削除"
@ -1398,12 +1370,10 @@ msgid "Moderator deletion by %r"
msgstr "%r によるモデレータ削除" msgstr "%r によるモデレータ削除"
#: contrib/comments/templates/comments/form.html:8 #: contrib/comments/templates/comments/form.html:8
#, fuzzy
msgid "Forgotten your password?" msgid "Forgotten your password?"
msgstr "パスワードをお忘れですか?" msgstr "パスワードをお忘れですか?"
#: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:12
#, fuzzy
msgid "Ratings" msgid "Ratings"
msgstr "レーティング" msgstr "レーティング"
@ -1423,18 +1393,15 @@ msgstr "写真を登録"
#: contrib/comments/templates/comments/form.html:28 #: contrib/comments/templates/comments/form.html:28
#: contrib/comments/templates/comments/freeform.html:5 #: contrib/comments/templates/comments/freeform.html:5
#, fuzzy
msgid "Comment:" msgid "Comment:"
msgstr "コメント:" msgstr "コメント:"
#: contrib/comments/templates/comments/form.html:35 #: contrib/comments/templates/comments/form.html:35
#: contrib/comments/templates/comments/freeform.html:10 #: contrib/comments/templates/comments/freeform.html:10
#, fuzzy
msgid "Preview comment" msgid "Preview comment"
msgstr "コメントをプレビュー" msgstr "コメントをプレビュー"
#: contrib/comments/templates/comments/freeform.html:4 #: contrib/comments/templates/comments/freeform.html:4
#, fuzzy
msgid "Your name:" msgid "Your name:"
msgstr "ユーザ名:" msgstr "ユーザ名:"
@ -1512,7 +1479,6 @@ msgid "No voting for yourself"
msgstr "自分には投票できません。" msgstr "自分には投票できません。"
#: contrib/contenttypes/models.py:20 #: contrib/contenttypes/models.py:20
#, fuzzy
msgid "python model class name" msgid "python model class name"
msgstr "Python モデルクラス名" msgstr "Python モデルクラス名"
@ -1547,13 +1513,12 @@ msgid "template name"
msgstr "テンプレート名" msgstr "テンプレート名"
#: contrib/flatpages/models.py:13 #: contrib/flatpages/models.py:13
#, fuzzy
msgid "" msgid ""
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " "Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
"will use 'flatpages/default.html'." "will use 'flatpages/default.html'."
msgstr "" msgstr ""
"例: 'flatpages/contact_page'. 指定しなければ、デフォルト設定の'flatpages/" "例: 'flatpages/contact_page.html'. 指定しなければ、デフォルト設定"
"default' を使います。" "の'flatpages/default.html' を使います。"
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "registration required" msgid "registration required"
@ -1640,16 +1605,15 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "半角の英数字およびアンダースコア以外は使用できません。" msgstr "半角の英数字およびアンダースコア以外は使用できません。"
#: core/validators.py:67 #: core/validators.py:67
#, fuzzy
msgid "" msgid ""
"This value must contain only letters, numbers, underscores, dashes or " "This value must contain only letters, numbers, underscores, dashes or "
"slashes." "slashes."
msgstr "半角の英数字、アンダースコア、ダッシュ、ラッシュ以外は使用できません。" msgstr ""
"半角の英数字、アンダースコア、ダッシュ、スラッシュ以外は使用できません。"
#: core/validators.py:71 #: core/validators.py:71
#, fuzzy
msgid "This value must contain only letters, numbers, underscores or hyphens." msgid "This value must contain only letters, numbers, underscores or hyphens."
msgstr "半角の英数字、アンダースコア、ダッシュ、ラッシュ以外は使用できません。" msgstr "半角の英数字、アンダースコア、ハイフン以外は使用できません。"
#: core/validators.py:75 #: core/validators.py:75
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."
@ -1696,9 +1660,9 @@ msgid "Year must be 1900 or later."
msgstr "1900年以降を指定してください。" msgstr "1900年以降を指定してください。"
#: core/validators.py:142 #: core/validators.py:142
#, fuzzy, python-format #, python-format
msgid "Invalid date: %s." msgid "Invalid date: %s."
msgstr "無効なURL: %s" msgstr "無効な日付: %s"
#: core/validators.py:146 db/models/fields/__init__.py:424 #: core/validators.py:146 db/models/fields/__init__.py:424
msgid "Enter a valid date in YYYY-MM-DD format." 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 #: core/validators.py:172 core/validators.py:401 forms/__init__.py:662
msgid "No file was submitted. Check the encoding type on the form." msgid "No file was submitted. Check the encoding type on the form."
msgstr "ファイルが取得できませんでした。formのencoding typeを確認してください。" msgstr ""
"ファイルが取得できませんでした。formのencoding typeを確認してください。"
#: core/validators.py:176 #: core/validators.py:176
msgid "" msgid ""
@ -1825,25 +1790,25 @@ msgstr "有効な 10 進数を入力してください。"
msgid "Please enter a valid decimal number with at most %s total digit." msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s total digits." "Please enter a valid decimal number with at most %s total digits."
msgstr[0] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。" msgstr[0] "全体で %s 文字以下の数字を入力してください。"
msgstr[1] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。" msgstr[1] "全体で %s 文字以下の数字を入力してください。"
#: core/validators.py:381 #: core/validators.py:381
#, fuzzy, python-format #, python-format
msgid "" msgid ""
"Please enter a valid decimal number with a whole part of at most %s digit." "Please enter a valid decimal number with a whole part of at most %s digit."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with a whole part of at most %s digits." "Please enter a valid decimal number with a whole part of at most %s digits."
msgstr[0] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。" msgstr[0] "整数部は %s 文字以下の数字を入力してください。"
msgstr[1] "最大桁数 %s 桁以下の有効な 10 進数を入力してください。" msgstr[1] "整数部は %s 文字以下の数字を入力してください。"
#: core/validators.py:384 #: core/validators.py:384
#, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s decimal place." msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places." "Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "小数点以下が %s 桁までの有効な 10 進数を入力してください。" msgstr[0] "小数部は %s 文字以下の数字を入力してください。"
msgstr[1] "小数点以下が %s 桁までの有効な 10 進数を入力してください。" msgstr[1] "小数部は %s 文字以下の数字を入力してください。"
#: core/validators.py:394 #: core/validators.py:394
#, python-format #, python-format
@ -1947,17 +1912,14 @@ msgid "This field is required."
msgstr "このフィールドは必須です。" msgstr "このフィールドは必須です。"
#: db/models/fields/__init__.py:349 #: db/models/fields/__init__.py:349
#, fuzzy
msgid "This value must be an integer." msgid "This value must be an integer."
msgstr "値は整数でなければなりません。" msgstr "値は整数でなければなりません。"
#: db/models/fields/__init__.py:381 #: db/models/fields/__init__.py:381
#, fuzzy
msgid "This value must be either True or False." msgid "This value must be either True or False."
msgstr "値は真: True または偽: False でなければなりません。" msgstr "値は真: True または偽: False でなければなりません。"
#: db/models/fields/__init__.py:397 #: db/models/fields/__init__.py:397
#, fuzzy
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "このフィールドには NULL を指定できません。" msgstr "このフィールドには NULL を指定できません。"
@ -1971,7 +1933,6 @@ msgid "Please enter a valid %s."
msgstr "正しい %s を入力してください。" msgstr "正しい %s を入力してください。"
#: db/models/fields/related.py:618 #: db/models/fields/related.py:618
#, fuzzy
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr "複数の ID はカンマで区切ってください。" msgstr "複数の ID はカンマで区切ってください。"
@ -1979,7 +1940,8 @@ msgstr "複数の ID はカンマで区切ってください。"
msgid "" msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "" msgstr ""
"複数選択するときには Control キーを押したまま選択してください。Mac は Command キーを使ってください" "複数選択するときには Control キーを押したまま選択してください。Mac は "
"Command キーを使ってください"
#: db/models/fields/related.py:664 #: db/models/fields/related.py:664
#, python-format #, python-format
@ -2102,7 +2064,6 @@ msgid "December"
msgstr "12月" msgstr "12月"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "jan" msgid "jan"
msgstr "1月" msgstr "1月"
@ -2119,7 +2080,6 @@ msgid "apr"
msgstr "4月" msgstr "4月"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "may" msgid "may"
msgstr "5月" msgstr "5月"
@ -2228,29 +2188,27 @@ msgid "TIME_FORMAT"
msgstr "H:i" msgstr "H:i"
#: utils/translation/trans_real.py:380 #: utils/translation/trans_real.py:380
#, fuzzy
msgid "YEAR_MONTH_FORMAT" msgid "YEAR_MONTH_FORMAT"
msgstr "Y/m/d" msgstr "Y/m/d"
#: utils/translation/trans_real.py:381 #: utils/translation/trans_real.py:381
#, fuzzy
msgid "MONTH_DAY_FORMAT" msgid "MONTH_DAY_FORMAT"
msgstr "Y/m/d" msgstr "m/d"
#: views/generic/create_update.py:43 #: views/generic/create_update.py:43
#, fuzzy, python-format #, python-format
msgid "The %(verbose_name)s was created successfully." msgid "The %(verbose_name)s was created successfully."
msgstr "%(name)s \"%(obj)s\" を変更しました。" msgstr "%(verbose_name)s を作成しました。"
#: views/generic/create_update.py:117 #: views/generic/create_update.py:117
#, fuzzy, python-format #, python-format
msgid "The %(verbose_name)s was updated successfully." msgid "The %(verbose_name)s was updated successfully."
msgstr "%(name)s \"%(obj)s\" を削除しました。" msgstr "%(verbose_name)s を更新しました。"
#: views/generic/create_update.py:184 #: views/generic/create_update.py:184
#, fuzzy, python-format #, python-format
msgid "The %(verbose_name)s was deleted." msgid "The %(verbose_name)s was deleted."
msgstr " %(site_name)s チーム" msgstr " %(verbose_name)s を削除しました。"
#~ msgid "String (up to 50)" #~ msgid "String (up to 50)"
#~ msgstr "文字列 (50 字まで)" #~ msgstr "文字列 (50 字まで)"

View File

@ -2,14 +2,15 @@
# Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# João Marcus Christ <joaoma@gmail.com>, 2006. # João Marcus Christ <joaoma@gmail.com>, 2006.
# Carlos Eduardo de Paula <carlosedp@gmail.com>, 2006.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django\n" "Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 10:11+0200\n" "POT-Creation-Date: 2006-05-16 10:11+0200\n"
"PO-Revision-Date: 2006-01-23 19:54-0200\n" "PO-Revision-Date: 2006-11-01 17:45-0300\n"
"Last-Translator: João Marcus Christ <joaoma@gmail.com>\n" "Last-Translator: Carlos Eduardo de Paula <carlosedp@gmail.com>\n"
"Language-Team: Português do Brasil <pt-br@li.org>\n" "Language-Team: Português do Brasil <pt-br@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -86,12 +87,12 @@ msgid ""
"removed\" message will be displayed instead." "removed\" message will be displayed instead."
msgstr "" msgstr ""
"Selecione esta opção se o comentário é inapropriado. Uma mensagem \"Este " "Selecione esta opção se o comentário é inapropriado. Uma mensagem \"Este "
"comentário foi removido\" será mostrada no lugar." "comentário foi removido\" a mensagem será mostrada no lugar."
#: contrib/comments/models.py:91 #: contrib/comments/models.py:91
#, fuzzy #, fuzzy
msgid "comments" msgid "comments"
msgstr "comentário" msgstr "comentários"
#: contrib/comments/models.py:131 contrib/comments/models.py:207 #: contrib/comments/models.py:131 contrib/comments/models.py:207
msgid "Content object" msgid "Content object"
@ -150,7 +151,7 @@ msgstr "Pontuação de Karma"
#: contrib/comments/models.py:238 #: contrib/comments/models.py:238
#, fuzzy #, fuzzy
msgid "karma scores" msgid "karma scores"
msgstr "Pontuação de Karma" msgstr "Pontuações de Karma"
#: contrib/comments/models.py:242 #: contrib/comments/models.py:242
#, python-format #, python-format
@ -170,17 +171,17 @@ msgstr ""
#: contrib/comments/models.py:265 #: contrib/comments/models.py:265
msgid "flag date" msgid "flag date"
msgstr "marca de data" msgstr "flag de data"
#: contrib/comments/models.py:268 #: contrib/comments/models.py:268
#, fuzzy #, fuzzy
msgid "user flag" msgid "user flag"
msgstr "Flag de usuário" msgstr "flag de usuário"
#: contrib/comments/models.py:269 #: contrib/comments/models.py:269
#, fuzzy #, fuzzy
msgid "user flags" msgid "user flags"
msgstr "Flags de usuário" msgstr "flags de usuário"
#: contrib/comments/models.py:273 #: contrib/comments/models.py:273
#, python-format #, python-format
@ -189,22 +190,22 @@ msgstr "Flag por %r"
#: contrib/comments/models.py:278 #: contrib/comments/models.py:278
msgid "deletion date" msgid "deletion date"
msgstr "data de apagamento" msgstr "data de exclusão"
#: contrib/comments/models.py:280 #: contrib/comments/models.py:280
#, fuzzy #, fuzzy
msgid "moderator deletion" msgid "moderator deletion"
msgstr "Apagamento feito por moderador" msgstr "Exclusão feita pelo moderador"
#: contrib/comments/models.py:281 #: contrib/comments/models.py:281
#, fuzzy #, fuzzy
msgid "moderator deletions" msgid "moderator deletions"
msgstr "Apagamentos feitos por moderador" msgstr "Exclusões feitas pelo moderador"
#: contrib/comments/models.py:285 #: contrib/comments/models.py:285
#, python-format #, python-format
msgid "Moderator deletion by %r" msgid "Moderator deletion by %r"
msgstr "Apagamento feito pelo moderador %r" msgstr "Exclusao feita pelo moderador %r"
#: contrib/comments/views/karma.py:19 #: contrib/comments/views/karma.py:19
msgid "Anonymous users cannot vote" msgid "Anonymous users cannot vote"
@ -237,12 +238,12 @@ msgid_plural ""
"\n" "\n"
"%(text)s" "%(text)s"
msgstr[0] "" msgstr[0] ""
"Este comentário foi feito por um usuário esboço:\n" "Este comentário foi feito por um usuário que postou menos de %(count)s "
"\n" "comentário:\n"
"%(text)s" "%(text)s"
msgstr[1] "" msgstr[1] ""
"Este comentário foi feito por um usuário esboço:\n" "Este comentário foi feito por um usuário que postou menos de %(count)s "
"\n" "comentários:\n"
"%(text)s" "%(text)s"
#: contrib/comments/views/comments.py:117 #: contrib/comments/views/comments.py:117
@ -252,7 +253,7 @@ msgid ""
"\n" "\n"
"%(text)s" "%(text)s"
msgstr "" msgstr ""
"Este comentário foi feito por um usuário esboço:\n" "Este comentário foi feito por um usuário incompleto:\n"
"\n" "\n"
"%(text)s" "%(text)s"
@ -299,7 +300,7 @@ msgstr "Senha:"
#: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:6
#, fuzzy #, fuzzy
msgid "Forgotten your password?" msgid "Forgotten your password?"
msgstr "Alterar minha senha" msgstr "Esqueceu sua senha?"
#: contrib/comments/templates/comments/form.html:8 #: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
@ -325,21 +326,21 @@ msgstr "Encerrar sessão"
#: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:12
#, fuzzy #, fuzzy
msgid "Ratings" msgid "Ratings"
msgstr "avaliação #1" msgstr "Avaliações"
#: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23 #: contrib/comments/templates/comments/form.html:23
msgid "Required" msgid "Required"
msgstr "" msgstr "Requerido"
#: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:12
#: contrib/comments/templates/comments/form.html:23 #: contrib/comments/templates/comments/form.html:23
msgid "Optional" msgid "Optional"
msgstr "" msgstr "Opcional"
#: contrib/comments/templates/comments/form.html:23 #: contrib/comments/templates/comments/form.html:23
msgid "Post a photo" msgid "Post a photo"
msgstr "" msgstr "Postar uma foto"
#: contrib/comments/templates/comments/form.html:27 #: contrib/comments/templates/comments/form.html:27
#: contrib/comments/templates/comments/freeform.html:5 #: contrib/comments/templates/comments/freeform.html:5
@ -351,12 +352,12 @@ msgstr "Comentário"
#: contrib/comments/templates/comments/freeform.html:9 #: contrib/comments/templates/comments/freeform.html:9
#, fuzzy #, fuzzy
msgid "Preview comment" msgid "Preview comment"
msgstr "Comentário livre" msgstr "Pré visualizar comentário"
#: contrib/comments/templates/comments/freeform.html:4 #: contrib/comments/templates/comments/freeform.html:4
#, fuzzy #, fuzzy
msgid "Your name:" msgid "Your name:"
msgstr "usuário" msgstr "Seu nome:"
#: contrib/admin/filterspecs.py:40 #: contrib/admin/filterspecs.py:40
#, python-format #, python-format
@ -443,7 +444,7 @@ msgid ""
"sensitive." "sensitive."
msgstr "" msgstr ""
"Por favor entre usuário e senha corretos. Note que ambos os " "Por favor entre usuário e senha corretos. Note que ambos os "
"camposdiferenciam maiúsculas e minúsculas." "campos diferenciam maiúsculas e minúsculas."
#: contrib/admin/views/decorators.py:23 #: contrib/admin/views/decorators.py:23
#: contrib/admin/templates/admin/login.html:25 #: contrib/admin/templates/admin/login.html:25
@ -468,7 +469,7 @@ msgstr ""
#: contrib/admin/views/decorators.py:82 #: contrib/admin/views/decorators.py:82
msgid "Usernames cannot contain the '@' character." msgid "Usernames cannot contain the '@' character."
msgstr "Nomes de usuário não podem conter o caracter '@'." msgstr "Nomes de usuário não podem conter o caractere '@'."
#: contrib/admin/views/decorators.py:84 #: contrib/admin/views/decorators.py:84
#, python-format #, python-format
@ -553,7 +554,7 @@ msgstr "Um(a) ou mais %(fieldname)s em %(name)s:"
#: contrib/admin/views/main.py:508 #: contrib/admin/views/main.py:508
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "O(A) %(name)s \"%(obj)s\" foi adicionado com sucesso." msgstr "O(A) %(name)s \"%(obj)s\" foi excluído com sucesso."
#: contrib/admin/views/main.py:511 #: contrib/admin/views/main.py:511
msgid "Are you sure?" msgid "Are you sure?"
@ -746,7 +747,7 @@ msgid ""
"mail and should be fixed shortly. Thanks for your patience." "mail and should be fixed shortly. Thanks for your patience."
msgstr "" msgstr ""
"Houve um erro. Este foi reportado aos administradores do site através d e-" "Houve um erro. Este foi reportado aos administradores do site através d e-"
"mail e deve ser consertado em breve. Obrigado pela compreensão." "mail e deve ser corrigido em breve. Obrigado pela compreensão."
#: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8 #: contrib/admin/templates/admin/404.html:8
@ -760,7 +761,7 @@ msgstr "Desculpe, mas a página requisitada não pode ser encontrada."
#: contrib/admin/templates/admin/index.html:17 #: contrib/admin/templates/admin/index.html:17
#, python-format #, python-format
msgid "Models available in the %(name)s application." msgid "Models available in the %(name)s application."
msgstr "" msgstr "Modelos disponíveis na aplicação %(name)s"
#: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15 #: contrib/admin/templates/admin/change_form.html:15
@ -794,7 +795,7 @@ msgstr "Adicionar %(name)s"
#: contrib/admin/templates/admin/login.html:22 #: contrib/admin/templates/admin/login.html:22
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
msgstr "Você <a href=\"/password_reset/\"esqueceu a senha</a>?" msgstr "Você <a href=\"/password_reset/\">esqueceu sua senha</a>?"
#: contrib/admin/templates/admin/base.html:23 #: contrib/admin/templates/admin/base.html:23
msgid "Welcome," msgid "Welcome,"
@ -836,7 +837,7 @@ msgstr "Por %(title)s "
#: contrib/admin/templates/admin/search_form.html:8 #: contrib/admin/templates/admin/search_form.html:8
msgid "Go" msgid "Go"
msgstr "" msgstr "Ir"
#: contrib/admin/templates/admin/change_form.html:21 #: contrib/admin/templates/admin/change_form.html:21
msgid "View on site" msgid "View on site"
@ -847,7 +848,7 @@ msgstr "Ver no site"
msgid "Please correct the error below." msgid "Please correct the error below."
msgid_plural "Please correct the errors below." msgid_plural "Please correct the errors below."
msgstr[0] "Por favor, corrija o erro abaixo." msgstr[0] "Por favor, corrija o erro abaixo."
msgstr[1] "Por favor, corrija o erro abaixo." msgstr[1] "Por favor, corrija os erros abaixo."
#: contrib/admin/templates/admin/change_form.html:48 #: contrib/admin/templates/admin/change_form.html:48
msgid "Ordering" msgid "Ordering"
@ -930,8 +931,8 @@ msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You " "We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly." "should be receiving it shortly."
msgstr "" msgstr ""
"Nós enviamos uma nova senha para o e-mail que você informou. Você deve estar " "Nós enviamos uma nova senha para o e-mail que você informou. Você deverá "
"recebendo uma mensagem em breve." "receber uma mensagem em breve."
#: contrib/admin/templates/registration/password_change_form.html:12 #: contrib/admin/templates/registration/password_change_form.html:12
msgid "" msgid ""
@ -973,7 +974,7 @@ msgstr "Sua nova senha é: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7 #: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:" msgid "Feel free to change this password by going to this page:"
msgstr "Sinta-se livre para alterar esta senha visitando esta página:" msgstr "Sinta-se a vontade para alterar esta senha visitando esta página:"
#: contrib/admin/templates/registration/password_reset_email.html:11 #: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:" msgid "Your username, in case you've forgotten:"
@ -1040,17 +1041,17 @@ msgstr ""
#: contrib/admin/templates/admin_doc/bookmarklets.html:25 #: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)" msgid "Edit this object (current window)"
msgstr "Edita este objeto (janela atual)" msgstr "Editar este objeto (janela atual)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26 #: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object." msgid "Jumps to the admin page for pages that represent a single object."
msgstr "" msgstr ""
"Vai para a página de administração para páginas que representam um objeto " "Vai para a página de administração que representam um objeto "
"único." "único."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28 #: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)" msgid "Edit this object (new window)"
msgstr "Edita este objeto (nova janela)" msgstr "Editar este objeto (nova janela)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:29 #: contrib/admin/templates/admin_doc/bookmarklets.html:29
msgid "As above, but opens the admin page in a new window." msgid "As above, but opens the admin page in a new window."
@ -1135,7 +1136,7 @@ msgstr ""
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "registration required" msgid "registration required"
msgstr "é obrigatório registrar" msgstr "registro obrigatório"
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page." msgid "If this is checked, only logged-in users will be able to view the page."
@ -1160,22 +1161,22 @@ msgstr "nome código"
#: contrib/auth/models.py:17 #: contrib/auth/models.py:17
#, fuzzy #, fuzzy
msgid "permission" msgid "permission"
msgstr "Permissão" msgstr "permissão"
#: contrib/auth/models.py:18 contrib/auth/models.py:27 #: contrib/auth/models.py:18 contrib/auth/models.py:27
#, fuzzy #, fuzzy
msgid "permissions" msgid "permissions"
msgstr "Permissões" msgstr "permissões"
#: contrib/auth/models.py:29 #: contrib/auth/models.py:29
#, fuzzy #, fuzzy
msgid "group" msgid "group"
msgstr "Grupo" msgstr "grupo"
#: contrib/auth/models.py:30 contrib/auth/models.py:65 #: contrib/auth/models.py:30 contrib/auth/models.py:65
#, fuzzy #, fuzzy
msgid "groups" msgid "groups"
msgstr "Grupos" msgstr "grupos"
#: contrib/auth/models.py:55 #: contrib/auth/models.py:55
msgid "username" msgid "username"
@ -1236,17 +1237,17 @@ msgstr ""
#: contrib/auth/models.py:67 #: contrib/auth/models.py:67
#, fuzzy #, fuzzy
msgid "user permissions" msgid "user permissions"
msgstr "Permissões" msgstr "permissões do usuário"
#: contrib/auth/models.py:70 #: contrib/auth/models.py:70
#, fuzzy #, fuzzy
msgid "user" msgid "user"
msgstr "Usuário" msgstr "usuário"
#: contrib/auth/models.py:71 #: contrib/auth/models.py:71
#, fuzzy #, fuzzy
msgid "users" msgid "users"
msgstr "Usuários" msgstr "usuários"
#: contrib/auth/models.py:76 #: contrib/auth/models.py:76
msgid "Personal info" msgid "Personal info"
@ -1267,7 +1268,7 @@ msgstr "Grupos"
#: contrib/auth/models.py:219 #: contrib/auth/models.py:219
#, fuzzy #, fuzzy
msgid "message" msgid "message"
msgstr "Mensagem" msgstr "mensagem"
#: contrib/auth/forms.py:30 #: contrib/auth/forms.py:30
msgid "" msgid ""
@ -1275,7 +1276,7 @@ msgid ""
"required for logging in." "required for logging in."
msgstr "" msgstr ""
"Seu navegador Web não parece estar com os cookies habilitados. Cookies são " "Seu navegador Web não parece estar com os cookies habilitados. Cookies são "
"requeridos para acesssar." "requeridos para acessar."
#: contrib/contenttypes/models.py:25 #: contrib/contenttypes/models.py:25
#, fuzzy #, fuzzy
@ -1417,52 +1418,52 @@ msgstr "Dezembro"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy #, fuzzy
msgid "jan" msgid "jan"
msgstr "e" msgstr "jan"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "feb" msgid "feb"
msgstr "" msgstr "fev"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "mar" msgid "mar"
msgstr "" msgstr "mar"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "apr" msgid "apr"
msgstr "" msgstr "abr"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy #, fuzzy
msgid "may" msgid "may"
msgstr "dia" msgstr "mai"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "jun" msgid "jun"
msgstr "" msgstr "jun"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "jul" msgid "jul"
msgstr "" msgstr "jul"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "aug" msgid "aug"
msgstr "" msgstr "ago"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "sep" msgid "sep"
msgstr "" msgstr "set"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "oct" msgid "oct"
msgstr "" msgstr "out"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "nov" msgid "nov"
msgstr "" msgstr "nov"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "dec" msgid "dec"
msgstr "" msgstr "dez"
#: utils/dates.py:27 #: utils/dates.py:27
msgid "Jan." msgid "Jan."
@ -1497,45 +1498,45 @@ msgstr "Dez."
msgid "year" msgid "year"
msgid_plural "years" msgid_plural "years"
msgstr[0] "ano" msgstr[0] "ano"
msgstr[1] "ano" msgstr[1] "anos"
#: utils/timesince.py:13 #: utils/timesince.py:13
#, fuzzy #, fuzzy
msgid "month" msgid "month"
msgid_plural "months" msgid_plural "months"
msgstr[0] "mês" msgstr[0] "mês"
msgstr[1] "mês" msgstr[1] "meses"
#: utils/timesince.py:14 #: utils/timesince.py:14
msgid "week" msgid "week"
msgid_plural "weeks" msgid_plural "weeks"
msgstr[0] "" msgstr[0] "semana"
msgstr[1] "" msgstr[1] "semanas"
#: utils/timesince.py:15 #: utils/timesince.py:15
#, fuzzy #, fuzzy
msgid "day" msgid "day"
msgid_plural "days" msgid_plural "days"
msgstr[0] "dia" msgstr[0] "dia"
msgstr[1] "dia" msgstr[1] "dias"
#: utils/timesince.py:16 #: utils/timesince.py:16
#, fuzzy #, fuzzy
msgid "hour" msgid "hour"
msgid_plural "hours" msgid_plural "hours"
msgstr[0] "hora" msgstr[0] "hora"
msgstr[1] "hora" msgstr[1] "horas"
#: utils/timesince.py:17 #: utils/timesince.py:17
#, fuzzy #, fuzzy
msgid "minute" msgid "minute"
msgid_plural "minutes" msgid_plural "minutes"
msgstr[0] "minuto" msgstr[0] "minuto"
msgstr[1] "minuto" msgstr[1] "minutos"
#: conf/global_settings.py:37 #: conf/global_settings.py:37
msgid "Bengali" msgid "Bengali"
msgstr "" msgstr "Bengalês"
#: conf/global_settings.py:38 #: conf/global_settings.py:38
msgid "Czech" msgid "Czech"
@ -1548,7 +1549,7 @@ msgstr ""
#: conf/global_settings.py:40 #: conf/global_settings.py:40
#, fuzzy #, fuzzy
msgid "Danish" msgid "Danish"
msgstr "Espanhol" msgstr "Dinamarquês"
#: conf/global_settings.py:41 #: conf/global_settings.py:41
msgid "German" msgid "German"
@ -1556,7 +1557,7 @@ msgstr "Alemão"
#: conf/global_settings.py:42 #: conf/global_settings.py:42
msgid "Greek" msgid "Greek"
msgstr "" msgstr "Grego"
#: conf/global_settings.py:43 #: conf/global_settings.py:43
msgid "English" msgid "English"
@ -1576,11 +1577,11 @@ msgstr "Galiciano"
#: conf/global_settings.py:47 #: conf/global_settings.py:47
msgid "Hungarian" msgid "Hungarian"
msgstr "" msgstr "Húngaro"
#: conf/global_settings.py:48 #: conf/global_settings.py:48
msgid "Hebrew" msgid "Hebrew"
msgstr "" msgstr "Hebraico"
#: conf/global_settings.py:49 #: conf/global_settings.py:49
msgid "Icelandic" msgid "Icelandic"
@ -1604,7 +1605,7 @@ msgstr "Norueguês"
#: conf/global_settings.py:54 #: conf/global_settings.py:54
msgid "Brazilian" msgid "Brazilian"
msgstr "Brazileiro" msgstr "Brasileiro"
#: conf/global_settings.py:55 #: conf/global_settings.py:55
msgid "Romanian" msgid "Romanian"
@ -1621,7 +1622,7 @@ msgstr "Eslovaco"
#: conf/global_settings.py:58 #: conf/global_settings.py:58
#, fuzzy #, fuzzy
msgid "Slovenian" msgid "Slovenian"
msgstr "Eslovaco" msgstr "Esloveno"
#: conf/global_settings.py:59 #: conf/global_settings.py:59
msgid "Serbian" msgid "Serbian"
@ -1634,7 +1635,7 @@ msgstr "Sueco"
#: conf/global_settings.py:61 #: conf/global_settings.py:61
#, fuzzy #, fuzzy
msgid "Ukrainian" msgid "Ukrainian"
msgstr "Brazileiro" msgstr "Ucraniano"
#: conf/global_settings.py:62 #: conf/global_settings.py:62
msgid "Simplified Chinese" msgid "Simplified Chinese"
@ -1689,7 +1690,7 @@ msgstr "Este valor não pode conter apenas dígitos."
#: core/validators.py:116 #: core/validators.py:116
msgid "Enter a whole number." msgid "Enter a whole number."
msgstr "Informe um número inteiro." msgstr "Informe um número completo."
#: core/validators.py:120 #: core/validators.py:120
msgid "Only alphabetical characters are allowed here." msgid "Only alphabetical characters are allowed here."
@ -1772,7 +1773,7 @@ msgstr "Informe uma abreviação válida de nome de um estado dos EUA."
msgid "Watch your mouth! The word %s is not allowed here." msgid "Watch your mouth! The word %s is not allowed here."
msgid_plural "Watch your mouth! The words %s are not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here."
msgstr[0] "Lave sua boca! A palavra %s não é permitida aqui." msgstr[0] "Lave sua boca! A palavra %s não é permitida aqui."
msgstr[1] "Lave sua boca! A palavra %s não é permitida aqui." msgstr[1] "Lave sua boca! As palavras %s não são permitidas aqui."
#: core/validators.py:236 #: core/validators.py:236
#, python-format #, python-format
@ -1808,14 +1809,14 @@ msgstr "Este valor deve ser uma potência de %s."
#: core/validators.py:347 #: core/validators.py:347
msgid "Please enter a valid decimal number." msgid "Please enter a valid decimal number."
msgstr "Informe um número decimal." msgstr "Informe um número decimal válido."
#: core/validators.py:349 #: core/validators.py:349
#, fuzzy, python-format #, fuzzy, python-format
msgid "Please enter a valid decimal number with at most %s total digit." msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s total digits." "Please enter a valid decimal number with at most %s total digits."
msgstr[0] "Por favor entre com um número decimal com no máximo %s digitos." msgstr[0] "Por favor entre com um número decimal com no máximo %s digito."
msgstr[1] "Por favor entre com um número decimal com no máximo %s digitos." msgstr[1] "Por favor entre com um número decimal com no máximo %s digitos."
#: core/validators.py:352 #: core/validators.py:352
@ -1824,7 +1825,7 @@ msgid "Please enter a valid decimal number with at most %s decimal place."
msgid_plural "" msgid_plural ""
"Please enter a valid decimal number with at most %s decimal places." "Please enter a valid decimal number with at most %s decimal places."
msgstr[0] "Informe um número decimal com no máximo %s casa decimal." msgstr[0] "Informe um número decimal com no máximo %s casa decimal."
msgstr[1] "Informe um número decimal com no máximo %s casa decimal." msgstr[1] "Informe um número decimal com no máximo %s casas decimais."
#: core/validators.py:362 #: core/validators.py:362
#, python-format #, python-format
@ -1930,17 +1931,17 @@ msgstr "Este campo é requerido."
#: db/models/fields/__init__.py:337 #: db/models/fields/__init__.py:337
#, fuzzy #, fuzzy
msgid "This value must be an integer." msgid "This value must be an integer."
msgstr "Este valor deve ser uma potência de %s." msgstr "Este valor deve ser um inteiro."
#: db/models/fields/__init__.py:369 #: db/models/fields/__init__.py:369
#, fuzzy #, fuzzy
msgid "This value must be either True or False." msgid "This value must be either True or False."
msgstr "Este valor deve ser uma potência de %s." msgstr "Este valor deve ser Verdadeiro ou Falso."
#: db/models/fields/__init__.py:385 #: db/models/fields/__init__.py:385
#, fuzzy #, fuzzy
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "Este campo é inválido." msgstr "Este campo não pode ser nulo."
#: db/models/fields/__init__.py:562 #: db/models/fields/__init__.py:562
msgid "Enter a valid filename." msgid "Enter a valid filename."
@ -1954,14 +1955,14 @@ msgstr "Por favor informe um %s válido."
#: db/models/fields/related.py:579 #: db/models/fields/related.py:579
#, fuzzy #, fuzzy
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr " Separe IDs múltiplos com vírgulas." msgstr "Separe IDs múltiplos com vírgulas."
#: db/models/fields/related.py:581 #: db/models/fields/related.py:581
#, fuzzy #, fuzzy
msgid "" msgid ""
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr "" msgstr ""
" Mantenha pressionado \"Control\", ou \"Command\" num Mac para selecionar " " Mantenha pressionado \"Control\", ou \"Command\" no Mac para selecionar "
"mais de uma opção." "mais de uma opção."
#: db/models/fields/related.py:625 #: db/models/fields/related.py:625
@ -1972,18 +1973,18 @@ msgid_plural ""
msgstr[0] "" msgstr[0] ""
"Por favor, entre IDs válidos para %(self)s. O valor %(value)r é inválido." "Por favor, entre IDs válidos para %(self)s. O valor %(value)r é inválido."
msgstr[1] "" msgstr[1] ""
"Por favor, entre IDs válidos para %(self)s. O valor %(value)r é inválido." "Por favor, entre IDs válidos para %(self)s. Os valores %(value)r são inválidos."
#: forms/__init__.py:380 #: forms/__init__.py:380
#, fuzzy, python-format #, fuzzy, python-format
msgid "Ensure your text is less than %s character." msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters." msgid_plural "Ensure your text is less than %s characters."
msgstr[0] "Certifique-se de que seu texto tenha menos que %s caracteres." msgstr[0] "Certifique-se de que seu texto tenha menos que %s caractere."
msgstr[1] "Certifique-se de que seu texto tenha menos que %s caracteres." msgstr[1] "Certifique-se de que seu texto tenha menos que %s caracteres."
#: forms/__init__.py:385 #: forms/__init__.py:385
msgid "Line breaks are not allowed here." msgid "Line breaks are not allowed here."
msgstr "Não são permitidas múltiplas linhas aqui." msgstr "Não são permitidas quebras de linha aqui."
#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 #: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589
#, python-format #, python-format
@ -2037,7 +2038,7 @@ msgstr "sim,não,talvez"
#~ "\n" #~ "\n"
#~ "%(text)s" #~ "%(text)s"
#~ msgstr "" #~ msgstr ""
#~ "Este comentário foi envidao por um usuário que enviou menos de %(count)s " #~ "Este comentário foi enviado por um usuário que enviou menos de %(count)s "
#~ "comentário:\n" #~ "comentário:\n"
#~ "\n" #~ "\n"
#~ "%(text)sEste comentário foi enviado por um usuário que enviou menos de %" #~ "%(text)sEste comentário foi enviado por um usuário que enviou menos de %"
@ -2047,4 +2048,4 @@ msgstr "sim,não,talvez"
#, fuzzy #, fuzzy
#~ msgid "count" #~ msgid "count"
#~ msgstr "conteúdo" #~ msgstr "contagem"

View File

@ -1,15 +1,15 @@
# SOME DESCRIPTIVE TITLE. # Português do Brasil translation of django.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # Carlos Eduardo de Paula <carlosedp@gmail.com>, 2006.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django\n" "Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n" "POT-Creation-Date: 2005-12-09 11:51+0100\n"
"PO-Revision-Date: 2006-01-23 19:54-0200\n" "PO-Revision-Date: 2006-11-01 17:45-0300\n"
"Last-Translator: João Marcus Christ <joaoma@gmail.com>\n" "Last-Translator: Carlos Eduardo de Paula <carlosedp@gmail.com>\n"
"Language-Team: Português do Brasil <pt-br@li.org>\n" "Language-Team: Português do Brasil <pt-br@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -51,7 +51,7 @@ msgid ""
"January February March April May June July August September October November " "January February March April May June July August September October November "
"December" "December"
msgstr "" msgstr ""
"Janeiro Fevereiro Março Abrio Maio Junho Julho Agosto Setembro Outubro Novembro " "Janeiro Fevereiro Março Abril Maio Junho Julho Agosto Setembro Outubro Novembro "
"Dezembro" "Dezembro"
#: contrib/admin/media/js/dateparse.js:27 #: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"

View File

@ -169,8 +169,8 @@ var dateParsePatterns = [
handler: function(bits) { handler: function(bits) {
var d = new Date(); var d = new Date();
d.setYear(parseInt(bits[1])); d.setYear(parseInt(bits[1]));
d.setDate(parseInt(bits[3], 10));
d.setMonth(parseInt(bits[2], 10) - 1); d.setMonth(parseInt(bits[2], 10) - 1);
d.setDate(parseInt(bits[3], 10));
return d; return d;
} }
}, },

View File

@ -19,7 +19,7 @@
<div class="form-row"> <div class="form-row">
<label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> <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="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>
<div class="submit-row"> <div class="submit-row">
<label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" /> <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />

View File

@ -177,8 +177,8 @@ def output_all(form_fields):
output_all = register.simple_tag(output_all) output_all = register.simple_tag(output_all)
def auto_populated_field_script(auto_pop_fields, change = False): def auto_populated_field_script(auto_pop_fields, change = False):
t = []
for field in auto_pop_fields: for field in auto_pop_fields:
t = []
if change: if change:
t.append('document.getElementById("id_%s")._changed = true;' % field.name) t.append('document.getElementById("id_%s")._changed = true;' % field.name)
else: else:
@ -197,8 +197,8 @@ def filter_interface_script_maybe(bound_field):
f = bound_field.field f = bound_field.field
if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface: if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface:
return '<script type="text/javascript">addEvent(window, "load", function(e) {' \ return '<script type="text/javascript">addEvent(window, "load", function(e) {' \
' SelectFilter.init("id_%s", %r, %s, "%s"); });</script>\n' % ( ' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
f.name, f.verbose_name, f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX) f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX)
else: else:
return '' return ''
filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe) 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.admin.views.decorators import staff_member_required
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from django import forms, template from django import forms, template
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect

View File

@ -98,13 +98,13 @@ def view_index(request):
return missing_docutils_page(request) return missing_docutils_page(request)
if settings.ADMIN_FOR: if settings.ADMIN_FOR:
settings_modules = [__import__(m, '', '', ['']) for m in settings.ADMIN_FOR] settings_modules = [__import__(m, {}, {}, ['']) for m in settings.ADMIN_FOR]
else: else:
settings_modules = [settings] settings_modules = [settings]
views = [] views = []
for settings_mod in settings_modules: for settings_mod in settings_modules:
urlconf = __import__(settings_mod.ROOT_URLCONF, '', '', ['']) urlconf = __import__(settings_mod.ROOT_URLCONF, {}, {}, [''])
view_functions = extract_views_from_urlpatterns(urlconf.urlpatterns) view_functions = extract_views_from_urlpatterns(urlconf.urlpatterns)
if Site._meta.installed: if Site._meta.installed:
site_obj = Site.objects.get(pk=settings_mod.SITE_ID) site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
@ -127,7 +127,7 @@ def view_detail(request, view):
mod, func = urlresolvers.get_mod_func(view) mod, func = urlresolvers.get_mod_func(view)
try: try:
view_func = getattr(__import__(mod, '', '', ['']), func) view_func = getattr(__import__(mod, {}, {}, ['']), func)
except (ImportError, AttributeError): except (ImportError, AttributeError):
raise Http404 raise Http404
title, body, metadata = utils.parse_docstring(view_func.__doc__) title, body, metadata = utils.parse_docstring(view_func.__doc__)
@ -235,7 +235,7 @@ model_detail = staff_member_required(model_detail)
def template_detail(request, template): def template_detail(request, template):
templates = [] templates = []
for site_settings_module in settings.ADMIN_FOR: for site_settings_module in settings.ADMIN_FOR:
settings_mod = __import__(site_settings_module, '', '', ['']) settings_mod = __import__(site_settings_module, {}, {}, [''])
if Site._meta.installed: if Site._meta.installed:
site_obj = Site.objects.get(pk=settings_mod.SITE_ID) site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
else: else:

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: if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
if not user.has_perm(p): 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(): for related in opts.get_all_related_many_to_many_objects():
if related.opts in opts_seen: if related.opts in opts_seen:
continue continue

View File

@ -14,7 +14,7 @@ def template_validator(request):
# get a dict of {site_id : settings_module} for the validator # get a dict of {site_id : settings_module} for the validator
settings_modules = {} settings_modules = {}
for mod in settings.ADMIN_FOR: for mod in settings.ADMIN_FOR:
settings_module = __import__(mod, '', '', ['']) settings_module = __import__(mod, {}, {}, [''])
settings_modules[settings_module.SITE_ID] = settings_module settings_modules[settings_module.SITE_ID] = settings_module
manipulator = TemplateValidator(settings_modules) manipulator = TemplateValidator(settings_modules)
new_data, errors = {}, {} new_data, errors = {}, {}

View File

@ -9,7 +9,7 @@ def load_backend(path):
i = path.rfind('.') i = path.rfind('.')
module, attr = path[:i], path[i+1:] module, attr = path[:i], path[i+1:]
try: try:
mod = __import__(module, '', '', [attr]) mod = __import__(module, {}, {}, [attr])
except ImportError, e: except ImportError, e:
raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e) raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e)
try: try:

View File

@ -92,9 +92,9 @@ class User(models.Model):
last_name = models.CharField(_('last name'), maxlength=30, blank=True) last_name = models.CharField(_('last name'), maxlength=30, blank=True)
email = models.EmailField(_('e-mail address'), blank=True) email = models.EmailField(_('e-mail address'), blank=True)
password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]'")) 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_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()) last_login = models.DateTimeField(_('last login'), default=models.LazyDate())
date_joined = models.DateTimeField(_('date joined'), default=models.LazyDate()) date_joined = models.DateTimeField(_('date joined'), default=models.LazyDate())
groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
@ -126,7 +126,7 @@ class User(models.Model):
def is_anonymous(self): def is_anonymous(self):
"Always returns False. This is a way of comparing User objects to anonymous users." "Always returns False. This is a way of comparing User objects to anonymous users."
return False return False
def is_authenticated(self): def is_authenticated(self):
"""Always return True. This is a way to tell if the user has been authenticated in templates. """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): def __str__(self):
return 'AnonymousUser' 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): def save(self):
raise NotImplementedError raise NotImplementedError
@ -301,6 +310,6 @@ class AnonymousUser(object):
def is_anonymous(self): def is_anonymous(self):
return True return True
def is_authenticated(self): def is_authenticated(self):
return False return False

View File

@ -34,7 +34,7 @@ class CommentManager(models.Manager):
""" """
Given a rating_string, this returns a tuple of (rating_range, options). Given a rating_string, this returns a tuple of (rating_range, options).
>>> s = "scale:1-10|First_category|Second_category" >>> s = "scale:1-10|First_category|Second_category"
>>> get_rating_options(s) >>> Comment.objects.get_rating_options(s)
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ['First category', 'Second category']) ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ['First category', 'Second category'])
""" """
rating_range, options = rating_string.split('|', 1) rating_range, options = rating_string.split('|', 1)

View File

@ -109,7 +109,7 @@ class PublicCommentManipulator(AuthenticationForm):
# send the comment to the managers. # send the comment to the managers.
if self.user_cache.comment_set.count() <= settings.COMMENTS_FIRST_FEW: 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', 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()} {'count': settings.COMMENTS_FIRST_FEW, 'text': c.get_as_text()}
mail_managers("Comment posted by rookie user", message) 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()]: 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) errors = manipulator.get_validation_errors(new_data)
# If user gave correct username/password and wasn't already logged in, log them in # 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. # 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 from django.contrib.auth import login
login(request, manipulator.get_user()) login(request, manipulator.get_user())
if errors or request.POST.has_key('preview'): if errors or request.POST.has_key('preview'):

View File

@ -48,7 +48,7 @@ def get_cache(backend_uri):
if host.endswith('/'): if host.endswith('/'):
host = host[:-1] host = host[:-1]
cache_class = getattr(__import__('django.core.cache.backends.%s' % BACKENDS[scheme], '', '', ['']), 'CacheClass') cache_class = getattr(__import__('django.core.cache.backends.%s' % BACKENDS[scheme], {}, {}, ['']), 'CacheClass')
return cache_class(host, params) return cache_class(host, params)
cache = get_cache(settings.CACHE_BACKEND) cache = get_cache(settings.CACHE_BACKEND)

View File

@ -26,7 +26,7 @@ class BaseHandler(object):
raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:] mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
try: try:
mod = __import__(mw_module, '', '', ['']) mod = __import__(mw_module, {}, {}, [''])
except ImportError, e: except ImportError, e:
raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e) raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
try: try:

View File

@ -41,6 +41,7 @@ class ModPythonRequest(http.HttpRequest):
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '') return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
def is_secure(self): 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' return self._req.subprocess_env.has_key('HTTPS') and self._req.subprocess_env['HTTPS'] == 'on'
def _load_post_and_files(self): def _load_post_and_files(self):
@ -102,7 +103,7 @@ class ModPythonRequest(http.HttpRequest):
'REQUEST_METHOD': self._req.method, 'REQUEST_METHOD': self._req.method,
'SCRIPT_NAME': None, # Not supported 'SCRIPT_NAME': None, # Not supported
'SERVER_NAME': self._req.server.server_hostname, '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_PROTOCOL': self._req.protocol,
'SERVER_SOFTWARE': 'mod_python' 'SERVER_SOFTWARE': 'mod_python'
} }

View File

@ -4,6 +4,9 @@ from django.conf import settings
from email.MIMEText import MIMEText from email.MIMEText import MIMEText
from email.Header import Header from email.Header import Header
import smtplib, rfc822 import smtplib, rfc822
import socket
import time
import random
class BadHeaderError(ValueError): class BadHeaderError(ValueError):
pass pass
@ -50,6 +53,7 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=settings.EMAIL_HOST
msg['From'] = from_email msg['From'] = from_email
msg['To'] = ', '.join(recipient_list) msg['To'] = ', '.join(recipient_list)
msg['Date'] = rfc822.formatdate() msg['Date'] = rfc822.formatdate()
msg['Message-ID'] = "<%d.%d@%s>" % (time.time(), random.getrandbits(64), socket.getfqdn())
try: try:
server.sendmail(from_email, recipient_list, msg.as_string()) server.sendmail(from_email, recipient_list, msg.as_string())
num_sent += 1 num_sent += 1

View File

@ -32,6 +32,7 @@ class dummy: pass
style = dummy() style = dummy()
style.ERROR = termcolors.make_style(fg='red', opts=('bold',)) style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
style.ERROR_OUTPUT = 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_FIELD = termcolors.make_style(fg='green', opts=('bold',))
style.SQL_COLTYPE = termcolors.make_style(fg='green') style.SQL_COLTYPE = termcolors.make_style(fg='green')
style.SQL_KEYWORD = termcolors.make_style(fg='yellow') style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
@ -348,6 +349,8 @@ def get_sql_initial_data_for_model(model):
if os.path.exists(sql_file): if os.path.exists(sql_file):
fp = open(sql_file, 'U') fp = open(sql_file, 'U')
for statement in statements.split(fp.read()): for statement in statements.split(fp.read()):
# Remove any comments from the file
statement = re.sub(r"--.*[\n\Z]", "", statement)
if statement.strip(): if statement.strip():
output.append(statement + ";") output.append(statement + ";")
fp.close() fp.close()
@ -445,7 +448,7 @@ def syncdb(verbosity=1, interactive=True):
# dispatcher events. # dispatcher events.
for app_name in settings.INSTALLED_APPS: for app_name in settings.INSTALLED_APPS:
try: try:
__import__(app_name + '.management', '', '', ['']) __import__(app_name + '.management', {}, {}, [''])
except ImportError: except ImportError:
pass pass
@ -540,7 +543,7 @@ def syncdb(verbosity=1, interactive=True):
transaction.rollback_unless_managed() transaction.rollback_unless_managed()
else: else:
transaction.commit_unless_managed() transaction.commit_unless_managed()
syncdb.args = '' syncdb.args = ''
def get_admin_index(app): def get_admin_index(app):
@ -627,6 +630,7 @@ install.args = APP_ARGS
def reset(app, interactive=True): def reset(app, interactive=True):
"Executes the equivalent of 'get_sql_reset' in the current database." "Executes the equivalent of 'get_sql_reset' in the current database."
from django.db import connection, transaction from django.db import connection, transaction
from django.conf import settings
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
disable_termcolors() disable_termcolors()
@ -638,13 +642,14 @@ def reset(app, interactive=True):
if interactive: if interactive:
confirm = raw_input(""" confirm = raw_input("""
You have requested a database reset. 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? 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: else:
confirm = 'yes' confirm = 'yes'
if confirm == 'yes': if confirm == 'yes':
try: try:
cursor = connection.cursor() cursor = connection.cursor()
@ -694,7 +699,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_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
fp_old.close() fp_old.close()
fp_new.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): def startproject(project_name, directory):
"Creates a Django project for the given project_name in the given directory." "Creates a Django project for the given project_name in the given directory."
@ -1224,7 +1232,7 @@ def test(app_labels, verbosity=1):
test_module_name = '.'.join(test_path[:-1]) test_module_name = '.'.join(test_path[:-1])
else: else:
test_module_name = '.' test_module_name = '.'
test_module = __import__(test_module_name, [],[],test_path[-1]) test_module = __import__(test_module_name, {}, {}, test_path[-1])
test_runner = getattr(test_module, test_path[-1]) test_runner = getattr(test_module, test_path[-1])
test_runner(app_list, verbosity) test_runner(app_list, verbosity)
@ -1413,7 +1421,7 @@ def setup_environ(settings_mod):
project_directory = os.path.dirname(settings_mod.__file__) project_directory = os.path.dirname(settings_mod.__file__)
project_name = os.path.basename(project_directory) project_name = os.path.basename(project_directory)
sys.path.append(os.path.join(project_directory, '..')) sys.path.append(os.path.join(project_directory, '..'))
project_module = __import__(project_name, '', '', ['']) project_module = __import__(project_name, {}, {}, [''])
sys.path.pop() sys.path.pop()
# Set DJANGO_SETTINGS_MODULE appropriately. # Set DJANGO_SETTINGS_MODULE appropriately.

View File

@ -1,54 +1,46 @@
from math import ceil
class InvalidPage(Exception): class InvalidPage(Exception):
pass pass
class ObjectPaginator(object): class ObjectPaginator(object):
""" """
This class makes pagination easy. Feed it a QuerySet, plus the number of This class makes pagination easy. Feed it a QuerySet or list, plus the number
objects you want on each page. Then read the hits and pages properties to of objects you want on each page. Then read the hits and pages properties to
see how many pages it involves. Call get_page with a page number (starting see how many pages it involves. Call get_page with a page number (starting
at 0) to get back a list of objects for that page. at 0) to get back a list of objects for that page.
Finally, check if a page number has a next/prev page using Finally, check if a page number has a next/prev page using
has_next_page(page_number) and has_previous_page(page_number). has_next_page(page_number) and has_previous_page(page_number).
Use orphans to avoid small final pages. For example:
13 records, num_per_page=10, orphans=2 --> pages==2, len(self.get_page(0))==10
12 records, num_per_page=10, orphans=2 --> pages==1, len(self.get_page(0))==12
""" """
def __init__(self, query_set, num_per_page): def __init__(self, query_set, num_per_page, orphans=0):
self.query_set = query_set self.query_set = query_set
self.num_per_page = num_per_page self.num_per_page = num_per_page
self._hits, self._pages = None, None self.orphans = orphans
self._has_next = {} # Caches page_number -> has_next_boolean self._hits = self._pages = None
def get_page(self, page_number): def validate_page_number(self, page_number):
try: try:
page_number = int(page_number) page_number = int(page_number)
except ValueError: except ValueError:
raise InvalidPage raise InvalidPage
if page_number < 0: if page_number < 0 or page_number > self.pages - 1:
raise InvalidPage raise InvalidPage
return page_number
# Retrieve one extra record, and check for the existence of that extra def get_page(self, page_number):
# record to determine whether there's a next page. page_number = self.validate_page_number(page_number)
limit = self.num_per_page + 1 bottom = page_number * self.num_per_page
offset = page_number * self.num_per_page top = bottom + self.num_per_page
if top + self.orphans >= self.hits:
object_list = list(self.query_set[offset:offset+limit]) top = self.hits
return self.query_set[bottom:top]
if not object_list:
raise InvalidPage
self._has_next[page_number] = (len(object_list) > self.num_per_page)
return object_list[:self.num_per_page]
def has_next_page(self, page_number): def has_next_page(self, page_number):
"Does page $page_number have a 'next' page?" "Does page $page_number have a 'next' page?"
if not self._has_next.has_key(page_number): return page_number < self.pages - 1
if self._pages is None:
offset = (page_number + 1) * self.num_per_page
self._has_next[page_number] = len(self.query_set[offset:offset+1]) > 0
else:
self._has_next[page_number] = page_number < (self.pages - 1)
return self._has_next[page_number]
def has_previous_page(self, page_number): def has_previous_page(self, page_number):
return page_number > 0 return page_number > 0
@ -58,8 +50,7 @@ class ObjectPaginator(object):
Returns the 1-based index of the first object on the given page, Returns the 1-based index of the first object on the given page,
relative to total objects found (hits). relative to total objects found (hits).
""" """
if page_number == 0: page_number = self.validate_page_number(page_number)
return 1
return (self.num_per_page * page_number) + 1 return (self.num_per_page * page_number) + 1
def last_on_page(self, page_number): def last_on_page(self, page_number):
@ -67,20 +58,30 @@ class ObjectPaginator(object):
Returns the 1-based index of the last object on the given page, Returns the 1-based index of the last object on the given page,
relative to total objects found (hits). relative to total objects found (hits).
""" """
if page_number == 0 and self.num_per_page >= self._hits: page_number = self.validate_page_number(page_number)
return self._hits page_number += 1 # 1-base
elif page_number == (self._pages - 1) and (page_number + 1) * self.num_per_page > self._hits: if page_number == self.pages:
return self._hits return self.hits
return (page_number + 1) * self.num_per_page return page_number * self.num_per_page
def _get_hits(self): def _get_hits(self):
if self._hits is None: if self._hits is None:
self._hits = self.query_set.count() # Try .count() or fall back to len().
try:
self._hits = int(self.query_set.count())
except (AttributeError, TypeError, ValueError):
# AttributeError if query_set has no object count.
# TypeError if query_set.count() required arguments.
# ValueError if int() fails.
self._hits = len(self.query_set)
return self._hits return self._hits
def _get_pages(self): def _get_pages(self):
if self._pages is None: if self._pages is None:
self._pages = int(ceil(self.hits / float(self.num_per_page))) hits = (self.hits - 1 - self.orphans)
if hits < 1:
hits = 0
self._pages = hits // self.num_per_page + 1
return self._pages return self._pages
hits = property(_get_hits) hits = property(_get_hits)

View File

@ -29,7 +29,7 @@ _serializers = {}
def register_serializer(format, serializer_module): def register_serializer(format, serializer_module):
"""Register a new serializer by passing in a module name.""" """Register a new serializer by passing in a module name."""
module = __import__(serializer_module, '', '', ['']) module = __import__(serializer_module, {}, {}, [''])
_serializers[format] = module _serializers[format] = module
def unregister_serializer(format): def unregister_serializer(format):

View File

@ -28,6 +28,7 @@ class Serializer(object):
self.options = options self.options = options
self.stream = options.get("stream", StringIO()) self.stream = options.get("stream", StringIO())
self.selected_fields = options.get("fields")
self.start_serialization() self.start_serialization()
for obj in queryset: for obj in queryset:
@ -36,11 +37,14 @@ class Serializer(object):
if field is obj._meta.pk: if field is obj._meta.pk:
continue continue
elif field.rel is None: elif field.rel is None:
self.handle_field(obj, field) if self.selected_fields is None or field.attname in self.selected_fields:
self.handle_field(obj, field)
else: else:
self.handle_fk_field(obj, field) if self.selected_fields is None or field.attname[:-3] in self.selected_fields:
self.handle_fk_field(obj, field)
for field in obj._meta.many_to_many: for field in obj._meta.many_to_many:
self.handle_m2m_field(obj, field) if self.selected_fields is None or field.attname in self.selected_fields:
self.handle_m2m_field(obj, field)
self.end_object(obj) self.end_object(obj)
self.end_serialization() self.end_serialization()
return self.getvalue() return self.getvalue()

View File

@ -76,7 +76,7 @@ def Deserializer(object_list, **options):
m2m_data[field.name] = field.rel.to._default_manager.in_bulk(field_value).values() m2m_data[field.name] = field.rel.to._default_manager.in_bulk(field_value).values()
# Handle FK fields # Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel): elif field.rel and isinstance(field.rel, models.ManyToOneRel) and field_value is not None:
try: try:
data[field.name] = field.rel.to._default_manager.get(pk=field_value) data[field.name] = field.rel.to._default_manager.get(pk=field_value)
except field.rel.to.DoesNotExist: except field.rel.to.DoesNotExist:

View File

@ -166,7 +166,11 @@ class Deserializer(base.Deserializer):
# If it doesn't exist, set the field to None (which might trigger # If it doesn't exist, set the field to None (which might trigger
# validation error, but that's expected). # validation error, but that's expected).
RelatedModel = self._get_model_from_node(node, "to") RelatedModel = self._get_model_from_node(node, "to")
return RelatedModel.objects.get(pk=getInnerText(node).strip().encode(self.encoding)) # Check if there is a child node named 'None', returning None if so.
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
return None
else:
return RelatedModel.objects.get(pk=getInnerText(node).strip().encode(self.encoding))
def _handle_m2m_field_node(self, node): def _handle_m2m_field_node(self, node):
""" """

View File

@ -31,9 +31,11 @@ Optional Fcgi settings: (setting=value)
port=PORTNUM port to listen on. port=PORTNUM port to listen on.
socket=FILE UNIX socket to listen on. socket=FILE UNIX socket to listen on.
method=IMPL prefork or threaded (default prefork) method=IMPL prefork or threaded (default prefork)
maxspare=NUMBER max number of spare processes to keep running. maxrequests=NUMBER number of requests a child handles before it is
minspare=NUMBER min number of spare processes to prefork. killed and a new child is forked (0 = no limit).
maxchildren=NUMBER hard limit number of processes in prefork mode. maxspare=NUMBER max number of spare processes / threads
minspare=NUMBER min number of spare processes / threads.
maxchildren=NUMBER hard limit number of processes / threads
daemonize=BOOL whether to detach from terminal. daemonize=BOOL whether to detach from terminal.
pidfile=FILE write the spawned process-id to this file. pidfile=FILE write the spawned process-id to this file.
workdir=DIRECTORY change to this directory when daemonizing workdir=DIRECTORY change to this directory when daemonizing
@ -66,6 +68,7 @@ FASTCGI_OPTIONS = {
'maxspare': 5, 'maxspare': 5,
'minspare': 2, 'minspare': 2,
'maxchildren': 50, 'maxchildren': 50,
'maxrequests': 0,
} }
def fastcgi_help(message=None): def fastcgi_help(message=None):
@ -103,10 +106,15 @@ def runfastcgi(argset=[], **kwargs):
'maxSpare': int(options["maxspare"]), 'maxSpare': int(options["maxspare"]),
'minSpare': int(options["minspare"]), 'minSpare': int(options["minspare"]),
'maxChildren': int(options["maxchildren"]), 'maxChildren': int(options["maxchildren"]),
'maxRequests': int(options["maxrequests"]),
} }
elif options['method'] in ('thread', 'threaded'): elif options['method'] in ('thread', 'threaded'):
from flup.server.fcgi import WSGIServer from flup.server.fcgi import WSGIServer
wsgi_opts = {} wsgi_opts = {
'maxSpare': int(options["maxspare"]),
'minSpare': int(options["minspare"]),
'maxThreads': int(options["maxchildren"]),
}
else: else:
return fastcgi_help("ERROR: Implementation must be one of prefork or thread.") return fastcgi_help("ERROR: Implementation must be one of prefork or thread.")

View File

@ -21,7 +21,10 @@ class NoReverseMatch(Exception):
def get_mod_func(callback): def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to # Converts 'django.views.news.stories.story_detail' to
# ['django.views.news.stories', 'story_detail'] # ['django.views.news.stories', 'story_detail']
dot = callback.rindex('.') try:
dot = callback.rindex('.')
except ValueError:
return callback, ''
return callback[:dot], callback[dot+1:] return callback[:dot], callback[dot+1:]
def reverse_helper(regex, *args, **kwargs): def reverse_helper(regex, *args, **kwargs):
@ -119,7 +122,7 @@ class RegexURLPattern(object):
return self._callback return self._callback
mod_name, func_name = get_mod_func(self._callback_str) mod_name, func_name = get_mod_func(self._callback_str)
try: try:
self._callback = getattr(__import__(mod_name, '', '', ['']), func_name) self._callback = getattr(__import__(mod_name, {}, {}, ['']), func_name)
except ImportError, e: except ImportError, e:
raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e)) raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e))
except AttributeError, e: except AttributeError, e:
@ -130,7 +133,7 @@ class RegexURLPattern(object):
def reverse(self, viewname, *args, **kwargs): def reverse(self, viewname, *args, **kwargs):
mod_name, func_name = get_mod_func(viewname) mod_name, func_name = get_mod_func(viewname)
try: try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
except (ImportError, AttributeError): except (ImportError, AttributeError):
raise NoReverseMatch raise NoReverseMatch
if lookup_view != self.callback: if lookup_view != self.callback:
@ -171,7 +174,7 @@ class RegexURLResolver(object):
return self._urlconf_module return self._urlconf_module
except AttributeError: except AttributeError:
try: try:
self._urlconf_module = __import__(self.urlconf_name, '', '', ['']) self._urlconf_module = __import__(self.urlconf_name, {}, {}, [''])
except ValueError, e: except ValueError, e:
# Invalid urlconf_name, such as "foo.bar." (note trailing period) # Invalid urlconf_name, such as "foo.bar." (note trailing period)
raise ImproperlyConfigured, "Error while importing URLconf %r: %s" % (self.urlconf_name, e) raise ImproperlyConfigured, "Error while importing URLconf %r: %s" % (self.urlconf_name, e)
@ -186,7 +189,7 @@ class RegexURLResolver(object):
callback = getattr(self.urlconf_module, 'handler%s' % view_type) callback = getattr(self.urlconf_module, 'handler%s' % view_type)
mod_name, func_name = get_mod_func(callback) mod_name, func_name = get_mod_func(callback)
try: try:
return getattr(__import__(mod_name, '', '', ['']), func_name), {} return getattr(__import__(mod_name, {}, {}, ['']), func_name), {}
except (ImportError, AttributeError), e: except (ImportError, AttributeError), e:
raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e)) raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
@ -200,7 +203,7 @@ class RegexURLResolver(object):
if not callable(lookup_view): if not callable(lookup_view):
mod_name, func_name = get_mod_func(lookup_view) mod_name, func_name = get_mod_func(lookup_view)
try: try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
except (ImportError, AttributeError): except (ImportError, AttributeError):
raise NoReverseMatch raise NoReverseMatch
for pattern in self.urlconf_module.urlpatterns: for pattern in self.urlconf_module.urlpatterns:

View File

@ -8,6 +8,7 @@ validator will *always* be run, regardless of whether its associated
form field is required. form field is required.
""" """
import urllib2
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext, gettext_lazy, ngettext from django.utils.translation import gettext, gettext_lazy, ngettext
from django.utils.functional import Promise, lazy from django.utils.functional import Promise, lazy
@ -223,18 +224,26 @@ def isWellFormedXmlFragment(field_data, all_data):
isWellFormedXml('<root>%s</root>' % field_data, all_data) isWellFormedXml('<root>%s</root>' % field_data, all_data)
def isExistingURL(field_data, all_data): def isExistingURL(field_data, all_data):
import urllib2
try: try:
u = urllib2.urlopen(field_data) headers = {
"Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
"Accept-Language" : "en-us,en;q=0.5",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Connection" : "close",
"User-Agent": settings.URL_VALIDATOR_USER_AGENT
}
req = urllib2.Request(field_data,None, headers)
u = urllib2.urlopen(req)
except ValueError: except ValueError:
raise ValidationError, gettext("Invalid URL: %s") % field_data raise ValidationError, _("Invalid URL: %s") % field_data
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
# 401s are valid; they just mean authorization is required. # 401s are valid; they just mean authorization is required.
if e.code not in ('401',): # 301 and 302 are redirects; they just mean look somewhere else.
raise ValidationError, gettext("The URL %s is a broken link.") % field_data if str(e.code) not in ('401','301','302'):
raise ValidationError, _("The URL %s is a broken link.") % field_data
except: # urllib2.URLError, httplib.InvalidURL, etc. except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError, gettext("The URL %s is a broken link.") % field_data raise ValidationError, _("The URL %s is a broken link.") % field_data
def isValidUSState(field_data, all_data): def isValidUSState(field_data, all_data):
"Checks that the given string is a valid two-letter U.S. state abbreviation" "Checks that the given string is a valid two-letter U.S. state abbreviation"
states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY'] states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY']
@ -344,6 +353,38 @@ class UniqueAmongstFieldsWithPrefix(object):
if field_name != self.field_name and value == field_data: if field_name != self.field_name and value == field_data:
raise ValidationError, self.error_message raise ValidationError, self.error_message
class NumberIsInRange(object):
"""
Validator that tests if a value is in a range (inclusive).
"""
def __init__(self, lower=None, upper=None, error_message=''):
self.lower, self.upper = lower, upper
if not error_message:
if lower and upper:
self.error_message = gettext("This value must be between %s and %s.") % (lower, upper)
elif lower:
self.error_message = gettext("This value must be at least %s.") % lower
elif upper:
self.error_message = gettext("This value must be no more than %s.") % upper
else:
self.error_message = error_message
def __call__(self, field_data, all_data):
# Try to make the value numeric. If this fails, we assume another
# validator will catch the problem.
try:
val = float(field_data)
except ValueError:
return
# Now validate
if self.lower and self.upper and (val < self.lower or val > self.upper):
raise ValidationError(self.error_message)
elif self.lower and val < self.lower:
raise ValidationError(self.error_message)
elif self.upper and val > self.upper:
raise ValidationError(self.error_message)
class IsAPowerOf(object): class IsAPowerOf(object):
""" """
>>> v = IsAPowerOf(2) >>> v = IsAPowerOf(2)

View File

@ -8,7 +8,7 @@ if not settings.DATABASE_ENGINE:
settings.DATABASE_ENGINE = 'dummy' settings.DATABASE_ENGINE = 'dummy'
try: try:
backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', ['']) backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
except ImportError, e: except ImportError, e:
# The database backend wasn't found. Display a helpful error message # The database backend wasn't found. Display a helpful error message
# listing all possible database backends. # listing all possible database backends.
@ -23,11 +23,11 @@ except ImportError, e:
else: else:
raise # If there's some other error, this must be an error in Django itself. raise # If there's some other error, this must be an error in Django itself.
get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, '', '', ['']) get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, {}, {}, [''])
get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, '', '', ['']) get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])
runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, '', '', ['']).runshell() runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, {}, {}, ['']).runshell()
connection = backend.DatabaseWrapper() connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
DatabaseError = backend.DatabaseError DatabaseError = backend.DatabaseError
# Register an event that closes the database connection # Register an event that closes the database connection

View File

@ -55,7 +55,7 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []

View File

@ -20,6 +20,9 @@ class DatabaseWrapper:
_commit = complain _commit = complain
_rollback = complain _rollback = complain
def __init__(self, **kwargs):
pass
def close(self): def close(self):
pass # close() pass # close()

View File

@ -65,10 +65,11 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []
self.server_version = None self.server_version = None
self.options = kwargs
def _valid_connection(self): def _valid_connection(self):
if self.connection is not None: if self.connection is not None:
@ -95,6 +96,7 @@ class DatabaseWrapper(local):
kwargs['host'] = settings.DATABASE_HOST kwargs['host'] = settings.DATABASE_HOST
if settings.DATABASE_PORT: if settings.DATABASE_PORT:
kwargs['port'] = int(settings.DATABASE_PORT) kwargs['port'] = int(settings.DATABASE_PORT)
kwargs.update(self.options)
self.connection = Database.connect(**kwargs) self.connection = Database.connect(**kwargs)
cursor = self.connection.cursor() cursor = self.connection.cursor()
if self.connection.get_server_info() >= '4.1': if self.connection.get_server_info() >= '4.1':

View File

@ -21,9 +21,10 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []
self.options = kwargs
def _valid_connection(self): def _valid_connection(self):
return self.connection is not None return self.connection is not None
@ -35,10 +36,10 @@ class DatabaseWrapper(local):
settings.DATABASE_HOST = 'localhost' settings.DATABASE_HOST = 'localhost'
if len(settings.DATABASE_PORT.strip()) != 0: if len(settings.DATABASE_PORT.strip()) != 0:
dsn = Database.makedsn(settings.DATABASE_HOST, int(settings.DATABASE_PORT), settings.DATABASE_NAME) dsn = Database.makedsn(settings.DATABASE_HOST, int(settings.DATABASE_PORT), settings.DATABASE_NAME)
self.connection = Database.connect(settings.DATABASE_USER, settings.DATABASE_PASSWORD, dsn) self.connection = Database.connect(settings.DATABASE_USER, settings.DATABASE_PASSWORD, dsn, **self.options)
else: else:
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
self.connection = Database.connect(conn_string) self.connection = Database.connect(conn_string, **self.options)
return FormatStylePlaceholderCursor(self.connection) return FormatStylePlaceholderCursor(self.connection)
def _commit(self): def _commit(self):

View File

@ -21,9 +21,10 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []
self.options = kwargs
def cursor(self): def cursor(self):
from django.conf import settings from django.conf import settings
@ -40,7 +41,7 @@ class DatabaseWrapper(local):
conn_string += " host=%s" % settings.DATABASE_HOST conn_string += " host=%s" % settings.DATABASE_HOST
if settings.DATABASE_PORT: if settings.DATABASE_PORT:
conn_string += " port=%s" % settings.DATABASE_PORT conn_string += " port=%s" % settings.DATABASE_PORT
self.connection = Database.connect(conn_string) self.connection = Database.connect(conn_string, **self.options)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor() cursor = self.connection.cursor()
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])

View File

@ -21,9 +21,10 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []
self.options = kwargs
def cursor(self): def cursor(self):
from django.conf import settings from django.conf import settings
@ -40,7 +41,7 @@ class DatabaseWrapper(local):
conn_string += " host=%s" % settings.DATABASE_HOST conn_string += " host=%s" % settings.DATABASE_HOST
if settings.DATABASE_PORT: if settings.DATABASE_PORT:
conn_string += " port=%s" % settings.DATABASE_PORT conn_string += " port=%s" % settings.DATABASE_PORT
self.connection = Database.connect(conn_string) self.connection = Database.connect(conn_string, **self.options)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor() cursor = self.connection.cursor()
cursor.tzinfo_factory = None cursor.tzinfo_factory = None

View File

@ -42,16 +42,20 @@ except ImportError:
from django.utils._threading_local import local from django.utils._threading_local import local
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self, **kwargs):
self.connection = None self.connection = None
self.queries = [] self.queries = []
self.options = kwargs
def cursor(self): def cursor(self):
from django.conf import settings from django.conf import settings
if self.connection is None: if self.connection is None:
self.connection = Database.connect(settings.DATABASE_NAME, kwargs = {
detect_types=Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES) 'database': settings.DATABASE_NAME,
'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES,
}
kwargs.update(self.options)
self.connection = Database.connect(**kwargs)
# Register extract and date_trunc functions. # Register extract and date_trunc functions.
self.connection.create_function("django_extract", 2, _sqlite_extract) self.connection.create_function("django_extract", 2, _sqlite_extract)
self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)

View File

@ -17,7 +17,7 @@ class CursorDebugWrapper(object):
if not isinstance(params, (tuple, dict)): if not isinstance(params, (tuple, dict)):
params = tuple(params) params = tuple(params)
self.db.queries.append({ self.db.queries.append({
'sql': sql % tuple(params), 'sql': sql % params,
'time': "%.3f" % (stop - start), 'time': "%.3f" % (stop - start),
}) })

View File

@ -376,24 +376,6 @@ class Model(object):
setattr(self, cachename, get_image_dimensions(filename)) setattr(self, cachename, get_image_dimensions(filename))
return getattr(self, cachename) return getattr(self, cachename)
# Handles setting many-to-many related objects.
# Example: Album.set_songs()
def _set_related_many_to_many(self, rel_class, rel_field, id_list):
id_list = map(int, id_list) # normalize to integers
rel = rel_field.rel.to
m2m_table = rel_field.m2m_db_table()
this_id = self._get_pk_val()
cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
(backend.quote_name(m2m_table),
backend.quote_name(rel_field.m2m_column_name())), [this_id])
sql = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
(backend.quote_name(m2m_table),
backend.quote_name(rel_field.m2m_column_name()),
backend.quote_name(rel_field.m2m_reverse_name()))
cursor.executemany(sql, [(this_id, i) for i in id_list])
transaction.commit_unless_managed()
############################################ ############################################
# HELPER FUNCTIONS (CURRIED MODEL METHODS) # # HELPER FUNCTIONS (CURRIED MODEL METHODS) #
############################################ ############################################

View File

@ -457,7 +457,9 @@ class DateField(Field):
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
# Casts dates into string format for entry into database. # Casts dates into string format for entry into database.
if value is not None: if isinstance(value, datetime.datetime):
value = value.date().strftime('%Y-%m-%d')
elif isinstance(value, datetime.date):
value = value.strftime('%Y-%m-%d') value = value.strftime('%Y-%m-%d')
return Field.get_db_prep_save(self, value) return Field.get_db_prep_save(self, value)
@ -487,12 +489,19 @@ class DateTimeField(DateField):
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
# Casts dates into string format for entry into database. # Casts dates into string format for entry into database.
if value is not None: if isinstance(value, datetime.datetime):
# MySQL will throw a warning if microseconds are given, because it # MySQL will throw a warning if microseconds are given, because it
# doesn't support microseconds. # doesn't support microseconds.
if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
value = value.replace(microsecond=0) value = value.replace(microsecond=0)
value = str(value) value = str(value)
elif isinstance(value, datetime.date):
# MySQL will throw a warning if microseconds are given, because it
# doesn't support microseconds.
if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
value = datetime.datetime(value.year, value.month, value.day, microsecond=0)
value = str(value)
return Field.get_db_prep_save(self, value) return Field.get_db_prep_save(self, value)
def get_db_prep_lookup(self, lookup_type, value): def get_db_prep_lookup(self, lookup_type, value):
@ -576,7 +585,7 @@ class FileField(Field):
# If the raw path is passed in, validate it's under the MEDIA_ROOT. # If the raw path is passed in, validate it's under the MEDIA_ROOT.
def isWithinMediaRoot(field_data, all_data): def isWithinMediaRoot(field_data, all_data):
f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data)) f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
if not f.startswith(os.path.normpath(settings.MEDIA_ROOT)): if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
raise validators.ValidationError, _("Enter a valid filename.") raise validators.ValidationError, _("Enter a valid filename.")
field_list[1].validator_list.append(isWithinMediaRoot) field_list[1].validator_list.append(isWithinMediaRoot)
return field_list return field_list

View File

@ -2,7 +2,7 @@ from django.db import backend, transaction
from django.db.models import signals, get_model from django.db.models import signals, get_model
from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class
from django.db.models.related import RelatedObject 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.utils.functional import curry
from django.core import validators from django.core import validators
from django import forms from django import forms

View File

@ -48,7 +48,7 @@ def get_app(app_label, emptyOK=False):
def load_app(app_name): def load_app(app_name):
"Loads the app with the provided fully qualified name, and returns the model module." "Loads the app with the provided fully qualified name, and returns the model module."
global _app_list global _app_list
mod = __import__(app_name, '', '', ['models']) mod = __import__(app_name, {}, {}, ['models'])
if not hasattr(mod, 'models'): if not hasattr(mod, 'models'):
return None return None
if mod.models not in _app_list: if mod.models not in _app_list:

View File

@ -286,7 +286,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
# This is really not going to work for fields that have different # This is really not going to work for fields that have different
# form fields, e.g. DateTime. # form fields, e.g. DateTime.
# This validation needs to occur after html2python to be effective. # This validation needs to occur after html2python to be effective.
field_val = all_data.get(f.attname, None) field_val = all_data.get(f.name, None)
if field_val is None: if field_val is None:
# This will be caught by another validator, assuming the field # This will be caught by another validator, assuming the field
# doesn't have blank=True. # doesn't have blank=True.
@ -303,7 +303,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
pass pass
else: else:
raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \ 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): 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 from django.db.models.fields.related import ManyToOneRel

View File

@ -108,8 +108,13 @@ class FormWrapper(object):
This allows dictionary-style lookups of formfields. It also handles feeding This allows dictionary-style lookups of formfields. It also handles feeding
prepopulated data and validation error messages to the formfield objects. prepopulated data and validation error messages to the formfield objects.
""" """
def __init__(self, manipulator, data, error_dict, edit_inline=True): def __init__(self, manipulator, data=None, error_dict=None, edit_inline=True):
self.manipulator, self.data = manipulator, data self.manipulator = manipulator
if data is None:
data = {}
if error_dict is None:
error_dict = {}
self.data = data
self.error_dict = error_dict self.error_dict = error_dict
self._inline_collections = None self._inline_collections = None
self.edit_inline = edit_inline self.edit_inline = edit_inline

View File

@ -0,0 +1,28 @@
"""
Django validation and HTML form handling.
TODO:
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 util import ValidationError
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

295
django/newforms/fields.py Normal file
View File

@ -0,0 +1,295 @@
"""
Field classes
"""
from util import ValidationError, DEFAULT_ENCODING
from widgets import TextInput, CheckboxInput, Select, SelectMultiple
import datetime
import re
import time
__all__ = (
'Field', 'CharField', 'IntegerField',
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
'RegexField', 'EmailField', 'URLField', 'BooleanField',
'ChoiceField', 'MultipleChoiceField',
'ComboField',
)
# These values, if given to to_python(), will trigger the self.required check.
EMPTY_VALUES = (None, '')
try:
set # Only available in Python 2.4+
except NameError:
from sets import Set as set # Python 2.3 fallback
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 clean(self, value):
"""
Validates the given value and returns its "cleaned" 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 clean(self, value):
"Validates max_length and min_length. Returns a Unicode object."
Field.clean(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 clean(self, value):
"""
Validates that int() can be called on the input. Returns the result
of int().
"""
super(IntegerField, self).clean(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 clean(self, value):
"""
Validates that the input can be converted to a date. Returns a Python
datetime.date object.
"""
Field.clean(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 clean(self, value):
"""
Validates that the input can be converted to a datetime. Returns a
Python datetime.datetime object.
"""
Field.clean(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 clean(self, value):
"""
Validates that the input matches the regular expression. Returns a
Unicode object.
"""
Field.clean(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)
url_re = re.compile(
r'^https?://' # http:// or https://
r'(?:[A-Z0-9-]+\.)+[A-Z]{2,6}' # domain
r'(?::\d+)?' # optional port
r'(?:/?|/\S+)$', re.IGNORECASE)
try:
from django.conf import settings
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
except ImportError:
# It's OK if Django settings aren't configured.
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
class URLField(RegexField):
def __init__(self, required=True, verify_exists=False, widget=None,
validator_user_agent=URL_VALIDATOR_USER_AGENT):
RegexField.__init__(self, url_re, u'Enter a valid URL.', required, widget)
self.verify_exists = verify_exists
self.user_agent = validator_user_agent
def clean(self, value):
value = RegexField.clean(self, value)
if self.verify_exists:
import urllib2
from django.conf import settings
headers = {
"Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Connection": "close",
"User-Agent": self.user_agent,
}
try:
req = urllib2.Request(field_data, None, headers)
u = urllib2.urlopen(req)
except ValueError:
raise ValidationError(u'Enter a valid URL.')
except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError(u'This URL appears to be a broken link.')
return value
class BooleanField(Field):
widget = CheckboxInput
def clean(self, value):
"Returns a Python boolean object."
Field.clean(self, value)
return bool(value)
class ChoiceField(Field):
def __init__(self, choices=(), required=True, widget=Select):
if isinstance(widget, type):
widget = widget(choices=choices)
Field.__init__(self, required, widget)
self.choices = choices
def clean(self, value):
"""
Validates that the input is in self.choices.
"""
value = Field.clean(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)
valid_values = set([str(k) for k, v in self.choices])
if value not in valid_values:
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
return value
class MultipleChoiceField(ChoiceField):
def __init__(self, choices=(), required=True, widget=SelectMultiple):
ChoiceField.__init__(self, choices, required, widget)
def clean(self, value):
"""
Validates that the input is a list or tuple.
"""
if not isinstance(value, (list, tuple)):
raise ValidationError(u'Enter a list of values.')
if self.required and not value:
raise ValidationError(u'This field is required.')
new_value = []
for val in value:
if not isinstance(val, basestring):
value = unicode(str(val), DEFAULT_ENCODING)
elif not isinstance(val, unicode):
value = unicode(val, DEFAULT_ENCODING)
new_value.append(value)
# Validate that each value in the value list is in self.choices.
valid_values = set([k for k, v in self.choices])
for val in new_value:
if val not in valid_values:
raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % val)
return new_value
class ComboField(Field):
def __init__(self, fields=(), required=True, widget=None):
Field.__init__(self, required, widget)
self.fields = fields
def clean(self, value):
"""
Validates the given value against all of self.fields, which is a
list of Field instances.
"""
Field.clean(self, value)
for field in self.fields:
value = field.clean(value)
return value

169
django/newforms/forms.py Normal file
View File

@ -0,0 +1,169 @@
"""
Form classes
"""
from fields import Field
from widgets import TextInput, Textarea
from util import ErrorDict, ErrorList, ValidationError
NON_FIELD_ERRORS = '__all__'
def pretty_name(name):
"Converts 'first_name' to 'First name'"
name = name[0].upper() + name[1:]
return name.replace('_', ' ')
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.clean_data = None # Stores the data after clean() has been called.
self.__errors = None # Stores the errors after clean() has been called.
def __str__(self):
return self.as_table()
def __iter__(self):
for name, field in self.fields.items():
yield BoundField(self, field, name)
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 clean(self):
if self.__errors is None:
self.full_clean()
return self.clean_data
def errors(self):
"Returns an ErrorDict for self.data"
if self.__errors is None:
self.full_clean()
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 as_table(self):
"Returns this form rendered as an HTML <table>."
output = u'\n'.join(['<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])
return '<table>\n%s\n</table>' % output
def as_ul(self):
"Returns this form rendered as an HTML <ul>."
output = u'\n'.join(['<li>%s: %s</li>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])
return '<ul>\n%s\n</ul>' % output
def as_table_with_errors(self):
"Returns this form rendered as an HTML <table>, with errors."
output = []
if self.errors().get(NON_FIELD_ERRORS):
# Errors not corresponding to a particular field are displayed at the top.
output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]]))
for name, field in self.fields.items():
bf = BoundField(self, field, name)
if bf.errors:
output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors]))
output.append('<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), bf))
return '<table>\n%s\n</table>' % '\n'.join(output)
def as_ul_with_errors(self):
"Returns this form rendered as an HTML <ul>, with errors."
output = []
if self.errors().get(NON_FIELD_ERRORS):
# Errors not corresponding to a particular field are displayed at the top.
output.append('<li><ul>%s</ul></li>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]]))
for name, field in self.fields.items():
bf = BoundField(self, field, name)
line = '<li>'
if bf.errors:
line += '<ul>%s</ul>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors])
line += '%s: %s</li>' % (pretty_name(name), bf)
output.append(line)
return '<ul>\n%s\n</ul>' % '\n'.join(output)
def full_clean(self):
"""
Cleans all of self.data and populates self.__errors and self.clean_data.
"""
self.clean_data = {}
errors = ErrorDict()
for name, field in self.fields.items():
value = self.data.get(name, None)
try:
value = field.clean(value)
self.clean_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.clean_data[name] = value
except ValidationError, e:
errors[name] = e.messages
try:
self.clean_data = self.clean()
except ValidationError, e:
errors[NON_FIELD_ERRORS] = e.messages
if errors:
self.clean_data = None
self.__errors = errors
def clean(self):
"""
Hook for doing any extra form-wide cleaning after Field.clean() been
called on every field.
"""
return self.clean_data
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)

113
django/newforms/widgets.py Normal file
View File

@ -0,0 +1,113 @@
"""
HTML Widget classes
"""
__all__ = (
'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput',
'Textarea', 'CheckboxInput',
'Select', 'SelectMultiple',
)
from django.utils.html import escape
from itertools import chain
try:
set # Only available in Python 2.4+
except NameError:
from sets import Set as set # Python 2.3 fallback
# 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):
requires_data_list = False # Determines whether render()'s 'value' argument should be a list.
def __init__(self, attrs=None):
self.attrs = attrs or {}
def render(self, name, value):
raise NotImplementedError
class Input(Widget):
"Base class for all <input> widgets (except type='checkbox', which is special)"
input_type = None # Subclasses must define this.
def render(self, name, value, attrs=None):
if value is None: value = ''
final_attrs = dict(self.attrs, type=self.input_type, 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 TextInput(Input):
input_type = 'text'
class PasswordInput(Input):
input_type = 'password'
class HiddenInput(Input):
input_type = 'hidden'
class FileInput(Input):
input_type = 'file'
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)
class Select(Widget):
def __init__(self, attrs=None, choices=()):
# choices can be any iterable
self.attrs = attrs or {}
self.choices = choices
def render(self, name, value, attrs=None, choices=()):
if value is None: value = ''
final_attrs = dict(self.attrs, name=name)
if attrs:
final_attrs.update(attrs)
output = [u'<select %s>' % flatatt(final_attrs)]
str_value = str(value) # Normalize to string.
for option_value, option_label in chain(self.choices, choices):
selected_html = (str(option_value) == str_value) and ' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label)))
output.append(u'</select>')
return u'\n'.join(output)
class SelectMultiple(Widget):
requires_data_list = True
def __init__(self, attrs=None, choices=()):
# choices can be any iterable
self.attrs = attrs or {}
self.choices = choices
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = dict(self.attrs, name=name)
if attrs:
final_attrs.update(attrs)
output = [u'<select multiple="multiple" %s>' % flatatt(final_attrs)]
str_values = set([str(v) for v in value]) # Normalize to strings.
for option_value, option_label in chain(self.choices, choices):
selected_html = (str(option_value) in str_values) and ' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label)))
output.append(u'</select>')
return u'\n'.join(output)
class RadioSelect(Widget):
pass
class CheckboxSelectMultiple(Widget):
pass

View File

@ -66,6 +66,7 @@ __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
TOKEN_TEXT = 0 TOKEN_TEXT = 0
TOKEN_VAR = 1 TOKEN_VAR = 1
TOKEN_BLOCK = 2 TOKEN_BLOCK = 2
TOKEN_COMMENT = 3
# template syntax constants # template syntax constants
FILTER_SEPARATOR = '|' FILTER_SEPARATOR = '|'
@ -75,6 +76,8 @@ BLOCK_TAG_START = '{%'
BLOCK_TAG_END = '%}' BLOCK_TAG_END = '%}'
VARIABLE_TAG_START = '{{' VARIABLE_TAG_START = '{{'
VARIABLE_TAG_END = '}}' VARIABLE_TAG_END = '}}'
COMMENT_TAG_START = '{#'
COMMENT_TAG_END = '#}'
SINGLE_BRACE_START = '{' SINGLE_BRACE_START = '{'
SINGLE_BRACE_END = '}' SINGLE_BRACE_END = '}'
@ -85,8 +88,9 @@ ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01
UNKNOWN_SOURCE="&lt;unknown source&gt;" UNKNOWN_SOURCE="&lt;unknown source&gt;"
# match a variable or block tag and capture the entire tag, including start/end delimiters # 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), 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(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 # global dictionary of libraries that have been loaded using get_library
libraries = {} libraries = {}
@ -163,12 +167,12 @@ def compile_string(template_string, origin):
class Token(object): class Token(object):
def __init__(self, token_type, contents): 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 self.token_type, self.contents = token_type, contents
def __str__(self): def __str__(self):
return '<%s token: "%s...">' % \ 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', '')) self.contents[:20].replace('\n', ''))
def split_contents(self): 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()) token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip())
elif token_string.startswith(BLOCK_TAG_START): elif token_string.startswith(BLOCK_TAG_START):
token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) 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: else:
token = Token(TOKEN_TEXT, token_string) token = Token(TOKEN_TEXT, token_string)
return token return token
@ -862,8 +868,11 @@ class Library(object):
dict = func(*args) dict = func(*args)
if not getattr(self, 'nodelist', False): if not getattr(self, 'nodelist', False):
from django.template.loader import get_template from django.template.loader import get_template, select_template
t = get_template(file_name) if hasattr(file_name, '__iter__'):
t = select_template(file_name)
else:
t = get_template(file_name)
self.nodelist = t.nodelist self.nodelist = t.nodelist
return self.nodelist.render(context_class(dict)) return self.nodelist.render(context_class(dict))
@ -877,7 +886,7 @@ def get_library(module_name):
lib = libraries.get(module_name, None) lib = libraries.get(module_name, None)
if not lib: if not lib:
try: try:
mod = __import__(module_name, '', '', ['']) mod = __import__(module_name, {}, {}, [''])
except ImportError, e: except ImportError, e:
raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e) raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e)
try: try:

View File

@ -69,7 +69,7 @@ def get_standard_processors():
i = path.rfind('.') i = path.rfind('.')
module, attr = path[:i], path[i+1:] module, attr = path[:i], path[i+1:]
try: try:
mod = __import__(module, '', '', [attr]) mod = __import__(module, {}, {}, [attr])
except ImportError, e: except ImportError, e:
raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e) raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e)
try: try:

View File

@ -421,7 +421,11 @@ def filesizeformat(bytes):
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
bytes, etc). bytes, etc).
""" """
bytes = float(bytes) try:
bytes = float(bytes)
except TypeError:
return "0 bytes"
if bytes < 1024: if bytes < 1024:
return "%d byte%s" % (bytes, bytes != 1 and 's' or '') return "%d byte%s" % (bytes, bytes != 1 and 's' or '')
if bytes < 1024 * 1024: if bytes < 1024 * 1024:

View File

@ -1,7 +1,7 @@
"Default tags used by the template system, available to all templates." "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 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.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings from django.conf import settings
import sys import sys
@ -124,17 +124,27 @@ class ForNode(Node):
return nodelist.render(context) return nodelist.render(context)
class IfChangedNode(Node): class IfChangedNode(Node):
def __init__(self, nodelist): def __init__(self, nodelist, *varlist):
self.nodelist = nodelist self.nodelist = nodelist
self._last_seen = None self._last_seen = None
self._varlist = varlist
def render(self, context): def render(self, context):
if context.has_key('forloop') and context['forloop']['first']: if context.has_key('forloop') and context['forloop']['first']:
self._last_seen = None self._last_seen = None
content = self.nodelist.render(context) try:
if content != self._last_seen: if self._varlist:
# Consider multiple parameters.
# This automatically behaves like a OR evaluation of the multiple variables.
compare_to = [resolve_variable(var, context) for var in self._varlist]
else:
compare_to = self.nodelist.render(context)
except VariableDoesNotExist:
compare_to = None
if compare_to != self._last_seen:
firstloop = (self._last_seen == None) firstloop = (self._last_seen == None)
self._last_seen = content self._last_seen = compare_to
context.push() context.push()
context['ifchanged'] = {'firstloop': firstloop} context['ifchanged'] = {'firstloop': firstloop}
content = self.nodelist.render(context) content = self.nodelist.render(context)
@ -295,6 +305,8 @@ class TemplateTagNode(Node):
'closevariable': VARIABLE_TAG_END, 'closevariable': VARIABLE_TAG_END,
'openbrace': SINGLE_BRACE_START, 'openbrace': SINGLE_BRACE_START,
'closebrace': SINGLE_BRACE_END, 'closebrace': SINGLE_BRACE_END,
'opencomment': COMMENT_TAG_START,
'closecomment': COMMENT_TAG_END,
} }
def __init__(self, tagtype): def __init__(self, tagtype):
@ -632,23 +644,34 @@ def ifchanged(parser, token):
""" """
Check if a value has changed from the last iteration of a loop. Check if a value has changed from the last iteration of a loop.
The 'ifchanged' block tag is used within a loop. It checks its own rendered The 'ifchanged' block tag is used within a loop. It has two possible uses.
contents against its previous state and only displays its content if the
value has changed::
<h1>Archive for {{ year }}</h1> 1. Checks its own rendered contents against its previous state and only
displays the content if it has changed. For example, this displays a list of
days, only displaying the month if it changes::
{% for date in days %} <h1>Archive for {{ year }}</h1>
{% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a> {% for date in days %}
{% endfor %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% endfor %}
2. If given a variable, check whether that variable has changed. For example, the
following shows the date every time it changes, but only shows the hour if both
the hour and the date have changed::
{% for date in days %}
{% ifchanged date.date %} {{ date.date }} {% endifchanged %}
{% ifchanged date.hour date.date %}
{{ date.hour }}
{% endifchanged %}
{% endfor %}
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 1:
raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
nodelist = parser.parse(('endifchanged',)) nodelist = parser.parse(('endifchanged',))
parser.delete_first_token() parser.delete_first_token()
return IfChangedNode(nodelist) return IfChangedNode(nodelist, *bits[1:])
ifchanged = register.tag(ifchanged) ifchanged = register.tag(ifchanged)
#@register.tag #@register.tag
@ -831,6 +854,8 @@ def templatetag(parser, token):
``closevariable`` ``}}`` ``closevariable`` ``}}``
``openbrace`` ``{`` ``openbrace`` ``{``
``closebrace`` ``}`` ``closebrace`` ``}``
``opencomment`` ``{#``
``closecomment`` ``#}``
================== ======= ================== =======
""" """
bits = token.contents.split() bits = token.contents.split()

View File

@ -15,9 +15,9 @@ for app in settings.INSTALLED_APPS:
m, a = app[:i], app[i+1:] m, a = app[:i], app[i+1:]
try: try:
if a is None: if a is None:
mod = __import__(m, '', '', []) mod = __import__(m, {}, {}, [])
else: else:
mod = getattr(__import__(m, '', '', [a]), a) mod = getattr(__import__(m, {}, {}, [a]), a)
except ImportError, e: except ImportError, e:
raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0]) raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0])
template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates') template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')

View File

@ -2,6 +2,6 @@ from django.conf import settings
for a in settings.INSTALLED_APPS: for a in settings.INSTALLED_APPS:
try: try:
__path__.extend(__import__(a + '.templatetags', '', '', ['']).__path__) __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
except ImportError: except ImportError:
pass pass

View File

@ -28,7 +28,7 @@ def build_suite(app_module):
# models module # models module
try: try:
app_path = app_module.__name__.split('.')[:-1] app_path = app_module.__name__.split('.')[:-1]
test_module = __import__('.'.join(app_path + [TEST_MODULE]), [], [], TEST_MODULE) test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module)) suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
try: try:

View File

@ -75,7 +75,7 @@ def technical_500_response(request, exc_type, exc_value, tb):
loader_debug_info = [] loader_debug_info = []
for loader in template_source_loaders: for loader in template_source_loaders:
try: try:
source_list_func = getattr(__import__(loader.__module__, '', '', ['get_template_sources']), 'get_template_sources') source_list_func = getattr(__import__(loader.__module__, {}, {}, ['get_template_sources']), 'get_template_sources')
# NOTE: This assumes exc_value is the name of the template that # NOTE: This assumes exc_value is the name of the template that
# the loader attempted to load. # the loader attempted to load.
template_list = [{'name': t, 'exists': os.path.exists(t)} \ template_list = [{'name': t, 'exists': os.path.exists(t)} \

View File

@ -2,12 +2,18 @@ from django.shortcuts import render_to_response
from django.template import RequestContext from django.template import RequestContext
from django.http import HttpResponse, HttpResponsePermanentRedirect, HttpResponseGone 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 Render a given template with any extra URL parameters in the context as
``{{ params }}``. ``{{ 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): 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:: ``/foo/<id>/`` to ``/bar/<id>/``, you could use the following URLconf::
urlpatterns = patterns('', 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. If the given url is ``None``, a HttpResponseGone (410) will be issued.

View File

@ -745,7 +745,7 @@ messages are made available in the `template context`_ as the template variable
{% if messages %} {% if messages %}
<ul> <ul>
{% for message in messages %} {% for message in messages %}
<li>{{ message.message }}</li> <li>{{ message }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View File

@ -610,6 +610,15 @@ fails. If no message is passed in, a default message is used.
string "123" is less than the string "2", for example. If you don't want string "123" is less than the string "2", for example. If you don't want
string comparison here, you will need to write your own validator. string comparison here, you will need to write your own validator.
``NumberIsInRange``
Takes two boundary numbers, ``lower`` and ``upper``, and checks that the
field is greater than ``lower`` (if given) and less than ``upper`` (if
given).
Both checks are inclusive. That is, ``NumberIsInRange(10, 20)`` will allow
values of both 10 and 20. This validator only checks numeric values
(e.g., float and integer values).
``IsAPowerOf`` ``IsAPowerOf``
Takes an integer argument and when called as a validator, checks that the Takes an integer argument and when called as a validator, checks that the
field being validated is a power of the integer. field being validated is a power of the integer.

View File

@ -92,6 +92,14 @@ which is a dictionary of the parameters captured in the URL.
* ``template``: The full name of a template to use. * ``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. (**This is new in the
Django development version.**)
**Example:** **Example:**
Given the following URL patterns:: Given the following URL patterns::
@ -171,7 +179,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
template. By default, it's ``django.template.loader``. template. By default, it's ``django.template.loader``.
* ``extra_context``: A dictionary of values to add to the template * ``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 dictionary is callable, the generic view will call it
just before rendering the template. just before rendering the template.

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`` Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE``
so mod_python knows which settings to use. 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 Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
on it, you'll need to tell mod_python:: on it, you'll need to tell mod_python::

View File

@ -265,6 +265,14 @@ Default: ``''`` (Empty string)
The name of the database to use. For SQLite, it's the full path to the database The name of the database to use. For SQLite, it's the full path to the database
file. file.
DATABASE_OPTIONS
----------------
Default: ``{}`` (Empty dictionary)
Extra parameters to use when connecting to the database. Consult backend
module's document for available keywords.
DATABASE_PASSWORD DATABASE_PASSWORD
----------------- -----------------
@ -528,7 +536,7 @@ any code that uses ``LANGUAGES`` at runtime.
MANAGERS MANAGERS
-------- --------
Default: ``ADMINS`` (Whatever ``ADMINS`` is set to) Default: ``()`` (Empty tuple)
A tuple in the same format as ``ADMINS`` that specifies who should get A tuple in the same format as ``ADMINS`` that specifies who should get
broken-link notifications when ``SEND_BROKEN_LINK_EMAILS=True``. broken-link notifications when ``SEND_BROKEN_LINK_EMAILS=True``.
@ -814,6 +822,16 @@ manual configuration option (see below), Django will *not* touch the ``TZ``
environment variable, and it'll be up to you to ensure your processes are environment variable, and it'll be up to you to ensure your processes are
running in the correct environment. running in the correct environment.
URL_VALIDATOR_USER_AGENT
------------------------
Default: ``Django/<version> (http://www.djangoproject.com/)``
The string to use as the ``User-Agent`` header when checking to see if URLs
exist (see the ``verify_exists`` option on URLField_).
.. URLField: ../model_api/#urlfield
USE_ETAGS USE_ETAGS
--------- ---------

View File

@ -31,7 +31,7 @@ How to do it
Just put this in your URLconf_:: Just put this in your URLconf_::
(r'^site_media/(.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}), (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
...where ``site_media`` is the URL where your media will be rooted, and ...where ``site_media`` is the URL where your media will be rooted, and
``/path/to/media`` is the filesystem root for your media. ``/path/to/media`` is the filesystem root for your media.
@ -60,7 +60,7 @@ listings for directories.
Example:: Example::
(r'^site_media/(.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}), (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}),
You can customize the index view by creating a template called You can customize the index view by creating a template called
``static/directory_index``. That template gets two objects in its context: ``static/directory_index``. That template gets two objects in its context:

View File

@ -95,7 +95,7 @@ latest five news items::
from django.contrib.syndication.feeds import Feed from django.contrib.syndication.feeds import Feed
from chicagocrime.models import NewsItem from chicagocrime.models import NewsItem
class SiteNewsFeed(Feed): class LatestEntries(Feed):
title = "Chicagocrime.org site news" title = "Chicagocrime.org site news"
link = "/sitenews/" link = "/sitenews/"
description = "Updates on changes and additions to chicagocrime.org." description = "Updates on changes and additions to chicagocrime.org."
@ -120,14 +120,14 @@ One thing's left to do. In an RSS feed, each ``<item>`` has a ``<title>``,
put into those elements. put into those elements.
* To specify the contents of ``<title>`` and ``<description>``, create * To specify the contents of ``<title>`` and ``<description>``, create
`Django templates`_ called ``feeds/sitenews_title.html`` and `Django templates`_ called ``feeds/latest_title.html`` and
``feeds/sitenews_description.html``, where ``sitenews`` is the ``slug`` ``feeds/latest_description.html``, where ``latest`` is the ``slug``
specified in the URLconf for the given feed. Note the ``.html`` extension specified in the URLconf for the given feed. Note the ``.html`` extension
is required. The RSS system renders that template for each item, passing is required. The RSS system renders that template for each item, passing
it two template context variables: it two template context variables:
* ``{{ obj }}`` -- The current object (one of whichever objects you * ``{{ obj }}`` -- The current object (one of whichever objects you
returned in ``items()``). returned in ``items()``).
* ``{{ site }}`` -- A ``django.models.core.sites.Site`` object * ``{{ site }}`` -- A ``django.models.core.sites.Site`` object
representing the current site. This is useful for representing the current site. This is useful for
``{{ site.domain }}`` or ``{{ site.name }}``. ``{{ site.domain }}`` or ``{{ site.name }}``.
@ -145,6 +145,16 @@ put into those elements.
Both ``get_absolute_url()`` and ``item_link()`` should return the item's Both ``get_absolute_url()`` and ``item_link()`` should return the item's
URL as a normal Python string. URL as a normal Python string.
* For the LatestEntries example above, we could have very simple feed templates:
* latest_title.html::
{{ obj.title }}
* latest_description.html::
{{ obj.description }}
.. _chicagocrime.org: http://www.chicagocrime.org/ .. _chicagocrime.org: http://www.chicagocrime.org/
.. _object-relational mapper: http://www.djangoproject.com/documentation/db_api/ .. _object-relational mapper: http://www.djangoproject.com/documentation/db_api/
.. _Django templates: http://www.djangoproject.com/documentation/templates/ .. _Django templates: http://www.djangoproject.com/documentation/templates/

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 below describes all the built-in tags. You can create your own tags, if you
know how to write Python code. 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 Template inheritance
==================== ====================
@ -458,7 +473,7 @@ block are output::
In the above, if ``athlete_list`` is not empty, the number of athletes will be In the above, if ``athlete_list`` is not empty, the number of athletes will be
displayed by the ``{{ athlete_list|length }}`` variable. displayed by the ``{{ athlete_list|length }}`` variable.
As you can see, the ``if`` tag can take an option ``{% else %}`` clause that As you can see, the ``if`` tag can take an optional ``{% else %}`` clause that
will be displayed if the test fails. will be displayed if the test fails.
``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or ``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or
@ -510,16 +525,29 @@ ifchanged
Check if a value has changed from the last iteration of a loop. Check if a value has changed from the last iteration of a loop.
The ``ifchanged`` block tag is used within a loop. It checks its own rendered The 'ifchanged' block tag is used within a loop. It has two possible uses.
contents against its previous state and only displays its content if the value
has changed::
<h1>Archive for {{ year }}</h1> 1. Checks its own rendered contents against its previous state and only
displays the content if it has changed. For example, this displays a list of
days, only displaying the month if it changes::
{% for day in days %} <h1>Archive for {{ year }}</h1>
{% ifchanged %}<h3>{{ day|date:"F" }}</h3>{% endifchanged %}
<a href="{{ day|date:"M/d"|lower }}/">{{ day|date:"j" }}</a> {% for date in days %}
{% endfor %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% endfor %}
2. **New in Django development version.** If given a variable, check whether that
variable has changed. For example, the following shows the date every time it
changes, but only shows the hour if both the hour and the date has changed::
{% for date in days %}
{% ifchanged date.date %} {{ date.date }} {% endifchanged %}
{% ifchanged date.hour date.date %}
{{ date.hour }}
{% endifchanged %}
{% endfor %}
ifequal ifequal
~~~~~~~ ~~~~~~~
@ -785,8 +813,12 @@ The argument tells which template bit to output:
``closevariable`` ``}}`` ``closevariable`` ``}}``
``openbrace`` ``{`` ``openbrace`` ``{``
``closebrace`` ``}`` ``closebrace`` ``}``
``opencomment`` ``{#``
``closecomment`` ``#}``
================== ======= ================== =======
Note: ``opencomment`` and ``closecomment`` are new in the Django development version.
widthratio widthratio
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -312,18 +312,18 @@ optional, third positional argument, ``processors``. In this example, the
}, [ip_address_processor]) }, [ip_address_processor])
Note:: Note::
If you are using Django's ``render_to_response()`` shortcut to populate a 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 template with the contents of a dictionary, your template will be passed a
``Context`` instance by default (not a ``RequestContext``). If you wish to ``Context`` instance by default (not a ``RequestContext``). To use a
use a ``RequestContext`` in your template rendering, you need to pass an ``RequestContext`` in your template rendering, pass an optional third
optional third argument to ``render_to_response()``: a ``RequestContext`` argument to ``render_to_response()``: a ``RequestContext``
instance. Your code might look like this:: instance. Your code might look like this::
def some_view(request): def some_view(request):
# ... # ...
return render_to_response('my_template'html', return render_to_response('my_template'html',
my_data_dictionary, my_data_dictionary,
context_instance = RequestContext(request)) context_instance=RequestContext(request))
Here's what each of the default processors does: Here's what each of the default processors does:
@ -1092,7 +1092,7 @@ Configuring the template system in standalone mode
.. note:: .. note::
This section is only of interest to people trying to use the template 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 template system as part of a Django application, nothing here applies to
you. you.
@ -1109,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 pieces of the templating system and then, *before* you call any of the
templating functions, call ``django.conf.settings.configure()`` with any templating functions, call ``django.conf.settings.configure()`` with any
settings you wish to specify. You might want to consider setting at least 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 ``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
``TEMPLATE_DEBUG``. All available settings are described in the ``TEMPLATE_DEBUG``. All available settings are described in the
`settings documentation`_, and any setting starting with *TEMPLATE_* `settings documentation`_, and any setting starting with *TEMPLATE_*

View File

@ -383,10 +383,10 @@ Django where our templates live::
Now copy the template ``admin/base_site.html`` from within the default Django Now copy the template ``admin/base_site.html`` from within the default Django
admin template directory (``django/contrib/admin/templates``) into an ``admin`` admin template directory (``django/contrib/admin/templates``) into an ``admin``
subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For
example, if your ``TEMPLATE_DIRS`` includes ``"/home/mytemplates"``, as above, example, if your ``TEMPLATE_DIRS`` includes ``"/home/my_username/mytemplates"``,
then copy ``django/contrib/admin/templates/admin/base_site.html`` to as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to
``/home/mytemplates/admin/base_site.html``. Don't forget that ``admin`` ``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that
subdirectory. ``admin`` subdirectory.
Then, just edit the file and replace the generic Django text with your own Then, just edit the file and replace the generic Django text with your own
site's name and URL as you see fit. site's name and URL as you see fit.

View File

@ -192,13 +192,13 @@ objects" and "display a detail page for a particular type of object."
``object_id`` for the generic views. ``object_id`` for the generic views.
By default, the ``object_detail`` generic view uses a template called 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"``. Thus, rename your ``polls/detail.html`` template to
``polls/poll_detail.html``, and change the ``render_to_response()`` line in ``polls/poll_detail.html``, and change the ``render_to_response()`` line in
``vote()``. ``vote()``.
Similarly, the ``object_list`` generic view uses a template called 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``. ``polls/poll_list.html``.
Because we have more than one entry in the URLconf that uses ``object_detail`` Because we have more than one entry in the URLconf that uses ``object_detail``

View File

@ -64,4 +64,17 @@ True
>>> paginator.last_on_page(1) >>> paginator.last_on_page(1)
9 9
# Add a few more records to test out the orphans feature.
>>> for x in range(10, 13):
... Article(headline="Article %s" % x, pub_date=datetime(2006, 10, 6)).save()
# With orphans set to 3 and 10 items per page, we should get all 12 items on a single page:
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=3)
>>> paginator.pages
1
# With orphans only set to 1, we should get two pages:
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1)
>>> paginator.pages
2
"""} """}

View File

View File

File diff suppressed because it is too large Load Diff

View File

@ -173,6 +173,22 @@ class Templates(unittest.TestCase):
# Empty strings can be passed as arguments to filters # Empty strings can be passed as arguments to filters
'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'), '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 TAG ###########################################################
'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"), 'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"), 'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),
@ -312,6 +328,21 @@ class Templates(unittest.TestCase):
'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'), 'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'),
'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'), 'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'),
'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'), 'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'),
# Test one parameter given to ifchanged.
'ifchanged-param01': ('{% for n in num %}{% ifchanged n %}..{% endifchanged %}{{ n }}{% endfor %}', { 'num': (1,2,3) }, '..1..2..3'),
'ifchanged-param02': ('{% for n in num %}{% for x in numx %}{% ifchanged n %}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}', { 'num': (1,2,3), 'numx': (5,6,7) }, '..567..567..567'),
# Test multiple parameters to ifchanged.
'ifchanged-param03': ('{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1,1,2), 'numx': (5,6,6) }, '156156256'),
# Test a date+hour like construct, where the hour of the last day
# is the same but the date had changed, so print the hour anyway.
'ifchanged-param04': ('{% for d in days %}{% ifchanged %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),
# Logically the same as above, just written with explicit
# ifchanged for the day.
'ifchanged-param04': ('{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),
### IFEQUAL TAG ########################################################### ### IFEQUAL TAG ###########################################################
'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
@ -473,7 +504,7 @@ class Templates(unittest.TestCase):
'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'), 'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
### HANDLING OF TEMPLATE_TAG_IF_INVALID ################################### ### HANDLING OF TEMPLATE_TAG_IF_INVALID ###################################
'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')), 'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')), 'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')),
'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''), 'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''),
@ -536,6 +567,8 @@ class Templates(unittest.TestCase):
'templatetag08': ('{% templatetag closebrace %}', {}, '}'), 'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'), 'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'), 'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
'templatetag11': ('{% templatetag opencomment %}', {}, '{#'),
'templatetag12': ('{% templatetag closecomment %}', {}, '#}'),
### WIDTHRATIO TAG ######################################################## ### WIDTHRATIO TAG ########################################################
'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'), 'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
@ -606,20 +639,20 @@ class Templates(unittest.TestCase):
# Turn TEMPLATE_DEBUG off, because tests assume that. # Turn TEMPLATE_DEBUG off, because tests assume that.
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False 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 old_invalid = settings.TEMPLATE_STRING_IF_INVALID
for name, vals in tests: for name, vals in tests:
install() install()
if isinstance(vals[2], tuple): if isinstance(vals[2], tuple):
normal_string_result = vals[2][0] normal_string_result = vals[2][0]
invalid_string_result = vals[2][1] invalid_string_result = vals[2][1]
else: else:
normal_string_result = vals[2] normal_string_result = vals[2]
invalid_string_result = vals[2] invalid_string_result = vals[2]
if 'LANGUAGE_CODE' in vals[1]: if 'LANGUAGE_CODE' in vals[1]:
activate(vals[1]['LANGUAGE_CODE']) activate(vals[1]['LANGUAGE_CODE'])
else: else:
@ -636,10 +669,10 @@ class Templates(unittest.TestCase):
continue continue
if output != result: if output != result:
failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output)) 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]: if 'LANGUAGE_CODE' in vals[1]:
deactivate() deactivate()
loader.template_source_loaders = old_template_loaders loader.template_source_loaders = old_template_loaders
deactivate() deactivate()
settings.TEMPLATE_DEBUG = old_td settings.TEMPLATE_DEBUG = old_td