1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

[per-object-permissions] Merged to revision 3582

git-svn-id: http://code.djangoproject.com/svn/django/branches/per-object-permissions@3583 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Christopher Long 2006-08-14 18:52:03 +00:00
parent 4f0118995c
commit 4cfd3203a6
65 changed files with 1354 additions and 856 deletions

21
AUTHORS
View File

@ -16,12 +16,23 @@ before Simon departed and currently oversees things with Adrian.
Wilson Miner <http://www.wilsonminer.com/>, who designed Django's admin Wilson Miner <http://www.wilsonminer.com/>, who designed Django's admin
interface, pretty error pages, official Web site (djangoproject.com) and has interface, pretty error pages, official Web site (djangoproject.com) and has
made many other contributions. made many other contributions. He makes us look good.
Malcolm Tredinnick <http://www.pointy-stick.com/blog/>, who has made
significant contributions to all levels of the framework, from its database
layer to template system and documentation.
Georg "Hugo" Bauer <http://hugo.muensterland.org/>, who added Georg "Hugo" Bauer <http://hugo.muensterland.org/>, who added
internationalization support, manages i18n contributions and has made a ton internationalization support, manages i18n contributions and has made a ton
of excellent tweaks, feature additions and bug fixes. of excellent tweaks, feature additions and bug fixes.
Luke Plant <http://lukeplant.me.uk/>, who has contributed many excellent
improvements, including database-level improvements, the CSRF middleware and
unit tests.
Russell Keith-Magee <freakboy@iinet.net.au>, who has contributed many excellent
improvements, including refactoring of the Django ORM code and unit tests.
Robert Wittams <http://robert.wittams.com/>, who majorly refactored the Django Robert Wittams <http://robert.wittams.com/>, who majorly refactored the Django
admin application to allow for easier reuse and has made a ton of excellent admin application to allow for easier reuse and has made a ton of excellent
tweaks, feature additions and bug fixes. tweaks, feature additions and bug fixes.
@ -49,6 +60,7 @@ answer newbie questions, and generally made Django that much better:
Amit Chakradeo <http://amit.chakradeo.net/> Amit Chakradeo <http://amit.chakradeo.net/>
ChaosKCW ChaosKCW
Ian Clelland <clelland@gmail.com> Ian Clelland <clelland@gmail.com>
crankycoder@gmail.com
Matt Croydon <http://www.postneo.com/> Matt Croydon <http://www.postneo.com/>
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/> Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
Jason Davies (Esaj) <http://www.jasondavies.com/> Jason Davies (Esaj) <http://www.jasondavies.com/>
@ -59,6 +71,8 @@ answer newbie questions, and generally made Django that much better:
Clint Ecker Clint Ecker
gandalf@owca.info gandalf@owca.info
Baishampayan Ghose Baishampayan Ghose
martin.glueck@gmail.com
Simon Greenhill <dev@simon.net.nz>
Espen Grindhaug <http://grindhaug.org/> Espen Grindhaug <http://grindhaug.org/>
Brant Harris Brant Harris
hipertracker@gmail.com hipertracker@gmail.com
@ -70,7 +84,6 @@ answer newbie questions, and generally made Django that much better:
Michael Josephson <http://www.sdjournal.com/> Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com jpellerin@gmail.com
junzhang.jn@gmail.com junzhang.jn@gmail.com
Russell Keith-Magee <freakboy@iinet.net.au>
Garth Kidd <http://www.deadlybloodyserious.com/> Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr> kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/> Sune Kirkeby <http://ibofobi.dk/>
@ -98,6 +111,7 @@ answer newbie questions, and generally made Django that much better:
Sam Newman <http://www.magpiebrain.com/> Sam Newman <http://www.magpiebrain.com/>
Neal Norwitz <nnorwitz@google.com> Neal Norwitz <nnorwitz@google.com>
oggie rob <oz.robharvey@gmail.com> oggie rob <oz.robharvey@gmail.com>
Jay Parlar <parlar@gmail.com>
pgross@thoughtworks.com pgross@thoughtworks.com
phaedo <http://phaedo.cx/> phaedo <http://phaedo.cx/>
phil@produxion.net phil@produxion.net
@ -112,13 +126,14 @@ answer newbie questions, and generally made Django that much better:
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
David Schein David Schein
sopel sopel
Thomas Steinacher <tom@eggdrop.ch>
Radek Švarz <http://www.svarz.cz/translate/> Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info> Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/> Aaron Swartz <http://www.aaronsw.com/>
Tom Tobin Tom Tobin
Tom Insam Tom Insam
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/> Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
Malcolm Tredinnick Karen Tracey <graybark@bellsouth.net>
Amit Upadhyay Amit Upadhyay
Geert Vanderkelen Geert Vanderkelen
Milton Waddams Milton Waddams

19
INSTALL
View File

@ -1,7 +1,22 @@
Thanks for downloading Django. Thanks for downloading Django.
To install it, make sure you have Python 2.3 or greater installed. Then run this command: To install it, make sure you have Python 2.3 or greater installed. Then run
this command from the command prompt:
python setup.py install python setup.py install
Note this requires a working Internet connection if you don't already have the
Python utility "setuptools" installed.
AS AN ALTERNATIVE, you can just copy the entire "django" directory to Python's
site-packages directory, which is located wherever your Python installation
lives. Some places you might check are:
/usr/lib/python2.4/site-packages (Unix, Python 2.4)
/usr/lib/python2.3/site-packages (Unix, Python 2.3)
C:\\PYTHON\site-packages (Windows)
This second solution does not require a working Internet connection; it
bypasses "setuptools" entirely.
For more detailed instructions, see docs/install.txt. For more detailed instructions, see docs/install.txt.

View File

@ -1 +1 @@
VERSION = (0, 95, 'post-magic-removal') VERSION = (0, 96, 'pre')

View File

@ -14,7 +14,7 @@ def compile_messages():
print "this script should be run from the django svn tree or your project or app tree" print "this script should be run from the django svn tree or your project or app tree"
sys.exit(1) sys.exit(1)
for (dirpath, dirnames, filenames) in os.walk(basedir): for dirpath, dirnames, filenames in os.walk(basedir):
for f in filenames: for f in filenames:
if f.endswith('.po'): if f.endswith('.po'):
sys.stderr.write('processing file %s in %s\n' % (f, dirpath)) sys.stderr.write('processing file %s in %s\n' % (f, dirpath))

View File

@ -252,6 +252,7 @@ MIDDLEWARE_CLASSES = (
SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want. SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks). SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie. SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request. SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser. SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.

View File

@ -5,17 +5,21 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django\n" "Project-Id-Version: django 0.95\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: 2005-11-26 00:00\n" "PO-Revision-Date: 2006-08-14 18:08+0300\n"
"Last-Translator: Dmitry Sorokin <ds@dial.com.ru>\n" "Last-Translator: Grigory Fateyev <greg@dial.com.ru>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: Dialcom Services <greg@dial.com.ru>\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"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Russian\n"
"X-Poedit-Country: RUSSIAN FEDERATION\n"
"X-Poedit-SourceCharset: utf-8\n"
#: contrib/comments/models.py:67 contrib/comments/models.py:166 #: contrib/comments/models.py:67
#: contrib/comments/models.py:166
msgid "object ID" msgid "object ID"
msgstr "ID объекта" msgstr "ID объекта"
@ -23,7 +27,8 @@ msgstr "ID объекта"
msgid "headline" msgid "headline"
msgstr "заголовок" msgstr "заголовок"
#: contrib/comments/models.py:69 contrib/comments/models.py:90 #: contrib/comments/models.py:69
#: contrib/comments/models.py:90
#: contrib/comments/models.py:167 #: contrib/comments/models.py:167
msgid "comment" msgid "comment"
msgstr "комментарий" msgstr "комментарий"
@ -64,15 +69,18 @@ msgstr "рейтинг #8"
msgid "is valid rating" msgid "is valid rating"
msgstr "доступный рейтинг" msgstr "доступный рейтинг"
#: contrib/comments/models.py:83 contrib/comments/models.py:169 #: contrib/comments/models.py:83
#: contrib/comments/models.py:169
msgid "date/time submitted" msgid "date/time submitted"
msgstr "дата/время добавления" msgstr "дата/время добавления"
#: contrib/comments/models.py:84 contrib/comments/models.py:170 #: contrib/comments/models.py:84
#: contrib/comments/models.py:170
msgid "is public" msgid "is public"
msgstr "публичный" msgstr "публичный"
#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 #: contrib/comments/models.py:85
#: contrib/admin/views/doc.py:289
msgid "IP address" msgid "IP address"
msgstr "IP адрес" msgstr "IP адрес"
@ -81,19 +89,15 @@ msgid "is removed"
msgstr "удален" msgstr "удален"
#: contrib/comments/models.py:86 #: contrib/comments/models.py:86
msgid "" msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead."
"Check this box if the comment is inappropriate. A \"This comment has been " msgstr "Отметте, если комментарий нежелателен. Сообщение \"Этот комментарий был удалён\" будет показано взамен."
"removed\" message will be displayed instead."
msgstr ""
"Отметте, если комментарий нежелателен. Сообщение \"Этот комментарий был "
"удалён\" будет показано взамен."
#: contrib/comments/models.py:91 #: contrib/comments/models.py:91
#, fuzzy
msgid "comments" msgid "comments"
msgstr "комментарий" msgstr "комментарии"
#: 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"
msgstr "Объект наполнения" msgstr "Объект наполнения"
@ -151,7 +155,7 @@ msgstr "Карма счета"
#: contrib/comments/models.py:242 #: contrib/comments/models.py:242
#, python-format #, python-format
msgid "%(score)d rating by %(user)s" msgid "%(score)d rating by %(user)s"
msgstr "" msgstr "%(score)d рейтинг %(user)s"
#: contrib/comments/models.py:258 #: contrib/comments/models.py:258
#, python-format #, python-format
@ -196,7 +200,7 @@ msgstr "Удаления модератором"
#: 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 "" msgstr "Удаления модератора %r"
#: contrib/comments/views/karma.py:19 #: contrib/comments/views/karma.py:19
msgid "Anonymous users cannot vote" msgid "Anonymous users cannot vote"
@ -211,20 +215,17 @@ msgid "No voting for yourself"
msgstr "Нельзя голосовать за себя" msgstr "Нельзя голосовать за себя"
#: contrib/comments/views/comments.py:28 #: contrib/comments/views/comments.py:28
msgid "" msgid "This rating is required because you've entered at least one other rating."
"This rating is required because you've entered at least one other rating." msgstr "Этот рейтинг необходим, так как вы входили хоть однажды в другие рейтинги."
msgstr ""
#: contrib/comments/views/comments.py:112 #: contrib/comments/views/comments.py:112
#, python-format #, python-format
msgid "" msgid ""
"This comment was posted by a user who has posted fewer than %(count)s " "This comment was posted by a user who has posted fewer than %(count)s comment:\n"
"comment:\n"
"\n" "\n"
"%(text)s" "%(text)s"
msgid_plural "" msgid_plural ""
"This comment was posted by a user who has posted fewer than %(count)s " "This comment was posted by a user who has posted fewer than %(count)s comments:\n"
"comments:\n"
"\n" "\n"
"%(text)s" "%(text)s"
msgstr[0] "" msgstr[0] ""
@ -258,11 +259,8 @@ msgstr "Кто-то вмешивается в форму комментария
#: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:207
#: contrib/comments/views/comments.py:292 #: contrib/comments/views/comments.py:292
msgid "" msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid"
"The comment form had an invalid 'target' parameter -- the object ID was " msgstr "Форма комментария имеет неверный 'target' параметр -- ID объекта неверно"
"invalid"
msgstr ""
"Форма комментария имеет неверный 'target' параметр -- ID объекта неверно"
#: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:257
#: contrib/comments/views/comments.py:321 #: contrib/comments/views/comments.py:321
@ -343,8 +341,11 @@ msgid ""
"<h3>By %s:</h3>\n" "<h3>By %s:</h3>\n"
"<ul>\n" "<ul>\n"
msgstr "" msgstr ""
"<h3>К %s:</h3>\n"
"<ul>\n"
#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 #: contrib/admin/filterspecs.py:70
#: contrib/admin/filterspecs.py:88
#: contrib/admin/filterspecs.py:143 #: contrib/admin/filterspecs.py:143
msgid "All" msgid "All"
msgstr "Все" msgstr "Все"
@ -413,14 +414,11 @@ msgstr "журнальные записи"
msgid "All dates" msgid "All dates"
msgstr "Все даты" msgstr "Все даты"
#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 #: contrib/admin/views/decorators.py:9
#: contrib/auth/forms.py:36
#: contrib/auth/forms.py:41 #: contrib/auth/forms.py:41
msgid "" msgid "Please enter a correct username and password. Note that both fields are case-sensitive."
"Please enter a correct username and password. Note that both fields are case-" msgstr "Пожалуйста, вводите верные данные именя пользователя и пароль. Помните, оба поля чувствительны к регистру."
"sensitive."
msgstr ""
"Пожалуйста, вводите верные данные именя пользователя и пароль. Помните, оба "
"поля чувствительны к регистру."
#: 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
@ -428,20 +426,12 @@ msgid "Log in"
msgstr "Вход" msgstr "Вход"
#: contrib/admin/views/decorators.py:61 #: contrib/admin/views/decorators.py:61
msgid "" msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved."
"Please log in again, because your session has expired. Don't worry: Your " msgstr "Пожалуйста войдите снова, посколькук ваша сессия устарела. Не беспокойтесь:введенные вами данные сохранены."
"submission has been saved."
msgstr ""
"Пожалуйста войдите снова, посколькук ваша сессия устарела. Не беспокойтесь:"
"введенные вами данные сохранены."
#: contrib/admin/views/decorators.py:68 #: contrib/admin/views/decorators.py:68
msgid "" msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
"Looks like your browser isn't configured to accept cookies. Please enable " msgstr "Похоже, что ваш броузер не настроен на прием cookies. Пожалуйства включите cookie, перезагрузите страницу и попытайтесь снова. "
"cookies, reload this page, and try again."
msgstr ""
"Похоже, что ваш броузер не настроен на прием cookies. Пожалуйства включите "
"cookie, перезагрузите страницу и попытайтесь снова. "
#: contrib/admin/views/decorators.py:82 #: contrib/admin/views/decorators.py:82
msgid "Usernames cannot contain the '@' character." msgid "Usernames cannot contain the '@' character."
@ -450,7 +440,7 @@ msgstr "Имя пользователя не может включать сим
#: contrib/admin/views/decorators.py:84 #: contrib/admin/views/decorators.py:84
#, python-format #, python-format
msgid "Your e-mail address is not your username. Try '%s' instead." msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr "" msgstr "Ваш e-mail адрес не ваше имя. Попробуйте '%s' в замен."
#: contrib/admin/views/main.py:226 #: contrib/admin/views/main.py:226
msgid "Site administration" msgid "Site administration"
@ -461,11 +451,13 @@ msgstr "Администрирование сайта"
msgid "The %(name)s \"%(obj)s\" was added successfully." msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" были успешно добавлены." msgstr "%(name)s \"%(obj)s\" были успешно добавлены."
#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 #: contrib/admin/views/main.py:264
#: contrib/admin/views/main.py:348
msgid "You may edit it again below." msgid "You may edit it again below."
msgstr "Вы снова можете редактировать их внизу" msgstr "Вы снова можете редактировать их внизу"
#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 #: contrib/admin/views/main.py:272
#: contrib/admin/views/main.py:357
#, python-format #, python-format
msgid "You may add another %s below." msgid "You may add another %s below."
msgstr "Вы можете добавить %s внизу." msgstr "Вы можете добавить %s внизу."
@ -480,7 +472,8 @@ msgstr "Добавить %s"
msgid "Added %s." msgid "Added %s."
msgstr "Добавлено %s" msgstr "Добавлено %s"
#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:336
#: contrib/admin/views/main.py:338
#: contrib/admin/views/main.py:340 #: contrib/admin/views/main.py:340
msgid "and" msgid "and"
msgstr "и" msgstr "и"
@ -497,18 +490,17 @@ msgstr "Удалено %s."
#: contrib/admin/views/main.py:343 #: contrib/admin/views/main.py:343
msgid "No fields changed." msgid "No fields changed."
msgstr "" msgstr "Ни одно поле не изменено."
#: contrib/admin/views/main.py:346 #: contrib/admin/views/main.py:346
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully." msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "" msgstr "%(name)s \"%(obj)s\" было успешно изменено"
#: contrib/admin/views/main.py:354 #: contrib/admin/views/main.py:354
#, python-format #, python-format
msgid "" msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "%(name)s \"%(obj)s\" было успешно изменено. Вы можете редактировать его снова."
msgstr ""
#: contrib/admin/views/main.py:392 #: contrib/admin/views/main.py:392
#, python-format #, python-format
@ -549,9 +541,12 @@ msgstr "Выберите %s"
msgid "Select %s to change" msgid "Select %s to change"
msgstr "Выберите %s для изменения" msgstr "Выберите %s для изменения"
#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 #: contrib/admin/views/doc.py:277
#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 #: contrib/admin/views/doc.py:286
#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 #: contrib/admin/views/doc.py:288
#: contrib/admin/views/doc.py:294
#: contrib/admin/views/doc.py:295
#: contrib/admin/views/doc.py:297
msgid "Integer" msgid "Integer"
msgstr "Целое" msgstr "Целое"
@ -559,7 +554,8 @@ msgstr "Целое"
msgid "Boolean (Either True or False)" msgid "Boolean (Either True or False)"
msgstr "Логическое (True или False)" msgstr "Логическое (True или False)"
#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 #: contrib/admin/views/doc.py:279
#: contrib/admin/views/doc.py:296
#, python-format #, python-format
msgid "String (up to %(maxlength)s)" msgid "String (up to %(maxlength)s)"
msgstr "Строка (до %(maxlength)s символов)" msgstr "Строка (до %(maxlength)s символов)"
@ -580,7 +576,8 @@ msgstr "Дата (с указанием времени)"
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mail адрес" msgstr "E-mail адрес"
#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 #: contrib/admin/views/doc.py:284
#: contrib/admin/views/doc.py:287
msgid "File path" msgid "File path"
msgstr "Путь к файлу" msgstr "Путь к файлу"
@ -594,7 +591,7 @@ msgstr "Логическое (True, False или None)"
#: contrib/admin/views/doc.py:292 #: contrib/admin/views/doc.py:292
msgid "Relation to parent model" msgid "Relation to parent model"
msgstr "" msgstr "Зависимость на родительскую модель."
#: contrib/admin/views/doc.py:293 #: contrib/admin/views/doc.py:293
msgid "Phone number" msgid "Phone number"
@ -608,7 +605,8 @@ msgstr "Текст"
msgid "Time" msgid "Time"
msgstr "Время" msgstr "Время"
#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 #: contrib/admin/views/doc.py:300
#: contrib/flatpages/models.py:7
msgid "URL" msgid "URL"
msgstr "URL" msgstr "URL"
@ -688,12 +686,8 @@ msgid "DATE_WITH_TIME_FULL"
msgstr "j. N Y, H:i" msgstr "j. N Y, H:i"
#: contrib/admin/templates/admin/object_history.html:36 #: contrib/admin/templates/admin/object_history.html:36
msgid "" msgid "This object doesn't have a change history. It probably wasn't added via this admin site."
"This object doesn't have a change history. It probably wasn't added via this " msgstr "Данный обьект не имеет истории изменения. Возможно он не был добавлен через данный административный сайт."
"admin site."
msgstr ""
"Данный обьект не имеет истории изменения. Возможно он не был добавлен через "
"данный административный сайт."
#: contrib/admin/templates/admin/base_site.html:4 #: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin" msgid "Django site admin"
@ -716,12 +710,8 @@ msgid "Server Error <em>(500)</em>"
msgstr "Ошибка сервера <em>(500)</em>" msgstr "Ошибка сервера <em>(500)</em>"
#: contrib/admin/templates/admin/500.html:10 #: contrib/admin/templates/admin/500.html:10
msgid "" msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience."
"There's been an error. It's been reported to the site administrators via e-" msgstr "Произошла ошибка. Отчет об ошибке отправлен администраторам сайта по e-mailи она должна быть вскоре исправлена. Благодарим вас на терпение и помощь."
"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
"Произошла ошибка. Отчет об ошибке отправлен администраторам сайта по e-mailи "
"она должна быть вскоре исправлена. Благодарим вас на терпение и помощь."
#: 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
@ -782,23 +772,13 @@ msgstr "Удалить"
#: contrib/admin/templates/admin/delete_confirmation.html:14 #: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format #, python-format
msgid "" msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:"
"Deleting the %(object_name)s '%(object)s' would result in deleting related " msgstr "Удаление объекта %(object_name)s '%(object)s' приведет к удалению зависимых элементов, но предоставленных вам прав недостаточно для удаления следующих типов объектов:"
"objects, but your account doesn't have permission to delete the following "
"types of objects:"
msgstr ""
"Удаление объекта %(object_name)s '%(object)s' приведет к удалению зависимых "
"элементов, но предоставленных вам прав недостаточно для удаления следующих "
"типов объектов:"
#: contrib/admin/templates/admin/delete_confirmation.html:21 #: contrib/admin/templates/admin/delete_confirmation.html:21
#, python-format #, python-format
msgid "" msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:"
"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " msgstr "Вы уверены, что хотите удалить %(object_name)s \"%(object)s\"? Все следующие объекты также будут удалены:"
"the following related items will be deleted:"
msgstr ""
"Вы уверены, что хотите удалить %(object_name)s \"%(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"
@ -807,7 +787,7 @@ msgstr "Да, я уверен"
#: contrib/admin/templates/admin/filter.html:2 #: contrib/admin/templates/admin/filter.html:2
#, python-format #, python-format
msgid " By %(title)s " msgid " By %(title)s "
msgstr "" msgstr "К%(title)s "
#: contrib/admin/templates/admin/search_form.html:8 #: contrib/admin/templates/admin/search_form.html:8
msgid "Go" msgid "Go"
@ -871,12 +851,8 @@ msgid "Password reset"
msgstr "Сброс пароля" msgstr "Сброс пароля"
#: contrib/admin/templates/registration/password_reset_form.html:12 #: contrib/admin/templates/registration/password_reset_form.html:12
msgid "" msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you."
"Forgotten your password? Enter your e-mail address below, and we'll reset " msgstr "Забыли пароль? Введите ваш e-mail адрес ниже и мы очистим ваш старый пароль, и вышлем вам по e-mail новый."
"your password and e-mail the new one to you."
msgstr ""
"Забыли пароль? Введите ваш e-mail адрес ниже и мы очистим ваш старый пароль, "
"и вышлем вам по e-mail новый."
#: contrib/admin/templates/registration/password_reset_form.html:16 #: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:" msgid "E-mail address:"
@ -900,20 +876,12 @@ msgid "Password reset successful"
msgstr "Успешная очистка пароля" msgstr "Успешная очистка пароля"
#: contrib/admin/templates/registration/password_reset_done.html:12 #: contrib/admin/templates/registration/password_reset_done.html:12
msgid "" msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly."
"We've e-mailed a new password to the e-mail address you submitted. You " msgstr "Мы отправили новый пароль по указанному вами адресу электронной почты. Вы должны его вскоре получить."
"should be receiving it shortly."
msgstr ""
"Мы отправили новый пароль по указанному вами адресу электронной почты. Вы "
"должны его вскоре получить."
#: contrib/admin/templates/registration/password_change_form.html:12 #: contrib/admin/templates/registration/password_change_form.html:12
msgid "" msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly."
"Please enter your old password, for security's sake, and then enter your new " msgstr "В целях безопасности, пожалуйста, введите ваш старый пароль, затем - новый пароль дважды, с тем, чтобы мы могли убедиться в правильности написания."
"password twice so we can verify you typed it in correctly."
msgstr ""
"В целях безопасности, пожалуйста, введите ваш старый пароль, затем - новый "
"пароль дважды, с тем, чтобы мы могли убедиться в правильности написания."
#: contrib/admin/templates/registration/password_change_form.html:17 #: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:" msgid "Old password:"
@ -986,24 +954,16 @@ msgid "Documentation for this page"
msgstr "Документация по данной странице" msgstr "Документация по данной странице"
#: contrib/admin/templates/admin_doc/bookmarklets.html:20 #: contrib/admin/templates/admin_doc/bookmarklets.html:20
msgid "" msgid "Jumps you from any page to the documentation for the view that generates that page."
"Jumps you from any page to the documentation for the view that generates " msgstr "Перенаправит вас с любой страницы к просмотру документа, который генерирует эту страницу."
"that page."
msgstr ""
"Перенаправит вас с любой страницы к просмотру документа, который генерирует "
"эту страницу."
#: contrib/admin/templates/admin_doc/bookmarklets.html:22 #: contrib/admin/templates/admin_doc/bookmarklets.html:22
msgid "Show object ID" msgid "Show object ID"
msgstr "Показать ID обьекта" msgstr "Показать ID обьекта"
#: contrib/admin/templates/admin_doc/bookmarklets.html:23 #: contrib/admin/templates/admin_doc/bookmarklets.html:23
msgid "" msgid "Shows the content-type and unique ID for pages that represent a single object."
"Shows the content-type and unique ID for pages that represent a single " msgstr "Показывает тип наполнения и уникальный ID для страниц, которые означают одинокий объект."
"object."
msgstr ""
"Показывает тип наполнения и уникальный ID для страниц, которые означают "
"одинокий объект."
#: 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)"
@ -1042,24 +1002,16 @@ msgid "redirect from"
msgstr "перенаправить из" msgstr "перенаправить из"
#: contrib/redirects/models.py:8 #: contrib/redirects/models.py:8
msgid "" msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'."
"This should be an absolute path, excluding the domain name. Example: '/" msgstr "Это должен быть абсолютный путь, исключая доменное имя. Пример: '/events/search/'."
"events/search/'."
msgstr ""
"Это должен быть абсолютный путь, исключая доменное имя. Пример: '/events/"
"search/'."
#: contrib/redirects/models.py:9 #: contrib/redirects/models.py:9
msgid "redirect to" msgid "redirect to"
msgstr "перенаправить на" msgstr "перенаправить на"
#: contrib/redirects/models.py:10 #: contrib/redirects/models.py:10
msgid "" msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'."
"This can be either an absolute path (as above) or a full URL starting with " msgstr "Это должен быть, либо абсолютный путь (как выше) или полный URL начинающийся с 'http://'."
"'http://'."
msgstr ""
"Это должен быть, либо абсолютный путь (как выше) или полный URL начинающийся "
"с 'http://'."
#: contrib/redirects/models.py:12 #: contrib/redirects/models.py:12
msgid "redirect" msgid "redirect"
@ -1070,10 +1022,8 @@ msgid "redirects"
msgstr "перенаправления" msgstr "перенаправления"
#: contrib/flatpages/models.py:8 #: contrib/flatpages/models.py:8
msgid "" msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
"Example: '/about/contact/'. Make sure to have leading and trailing slashes." msgstr "Пример: '/about/contact/'. Будьте уверенны, что вставили завепршающий слэш."
msgstr ""
"Пример: '/about/contact/'. Будьте уверенны, что вставили завепршающий слэш."
#: contrib/flatpages/models.py:9 #: contrib/flatpages/models.py:9
msgid "title" msgid "title"
@ -1092,10 +1042,8 @@ msgid "template name"
msgstr "имя шаблона" msgstr "имя шаблона"
#: contrib/flatpages/models.py:13 #: contrib/flatpages/models.py:13
msgid "" msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'."
"Example: 'flatpages/contact_page'. If this isn't provided, the system will " msgstr "Пример: 'flatpages/contact_page'. Если этот файл не присутствует, система будет использовать 'flatpages/default'."
"use 'flatpages/default'."
msgstr ""
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "registration required" msgid "registration required"
@ -1113,7 +1061,8 @@ msgstr "простая страница"
msgid "flat pages" msgid "flat pages"
msgstr "простые страницы" msgstr "простые страницы"
#: contrib/auth/models.py:13 contrib/auth/models.py:26 #: contrib/auth/models.py:13
#: contrib/auth/models.py:26
msgid "name" msgid "name"
msgstr "имя" msgstr "имя"
@ -1125,7 +1074,8 @@ msgstr "код"
msgid "permission" msgid "permission"
msgstr "Права" msgstr "Права"
#: contrib/auth/models.py:18 contrib/auth/models.py:27 #: contrib/auth/models.py:18
#: contrib/auth/models.py:27
msgid "permissions" msgid "permissions"
msgstr "Права" msgstr "Права"
@ -1133,7 +1083,8 @@ msgstr "Права"
msgid "group" msgid "group"
msgstr "Группа" msgstr "Группа"
#: contrib/auth/models.py:30 contrib/auth/models.py:65 #: contrib/auth/models.py:30
#: contrib/auth/models.py:65
msgid "groups" msgid "groups"
msgstr "Группы" msgstr "Группы"
@ -1159,7 +1110,7 @@ msgstr "пароль"
#: contrib/auth/models.py:59 #: contrib/auth/models.py:59
msgid "Use '[algo]$[salt]$[hexdigest]'" msgid "Use '[algo]$[salt]$[hexdigest]'"
msgstr "" msgstr "Используйте '[algo]$[salt]$[hexdigest]'"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "staff status" msgid "staff status"
@ -1186,12 +1137,8 @@ msgid "date joined"
msgstr "дата регистрации" msgstr "дата регистрации"
#: contrib/auth/models.py:66 #: contrib/auth/models.py:66
msgid "" msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."
"In addition to the permissions manually assigned, this user will also get " msgstr "К добавлению к перавам выбрнанным вуручную, этот пользователь может получить все права группы, к которой он принадлежит."
"all permissions granted to each group he/she is in."
msgstr ""
"К добавлению к перавам выбрнанным вуручную, этот пользователь может получить "
"все права группы, к которой он принадлежит."
#: contrib/auth/models.py:67 #: contrib/auth/models.py:67
msgid "user permissions" msgid "user permissions"
@ -1226,10 +1173,8 @@ msgid "message"
msgstr "Сообщение" msgstr "Сообщение"
#: contrib/auth/forms.py:30 #: contrib/auth/forms.py:30
msgid "" msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in."
"Your Web browser doesn't appear to have cookies enabled. Cookies are " msgstr "У вашего браузера не включены cookies. Cookies необходимы для входа."
"required for logging in."
msgstr ""
#: contrib/contenttypes/models.py:25 #: contrib/contenttypes/models.py:25
msgid "python model class name" msgid "python model class name"
@ -1327,23 +1272,28 @@ msgstr "Январь"
msgid "February" msgid "February"
msgstr "Февраль" msgstr "Февраль"
#: utils/dates.py:14 utils/dates.py:27 #: utils/dates.py:14
#: utils/dates.py:27
msgid "March" msgid "March"
msgstr "Март" msgstr "Март"
#: utils/dates.py:14 utils/dates.py:27 #: utils/dates.py:14
#: utils/dates.py:27
msgid "April" msgid "April"
msgstr "Апрель" msgstr "Апрель"
#: utils/dates.py:14 utils/dates.py:27 #: utils/dates.py:14
#: utils/dates.py:27
msgid "May" msgid "May"
msgstr "Май" msgstr "Май"
#: utils/dates.py:14 utils/dates.py:27 #: utils/dates.py:14
#: utils/dates.py:27
msgid "June" msgid "June"
msgstr "Июнь" msgstr "Июнь"
#: utils/dates.py:15 utils/dates.py:27 #: utils/dates.py:15
#: utils/dates.py:27
msgid "July" msgid "July"
msgstr "Июль" msgstr "Июль"
@ -1592,11 +1542,8 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "Значение может содержать только буквы, цифры и подчеркивания." msgstr "Значение может содержать только буквы, цифры и подчеркивания."
#: core/validators.py:64 #: core/validators.py:64
msgid "" msgid "This value must contain only letters, numbers, underscores, dashes or slashes."
"This value must contain only letters, numbers, underscores, dashes or " msgstr "Значение может содержать только буквы, цифры, подчеркивания, дифисы или тере."
"slashes."
msgstr "Значение может содержать только буквы, цифры, подчеркивания, дифисы или "
"тере."
#: core/validators.py:72 #: core/validators.py:72
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."
@ -1646,7 +1593,8 @@ msgstr "Вводите реальную дату в формате YYYY-MM-DD."
msgid "Enter a valid time in HH:MM format." msgid "Enter a valid time in HH:MM format."
msgstr "Вводите реальное время в формате HH:MM." msgstr "Вводите реальное время в формате HH:MM."
#: core/validators.py:132 db/models/fields/__init__.py:468 #: core/validators.py:132
#: db/models/fields/__init__.py:468
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Вводите реальные дата/время в формате YYYY-MM-DD HH:MM." msgstr "Вводите реальные дата/время в формате YYYY-MM-DD HH:MM."
@ -1655,12 +1603,8 @@ msgid "Enter a valid e-mail address."
msgstr "Укажите реальный e-mail адрес." msgstr "Укажите реальный e-mail адрес."
#: core/validators.py:148 #: core/validators.py:148
msgid "" msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
"Upload a valid image. The file you uploaded was either not an image or a " msgstr "Загрузите реальное изображение. Файл, который вы загружали, не был изображением или был поврежден."
"corrupted image."
msgstr ""
"Загрузите реальное изображение. Файл, который вы загружали, не был "
"изображением или был поврежден."
#: core/validators.py:155 #: core/validators.py:155
#, python-format #, python-format
@ -1700,7 +1644,8 @@ msgstr "Неверный формат XML: %s"
msgid "Invalid URL: %s" msgid "Invalid URL: %s"
msgstr "Неверный URL: %s" msgstr "Неверный URL: %s"
#: core/validators.py:206 core/validators.py:208 #: core/validators.py:206
#: core/validators.py:208
#, python-format #, python-format
msgid "The URL %s is a broken link." msgid "The URL %s is a broken link."
msgstr "URL %s сломанная ссылка." msgstr "URL %s сломанная ссылка."
@ -1725,7 +1670,8 @@ msgstr "Это поле должно совпадать с полем '%s'."
msgid "Please enter something for at least one field." msgid "Please enter something for at least one field."
msgstr "Пожалуйста, заполните хотя бы одно поле." msgstr "Пожалуйста, заполните хотя бы одно поле."
#: core/validators.py:264 core/validators.py:275 #: core/validators.py:264
#: core/validators.py:275
msgid "Please enter both fields or leave them both empty." msgid "Please enter both fields or leave them both empty."
msgstr "Пожалуйста, заполните оба поля либо оставьте их пустыми." msgstr "Пожалуйста, заполните оба поля либо оставьте их пустыми."
@ -1755,26 +1701,16 @@ msgstr "Пожалуйста, вводите корректное десятич
#: core/validators.py:349 #: core/validators.py:349
#, python-format #, python-format
msgid "Please enter a valid decimal number with at most %s total digit." msgid "Please enter a valid decimal number with at most %s total digit."
msgid_plural "" msgid_plural "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."
msgstr[0] "" msgstr[1] "Пожалуйста, вводите корректное десятичное число с максимальным количеством знаков %s."
"Пожалуйста, вводите корректное десятичное число с максимальным количеством "
"знаков %s."
msgstr[1] ""
"Пожалуйста, вводите корректное десятичное число с максимальным количеством "
"знаков %s."
#: core/validators.py:352 #: core/validators.py:352
#, 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."
msgstr[0] "" msgstr[1] "Пожалуйста, вводите корректное десятичное число с максимальным количеством знаков после запятой %s."
"Пожалуйста, вводите корректное десятичное число с максимальным количеством "
"знаков после запятой %s."
msgstr[1] ""
"Пожалуйста, вводите корректное десятичное число с максимальным количеством "
"знаков после запятой %s."
#: core/validators.py:362 #: core/validators.py:362
#, python-format #, python-format
@ -1801,50 +1737,37 @@ msgstr "Невозможно получить что-либо с %s."
#: core/validators.py:429 #: core/validators.py:429
#, python-format #, python-format
msgid "" msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "URL %(url)s вернул неверный заголовок Content-Type '%(contenttype)s'."
msgstr "URL %(url) вернул неверный заголовок Content-Type '%(contenttype)'."
#: core/validators.py:462 #: core/validators.py:462
#, python-format #, python-format
msgid "" msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)"
"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with "
"\"%(start)s\".)"
msgstr "" msgstr ""
#: core/validators.py:466 #: core/validators.py:466
#, python-format #, python-format
msgid "" msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)"
"Some text starting on line %(line)s is not allowed in that context. (Line "
"starts with \"%(start)s\".)"
msgstr "" msgstr ""
#: core/validators.py:471 #: core/validators.py:471
#, python-format #, python-format
msgid "" msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)"
"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%"
"(start)s\".)"
msgstr "" msgstr ""
#: core/validators.py:476 #: core/validators.py:476
#, python-format #, python-format
msgid "" msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)"
"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%"
"(start)s\".)"
msgstr "" msgstr ""
#: core/validators.py:480 #: core/validators.py:480
#, python-format #, python-format
msgid "" msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)"
"A tag on line %(line)s is missing one or more required attributes. (Line "
"starts with \"%(start)s\".)"
msgstr "" msgstr ""
#: core/validators.py:485 #: core/validators.py:485
#, python-format #, python-format
msgid "" msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)"
"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line "
"starts with \"%(start)s\".)"
msgstr "" msgstr ""
#: db/models/manipulators.py:302 #: db/models/manipulators.py:302
@ -1857,8 +1780,10 @@ msgstr ""
msgid "%(optname)s with this %(fieldname)s already exists." msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "" msgstr ""
#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 #: db/models/fields/__init__.py:114
#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 #: db/models/fields/__init__.py:265
#: db/models/fields/__init__.py:542
#: db/models/fields/__init__.py:553
#: forms/__init__.py:346 #: forms/__init__.py:346
msgid "This field is required." msgid "This field is required."
msgstr "Обязательное поле." msgstr "Обязательное поле."
@ -1868,14 +1793,12 @@ msgid "This value must be an integer."
msgstr "" msgstr ""
#: db/models/fields/__init__.py:369 #: db/models/fields/__init__.py:369
#, 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:385 #: db/models/fields/__init__.py:385
#, fuzzy
msgid "This field cannot be null." msgid "This field cannot be null."
msgstr "Это поле неверно." msgstr "Это поле не может быть нулевым."
#: db/models/fields/__init__.py:562 #: db/models/fields/__init__.py:562
msgid "Enter a valid filename." msgid "Enter a valid filename."
@ -1887,23 +1810,17 @@ msgid "Please enter a valid %s."
msgstr "" msgstr ""
#: db/models/fields/related.py:579 #: db/models/fields/related.py:579
#, fuzzy
msgid "Separate multiple IDs with commas." msgid "Separate multiple IDs with commas."
msgstr "Несколько значений ID разделяйте запятыми." msgstr "Несколько значений ID разделяйте запятыми."
#: db/models/fields/related.py:581 #: db/models/fields/related.py:581
#, fuzzy msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgid "" msgstr " Удерживайте \"Control\", или \"Command\" на Макинтош, для выбора больше чем одного."
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
" Удерживайте \"Control\", или \"Command\" на Макинтош, для выбора больше чем "
"одного."
#: db/models/fields/related.py:625 #: db/models/fields/related.py:625
#, python-format #, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural "" msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
"Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
@ -1918,7 +1835,9 @@ msgstr[1] ""
msgid "Line breaks are not allowed here." msgid "Line breaks are not allowed here."
msgstr "Переносы строк не допускаются здесь." msgstr "Переносы строк не допускаются здесь."
#: 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
msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "" msgstr ""
@ -1943,30 +1862,3 @@ msgstr "Введите целое число в диапазоне от 0 до 3
msgid "yes,no,maybe" msgid "yes,no,maybe"
msgstr "да,нет,может быть" msgstr "да,нет,может быть"
#~ msgid "Comment"
#~ msgstr "Комментарий"
#~ msgid "Comments"
#~ msgstr "Комментарии"
#~ msgid "label"
#~ msgstr "метка"
#~ msgid "package"
#~ msgstr "пакет"
#~ msgid "packages"
#~ msgstr "пакеты"
#~ msgid "String (up to 50)"
#~ msgstr "Строка (до 50 символов)"
#~ msgid ""
#~ "Example: 'flatfiles/contact_page'. If this isn't provided, the system "
#~ "will use 'flatfiles/default'."
#~ msgstr ""
#~ "Пример: 'flatfiles/contact_page'. Если не предусмотрена, система будет "
#~ "использовать 'flatfiles/default'."
#~ msgid "Server error <em>(500)</em>"
#~ msgstr "Ошибка сервера <em>(500)</em>"

File diff suppressed because it is too large Load Diff

View File

@ -60,8 +60,9 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = '{{ project_name }}.urls' ROOT_URLCONF = '{{ project_name }}.urls'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
) )
INSTALLED_APPS = ( INSTALLED_APPS = (

View File

@ -10,8 +10,10 @@ include = lambda urlconf_module: [urlconf_module]
def patterns(prefix, *tuples): def patterns(prefix, *tuples):
pattern_list = [] pattern_list = []
for t in tuples: for t in tuples:
if type(t[1]) == list: regex, view_or_include = t[:2]
pattern_list.append(RegexURLResolver(t[0], t[1][0])) default_kwargs = t[2:]
if type(view_or_include) == list:
pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs))
else: else:
pattern_list.append(RegexURLPattern(t[0], prefix and (prefix + '.' + t[1]) or t[1], *t[2:])) pattern_list.append(RegexURLPattern(regex, prefix and (prefix + '.' + view_or_include) or view_or_include, *default_kwargs))
return pattern_list return pattern_list

View File

@ -8,7 +8,9 @@ var DateTimeShortcuts = {
clockInputs: [], clockInputs: [],
calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled
calendarDivName2: 'calendarin', // name of <div> that contains calendar calendarDivName2: 'calendarin', // name of <div> that contains calendar
calendarLinkName: 'calendarlink',// name of the link that is used to toggle
clockDivName: 'clockbox', // name of clock <div> that gets toggled clockDivName: 'clockbox', // name of clock <div> that gets toggled
clockLinkName: 'clocklink', // name of the link that is used to toggle
admin_media_prefix: '', admin_media_prefix: '',
init: function() { init: function() {
// Deduce admin_media_prefix by looking at the <script>s in the // Deduce admin_media_prefix by looking at the <script>s in the
@ -46,6 +48,7 @@ var DateTimeShortcuts = {
now_link.appendChild(document.createTextNode(gettext('Now'))); now_link.appendChild(document.createTextNode(gettext('Now')));
var clock_link = document.createElement('a'); var clock_link = document.createElement('a');
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
clock_link.id = DateTimeShortcuts.clockLinkName + num;
quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock')); quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock'));
shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(now_link); shortcuts_span.appendChild(now_link);
@ -69,17 +72,6 @@ var DateTimeShortcuts = {
var clock_box = document.createElement('div'); var clock_box = document.createElement('div');
clock_box.style.display = 'none'; clock_box.style.display = 'none';
clock_box.style.position = 'absolute'; clock_box.style.position = 'absolute';
if (getStyle(document.body,'direction')!='rtl') {
clock_box.style.left = findPosX(clock_link) + 17 + 'px';
}
else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
// TODO: IE returns wrong value for findPosX when in rtl mode
// (it returns as it was left aligned), needs to be fixed.
clock_box.style.left = findPosX(clock_link) - 110 + 'px';
}
clock_box.style.top = findPosY(clock_link) - 30 + 'px';
clock_box.className = 'clockbox module'; clock_box.className = 'clockbox module';
clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num); clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
document.body.appendChild(clock_box); document.body.appendChild(clock_box);
@ -98,7 +90,25 @@ var DateTimeShortcuts = {
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');'); quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');');
}, },
openClock: function(num) { openClock: function(num) {
document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'block'; var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num)
var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num)
// Recalculate the clockbox position
// is it left-to-right or right-to-left layout ?
if (getStyle(document.body,'direction')!='rtl') {
clock_box.style.left = findPosX(clock_link) + 17 + 'px';
}
else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
// TODO: IE returns wrong value for findPosX when in rtl mode
// (it returns as it was left aligned), needs to be fixed.
clock_box.style.left = findPosX(clock_link) - 110 + 'px';
}
clock_box.style.top = findPosY(clock_link) - 30 + 'px';
// Show the clock box
clock_box.style.display = 'block';
addEvent(window, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; }); addEvent(window, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; });
}, },
dismissClock: function(num) { dismissClock: function(num) {
@ -123,6 +133,7 @@ var DateTimeShortcuts = {
today_link.appendChild(document.createTextNode(gettext('Today'))); today_link.appendChild(document.createTextNode(gettext('Today')));
var cal_link = document.createElement('a'); var cal_link = document.createElement('a');
cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');');
cal_link.id = DateTimeShortcuts.calendarLinkName + num;
quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar')); quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar'));
shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(today_link); shortcuts_span.appendChild(today_link);
@ -149,18 +160,6 @@ var DateTimeShortcuts = {
var cal_box = document.createElement('div'); var cal_box = document.createElement('div');
cal_box.style.display = 'none'; cal_box.style.display = 'none';
cal_box.style.position = 'absolute'; cal_box.style.position = 'absolute';
// is it left-to-right or right-to-left layout ?
if (getStyle(document.body,'direction')!='rtl') {
cal_box.style.left = findPosX(cal_link) + 17 + 'px';
}
else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
// TODO: IE returns wrong value for findPosX when in rtl mode
// (it returns as it was left aligned), needs to be fixed.
cal_box.style.left = findPosX(cal_link) - 180 + 'px';
}
cal_box.style.top = findPosY(cal_link) - 75 + 'px';
cal_box.className = 'calendarbox module'; cal_box.className = 'calendarbox module';
cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num); cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
document.body.appendChild(cal_box); document.body.appendChild(cal_box);
@ -195,7 +194,24 @@ var DateTimeShortcuts = {
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');'); quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');');
}, },
openCalendar: function(num) { openCalendar: function(num) {
document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'block'; var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
// Recalculate the clockbox position
// is it left-to-right or right-to-left layout ?
if (getStyle(document.body,'direction')!='rtl') {
cal_box.style.left = findPosX(cal_link) + 17 + 'px';
}
else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
// TODO: IE returns wrong value for findPosX when in rtl mode
// (it returns as it was left aligned), needs to be fixed.
cal_box.style.left = findPosX(cal_link) - 180 + 'px';
}
cal_box.style.top = findPosY(cal_link) - 75 + 'px';
cal_box.style.display = 'block';
addEvent(window, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; }); addEvent(window, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; });
}, },
dismissCalendar: function(num) { dismissCalendar: function(num) {

View File

@ -11,7 +11,7 @@ function showRelatedObjectLookupPopup(triggeringLink) {
} else { } else {
href = triggeringLink.href + '?pop=1'; href = triggeringLink.href + '?pop=1';
} }
var win = window.open(href, name, 'height=500,width=740,resizable=yes,scrollbars=yes'); var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus(); win.focus();
return false; return false;
} }

View File

@ -0,0 +1,28 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block after_field_sets %}
<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p>
<fieldset class="module aligned">
<div class="form-row">
{{ form.username.html_error_list }}
<label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }}
<p class="help">{{ username_help_text }}</p>
</div>
<div class="form-row">
{{ form.password1.html_error_list }}
<label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
</div>
<div class="form-row">
{{ form.password2.html_error_list }}
<label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
<p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
</div>
</fieldset>
{% endblock %}

View File

@ -21,7 +21,7 @@
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%} {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
</ul> </ul>
{% endif %}{% endif %} {% endif %}{% endif %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post">{% block form_top %}{% endblock %} <form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
<div> <div>
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %} {% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
{% if opts.admin.save_on_top %}{% submit_row %}{% endif %} {% if opts.admin.save_on_top %}{% submit_row %}{% endif %}

View File

@ -7,6 +7,7 @@
<th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th> <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</tr></thead>
{% for fcw in bound_related_object.form_field_collection_wrappers %} {% for fcw in bound_related_object.form_field_collection_wrappers %}
{% if change %}{% if original_row_needed %} {% if change %}{% if original_row_needed %}
{% if fcw.obj.original %} {% if fcw.obj.original %}

View File

@ -0,0 +1,39 @@
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms, template
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
def user_add_stage(request):
manipulator = UserCreationForm()
if request.method == 'POST':
new_data = request.POST.copy()
errors = manipulator.get_validation_errors(new_data)
if not errors:
new_user = manipulator.save(new_data)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user}
if request.POST.has_key("_addanother"):
request.user.message_set.create(message=msg)
return HttpResponseRedirect(request.path)
else:
request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
return HttpResponseRedirect('../%s/' % new_user.id)
else:
errors = new_data = {}
form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('admin/auth/user/add_form.html', {
'title': _('Add user'),
'form': form,
'is_popup': request.REQUEST.has_key('_popup'),
'add': True,
'change': False,
'has_delete_permission': False,
'has_change_permission': True,
'has_file_field': False,
'has_absolute_url': False,
'auto_populated_fields': (),
'bound_field_sets': (),
'first_form_field_id': 'id_username',
'opts': User._meta,
'username_help_text': User._meta.get_field('username').help_text,
}, context_instance=template.RequestContext(request))

View File

@ -43,11 +43,11 @@ def template_tag_index(request):
for tag_name, tag_func in library.tags.items(): for tag_name, tag_func in library.tags.items():
title, body, metadata = utils.parse_docstring(tag_func.__doc__) title, body, metadata = utils.parse_docstring(tag_func.__doc__)
if title: if title:
title = utils.parse_rst(title, 'tag', 'tag:' + tag_name) title = utils.parse_rst(title, 'tag', _('tag:') + tag_name)
if body: if body:
body = utils.parse_rst(body, 'tag', 'tag:' + tag_name) body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
for key in metadata: for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'tag', 'tag:' + tag_name) metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
if library in template.builtins: if library in template.builtins:
tag_library = None tag_library = None
else: else:
@ -74,11 +74,11 @@ def template_filter_index(request):
for filter_name, filter_func in library.filters.items(): for filter_name, filter_func in library.filters.items():
title, body, metadata = utils.parse_docstring(filter_func.__doc__) title, body, metadata = utils.parse_docstring(filter_func.__doc__)
if title: if title:
title = utils.parse_rst(title, 'filter', 'filter:' + filter_name) title = utils.parse_rst(title, 'filter', _('filter:') + filter_name)
if body: if body:
body = utils.parse_rst(body, 'filter', 'filter:' + filter_name) body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
for key in metadata: for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'filter', 'filter:' + filter_name) metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
if library in template.builtins: if library in template.builtins:
tag_library = None tag_library = None
else: else:
@ -132,11 +132,11 @@ def view_detail(request, view):
raise Http404 raise Http404
title, body, metadata = utils.parse_docstring(view_func.__doc__) title, body, metadata = utils.parse_docstring(view_func.__doc__)
if title: if title:
title = utils.parse_rst(title, 'view', 'view:' + view) title = utils.parse_rst(title, 'view', _('view:') + view)
if body: if body:
body = utils.parse_rst(body, 'view', 'view:' + view) body = utils.parse_rst(body, 'view', _('view:') + view)
for key in metadata: for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'model', 'view:' + view) metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view)
return render_to_response('admin_doc/view_detail.html', { return render_to_response('admin_doc/view_detail.html', {
'name': view, 'name': view,
'summary': title, 'summary': title,
@ -161,14 +161,14 @@ def model_detail(request, app_label, model_name):
try: try:
app_mod = models.get_app(app_label) app_mod = models.get_app(app_label)
except ImproperlyConfigured: except ImproperlyConfigured:
raise Http404, "App %r not found" % app_label raise Http404, _("App %r not found") % app_label
model = None model = None
for m in models.get_models(app_mod): for m in models.get_models(app_mod):
if m._meta.object_name.lower() == model_name: if m._meta.object_name.lower() == model_name:
model = m model = m
break break
if model is None: if model is None:
raise Http404, "Model %r not found in app %r" % (model_name, app_label) raise Http404, _("Model %r not found in app %r") % (model_name, app_label)
opts = model._meta opts = model._meta
@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name):
if isinstance(field, models.ForeignKey): if isinstance(field, models.ForeignKey):
data_type = related_object_name = field.rel.to.__name__ data_type = related_object_name = field.rel.to.__name__
app_label = field.rel.to._meta.app_label app_label = field.rel.to._meta.app_label
verbose = utils.parse_rst(("the related `%s.%s` object" % (app_label, data_type)), 'model', 'model:' + data_type) verbose = utils.parse_rst((_("the related `%s.%s` object") % (app_label, data_type)), 'model', _('model:') + data_type)
else: else:
data_type = get_readable_field_data_type(field) data_type = get_readable_field_data_type(field)
verbose = field.verbose_name verbose = field.verbose_name
@ -202,7 +202,7 @@ def model_detail(request, app_label, model_name):
continue continue
verbose = func.__doc__ verbose = func.__doc__
if verbose: if verbose:
verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', 'model:' + opts.module_name) verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.module_name)
fields.append({ fields.append({
'name': func_name, 'name': func_name,
'data_type': get_return_data_type(func_name), 'data_type': get_return_data_type(func_name),
@ -211,17 +211,17 @@ def model_detail(request, app_label, model_name):
# Gather related objects # Gather related objects
for rel in opts.get_all_related_objects(): for rel in opts.get_all_related_objects():
verbose = "related `%s.%s` objects" % (rel.opts.app_label, rel.opts.object_name) verbose = _("related `%s.%s` objects") % (rel.opts.app_label, rel.opts.object_name)
accessor = rel.get_accessor_name() accessor = rel.get_accessor_name()
fields.append({ fields.append({
'name' : "%s.all" % accessor, 'name' : "%s.all" % accessor,
'data_type' : 'List', 'data_type' : 'List',
'verbose' : utils.parse_rst("all " + verbose , 'model', 'model:' + opts.module_name), 'verbose' : utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
}) })
fields.append({ fields.append({
'name' : "%s.count" % accessor, 'name' : "%s.count" % accessor,
'data_type' : 'Integer', 'data_type' : 'Integer',
'verbose' : utils.parse_rst("number of " + verbose , 'model', 'model:' + opts.module_name), 'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
}) })
return render_to_response('admin_doc/model_detail.html', { return render_to_response('admin_doc/model_detail.html', {
@ -336,7 +336,7 @@ def extract_views_from_urlpatterns(urlpatterns, base=''):
elif hasattr(p, '_get_url_patterns'): elif hasattr(p, '_get_url_patterns'):
views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern)) views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern))
else: else:
raise TypeError, "%s does not appear to be a urlpattern object" % p raise TypeError, _("%s does not appear to be a urlpattern object") % p
return views return views
named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)') named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)')

View File

@ -263,7 +263,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
post_url_continue += "?_popup=1" post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value) return HttpResponseRedirect(post_url_continue % pk_value)
if request.POST.has_key("_popup"): if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \ return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %r, "%s");</script>' % \
(pk_value, str(new_object).replace('"', '\\"'))) (pk_value, str(new_object).replace('"', '\\"')))
elif request.POST.has_key("_addanother"): elif request.POST.has_key("_addanother"):
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name)) request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))

View File

@ -15,7 +15,6 @@ def user_passes_test(test_func, login_url=LOGIN_URL):
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
_checklogin.__doc__ = view_func.__doc__ _checklogin.__doc__ = view_func.__doc__
_checklogin.__dict__ = view_func.__dict__ _checklogin.__dict__ = view_func.__dict__
_checklogin.__name__ = view_func.__name__
return _checklogin return _checklogin
return _dec return _dec

View File

@ -5,6 +5,28 @@ from django.template import Context, loader
from django.core import validators from django.core import validators
from django import forms from django import forms
class UserCreationForm(forms.Manipulator):
"A form that creates a user, with no privileges, from the given username and password."
def __init__(self):
self.fields = (
forms.TextField(field_name='username', length=30, maxlength=30, is_required=True,
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
validator_list=[validators.AlwaysMatchesOtherField('password1', "The two password fields didn't match.")]),
)
def isValidUsername(self, field_data, all_data):
try:
User.objects.get(username=field_data)
except User.DoesNotExist:
return
raise validators.ValidationError, 'A user with that username already exists.'
def save(self, new_data):
"Creates the user."
return User.objects.create_user(new_data['username'], '', new_data['password1'])
class AuthenticationForm(forms.Manipulator): class AuthenticationForm(forms.Manipulator):
""" """
Base class for authenticating users. Extend this to get a form that accepts Base class for authenticating users. Extend this to get a form that accepts

View File

@ -2,7 +2,7 @@ This is an optional add-on app, flatpages.
For full documentation, see either of these: For full documentation, see either of these:
* The file django/docs/flatpages.txt in the Django distribution * The file docs/flatpages.txt in the Django distribution
* http://www.djangoproject.com/documentation/flatpages/ on the Web * http://www.djangoproject.com/documentation/flatpages/ on the Web
Both have identical content. Both have identical content.

View File

@ -88,5 +88,6 @@ class SessionMiddleware(object):
new_session = Session.objects.save(session_key, request.session._session, new_session = Session.objects.save(session_key, request.session._session,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)) datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key, response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN) max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
secure=settings.SESSION_COOKIE_SECURE or None)
return response return response

View File

@ -94,12 +94,15 @@ def get_sql_create(app):
"Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n")) "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
sys.exit(1) sys.exit(1)
# Get installed models, so we generate REFERENCES right # Get installed models, so we generate REFERENCES right.
# We trim models from the current app so that the sqlreset command does not
# generate invalid SQL (leaving models out of known_models is harmless, so
# we can be conservative).
app_models = models.get_models(app)
final_output = [] final_output = []
known_models = set(_get_installed_models(_get_table_list())) known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
pending_references = {} pending_references = {}
app_models = models.get_models(app)
for model in app_models: for model in app_models:
output, references = _get_sql_model_create(model, known_models) output, references = _get_sql_model_create(model, known_models)
@ -118,10 +121,13 @@ def get_sql_create(app):
# but don't exist physically # but don't exist physically
not_installed_models = set(pending_references.keys()) not_installed_models = set(pending_references.keys())
if not_installed_models: if not_installed_models:
final_output.append('-- The following references should be added but depend on non-existant tables:') alter_sql = []
for model in not_installed_models: for model in not_installed_models:
final_output.extend(['-- ' + sql for sql in alter_sql.extend(['-- ' + sql for sql in
_get_sql_for_pending_references(model, pending_references)]) _get_sql_for_pending_references(model, pending_references)])
if alter_sql:
final_output.append('-- The following references should be added but depend on non-existent tables:')
final_output.extend(alter_sql)
return final_output return final_output
get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)." get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
@ -192,7 +198,6 @@ def _get_sql_for_pending_references(model, pending_references):
data_types = get_creation_module().DATA_TYPES data_types = get_creation_module().DATA_TYPES
final_output = [] final_output = []
reference_names = {}
if backend.supports_constraints: if backend.supports_constraints:
opts = model._meta opts = model._meta
if model in pending_references: if model in pending_references:
@ -202,12 +207,9 @@ def _get_sql_for_pending_references(model, pending_references):
r_col = f.column r_col = f.column
table = opts.db_table table = opts.db_table
col = opts.get_field(f.rel.field_name).column col = opts.get_field(f.rel.field_name).column
r_name = '%s_referencing_%s_%s' % (r_col, table, col) # For MySQL, r_name must be unique in the first 64 characters.
if r_name in reference_names: # So we are careful with character usage here.
reference_names[r_name] += 1 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
r_name += '_%s' % reference_names[r_name]
else:
reference_names[r_name] = 0
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \
(backend.quote_name(r_table), r_name, (backend.quote_name(r_table), r_name,
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col)))
@ -299,7 +301,7 @@ def get_sql_delete(app):
(style.SQL_KEYWORD('ALTER TABLE'), (style.SQL_KEYWORD('ALTER TABLE'),
style.SQL_TABLE(backend.quote_name(table)), style.SQL_TABLE(backend.quote_name(table)),
style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()), style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
style.SQL_FIELD(backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col))))) style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))
del references_to_delete[model] del references_to_delete[model]
# Output DROP TABLE statements for many-to-many tables. # Output DROP TABLE statements for many-to-many tables.
@ -696,9 +698,7 @@ def inspectdb():
introspection_module = get_introspection_module() introspection_module = get_introspection_module()
def table2model(table_name): table2model = lambda table_name: table_name.title().replace('_', '')
object_name = table_name.title().replace('_', '')
return object_name.endswith('s') and object_name[:-1] or object_name
cursor = connection.cursor() cursor = connection.cursor()
yield "# This is an auto-generated Django model module." yield "# This is an auto-generated Django model module."
@ -727,6 +727,10 @@ def inspectdb():
comment_notes = [] # Holds Field notes, to be displayed in a Python comment. comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = {} # Holds Field parameters such as 'db_column'. extra_params = {} # Holds Field parameters such as 'db_column'.
if ' ' in att_name:
extra_params['db_column'] = att_name
att_name = att_name.replace(' ', '')
comment_notes.append('Field renamed to remove spaces.')
if keyword.iskeyword(att_name): if keyword.iskeyword(att_name):
extra_params['db_column'] = att_name extra_params['db_column'] = att_name
att_name += '_field' att_name += '_field'
@ -957,6 +961,12 @@ def get_validation_errors(outfile, app=None):
f = opts.get_field(fn) f = opts.get_field(fn)
except models.FieldDoesNotExist: except models.FieldDoesNotExist:
e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
# date_hierarchy
if opts.admin.date_hierarchy:
try:
f = opts.get_field(opts.admin.date_hierarchy)
except models.FieldDoesNotExist:
e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
# Check ordering attribute. # Check ordering attribute.
if opts.ordering: if opts.ordering:
@ -1132,7 +1142,14 @@ def dbshell():
dbshell.args = "" dbshell.args = ""
def runfcgi(args): def runfcgi(args):
"""Run this project as a FastCGI application. requires flup.""" "Runs this project as a FastCGI application. Requires flup."
from django.conf import settings
from django.utils import translation
# Activate the current language, because it won't get activated later.
try:
translation.activate(settings.LANGUAGE_CODE)
except AttributeError:
pass
from django.core.servers.fastcgi import runfastcgi from django.core.servers.fastcgi import runfastcgi
runfastcgi(args) runfastcgi(args)
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
@ -1289,7 +1306,11 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
if action not in NO_SQL_TRANSACTION: if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("COMMIT;") print style.SQL_KEYWORD("COMMIT;")
def execute_manager(settings_mod, argv=None): def setup_environ(settings_mod):
"""
Configure the runtime environment. This can also be used by external
scripts wanting to set up a similar environment to manage.py.
"""
# Add this project to sys.path so that it's importable in the conventional # Add this project to sys.path so that it's importable in the conventional
# way. For example, if this file (manage.py) lives in a directory # way. For example, if this file (manage.py) lives in a directory
# "myproject", this code would add "/path/to/myproject" to sys.path. # "myproject", this code would add "/path/to/myproject" to sys.path.
@ -1301,7 +1322,10 @@ def execute_manager(settings_mod, argv=None):
# Set DJANGO_SETTINGS_MODULE appropriately. # Set DJANGO_SETTINGS_MODULE appropriately.
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
return project_directory
def execute_manager(settings_mod, argv=None):
project_directory = setup_environ(settings_mod)
action_mapping = DEFAULT_ACTION_MAPPING.copy() action_mapping = DEFAULT_ACTION_MAPPING.copy()
# Remove the "startproject" command from the action_mapping, because that's # Remove the "startproject" command from the action_mapping, because that's

View File

@ -41,11 +41,11 @@ class DateTimeAwareJSONEncoder(simplejson.JSONEncoder):
TIME_FORMAT = "%H:%M:%S" TIME_FORMAT = "%H:%M:%S"
def default(self, o): def default(self, o):
if isinstance(o, datetime.date): if isinstance(o, datetime.datetime):
return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
elif isinstance(o, datetime.date):
return o.strftime(self.DATE_FORMAT) return o.strftime(self.DATE_FORMAT)
elif isinstance(o, datetime.time): elif isinstance(o, datetime.time):
return o.strftime(self.TIME_FORMAT) return o.strftime(self.TIME_FORMAT)
elif isinstance(o, datetime.datetime):
return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
else: else:
return super(self, DateTimeAwareJSONEncoder).default(o) return super(self, DateTimeAwareJSONEncoder).default(o)

View File

@ -547,10 +547,6 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
env['PATH_INFO'] = urllib.unquote(path) env['PATH_INFO'] = urllib.unquote(path)
env['QUERY_STRING'] = query env['QUERY_STRING'] = query
host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0] env['REMOTE_ADDR'] = self.client_address[0]
if self.headers.typeheader is None: if self.headers.typeheader is None:

View File

@ -86,10 +86,15 @@ class MatchChecker(object):
class RegexURLPattern(object): class RegexURLPattern(object):
def __init__(self, regex, callback, default_args=None): def __init__(self, regex, callback, default_args=None):
# regex is a string representing a regular expression. # regex is a string representing a regular expression.
# callback is something like 'foo.views.news.stories.story_detail', # callback is either a string like 'foo.views.news.stories.story_detail'
# which represents the path to a module and a view function name. # which represents the path to a module and a view function name, or a
# callable object (view).
self.regex = re.compile(regex) self.regex = re.compile(regex)
self.callback = callback if callable(callback):
self._callback = callback
else:
self._callback = None
self._callback_str = callback
self.default_args = default_args or {} self.default_args = default_args or {}
def resolve(self, path): def resolve(self, path):
@ -106,23 +111,28 @@ class RegexURLPattern(object):
# In both cases, pass any extra_kwargs as **kwargs. # In both cases, pass any extra_kwargs as **kwargs.
kwargs.update(self.default_args) kwargs.update(self.default_args)
try: # Lazily load self.func. return self.callback, args, kwargs
return self.func, args, kwargs
except AttributeError:
self.func = self.get_callback()
return self.func, args, kwargs
def get_callback(self): def _get_callback(self):
mod_name, func_name = get_mod_func(self.callback) if self._callback is not None:
return self._callback
mod_name, func_name = get_mod_func(self._callback_str)
try: try:
return 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:
raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
return self._callback
callback = property(_get_callback)
def reverse(self, viewname, *args, **kwargs): def reverse(self, viewname, *args, **kwargs):
if viewname != self.callback: mod_name, func_name = get_mod_func(viewname)
try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
except (ImportError, AttributeError):
raise NoReverseMatch
if lookup_view != self.callback:
raise NoReverseMatch raise NoReverseMatch
return self.reverse_helper(*args, **kwargs) return self.reverse_helper(*args, **kwargs)
@ -130,12 +140,13 @@ class RegexURLPattern(object):
return reverse_helper(self.regex, *args, **kwargs) return reverse_helper(self.regex, *args, **kwargs)
class RegexURLResolver(object): class RegexURLResolver(object):
def __init__(self, regex, urlconf_name): def __init__(self, regex, urlconf_name, default_kwargs=None):
# regex is a string representing a regular expression. # regex is a string representing a regular expression.
# urlconf_name is a string representing the module containing urlconfs. # urlconf_name is a string representing the module containing urlconfs.
self.regex = re.compile(regex) self.regex = re.compile(regex)
self.urlconf_name = urlconf_name self.urlconf_name = urlconf_name
self.callback = None self.callback = None
self.default_kwargs = default_kwargs or {}
def resolve(self, path): def resolve(self, path):
tried = [] tried = []
@ -149,7 +160,8 @@ class RegexURLResolver(object):
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
else: else:
if sub_match: if sub_match:
return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match[2]) sub_match_dict = dict(self.default_kwargs, **sub_match[2])
return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict)
tried.append(pattern.regex.pattern) tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path} raise Resolver404, {'tried': tried, 'path': new_path}
@ -183,22 +195,28 @@ class RegexURLResolver(object):
def resolve500(self): def resolve500(self):
return self._resolve_special('500') return self._resolve_special('500')
def reverse(self, viewname, *args, **kwargs): def reverse(self, lookup_view, *args, **kwargs):
if not callable(lookup_view):
mod_name, func_name = get_mod_func(lookup_view)
try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
except (ImportError, AttributeError):
raise NoReverseMatch
for pattern in self.urlconf_module.urlpatterns: for pattern in self.urlconf_module.urlpatterns:
if isinstance(pattern, RegexURLResolver): if isinstance(pattern, RegexURLResolver):
try: try:
return pattern.reverse_helper(viewname, *args, **kwargs) return pattern.reverse_helper(lookup_view, *args, **kwargs)
except NoReverseMatch: except NoReverseMatch:
continue continue
elif pattern.callback == viewname: elif pattern.callback == lookup_view:
try: try:
return pattern.reverse_helper(*args, **kwargs) return pattern.reverse_helper(*args, **kwargs)
except NoReverseMatch: except NoReverseMatch:
continue continue
raise NoReverseMatch raise NoReverseMatch
def reverse_helper(self, viewname, *args, **kwargs): def reverse_helper(self, lookup_view, *args, **kwargs):
sub_match = self.reverse(viewname, *args, **kwargs) sub_match = self.reverse(lookup_view, *args, **kwargs)
result = reverse_helper(self.regex, *args, **kwargs) result = reverse_helper(self.regex, *args, **kwargs)
return result + sub_match return result + sub_match
@ -209,11 +227,11 @@ def resolve(path, urlconf=None):
resolver = RegexURLResolver(r'^/', urlconf) resolver = RegexURLResolver(r'^/', urlconf)
return resolver.resolve(path) return resolver.resolve(path)
def reverse(viewname, urlconf, args=None, kwargs=None): def reverse(viewname, urlconf=None, args=None, kwargs=None):
args = args or [] args = args or []
kwargs = kwargs or {} kwargs = kwargs or {}
if urlconf is None: if urlconf is None:
from django.conf import settings from django.conf import settings
urlconf = settings.ROOT_URLCONF urlconf = settings.ROOT_URLCONF
resolver = RegexURLResolver(r'^/', urlconf) resolver = RegexURLResolver(r'^/', urlconf)
return resolver.reverse(viewname, *args, **kwargs) return '/' + resolver.reverse(viewname, *args, **kwargs)

View File

@ -11,6 +11,10 @@ except ImportError, e:
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e
# Register Unicode conversions
import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
DatabaseError = Database.DatabaseError DatabaseError = Database.DatabaseError
try: try:

View File

@ -16,6 +16,18 @@ from django.utils.text import capfirst
# Admin stages. # Admin stages.
ADD, CHANGE, BOTH = 1, 2, 3 ADD, CHANGE, BOTH = 1, 2, 3
# Decorator. Takes a function that returns a tuple in this format:
# (viewname, viewargs, viewkwargs)
# Returns a function that calls urlresolvers.reverse() on that data, to return
# the URL for those parameters.
def permalink(func):
from django.core.urlresolvers import reverse
def inner(*args, **kwargs):
bits = func(*args, **kwargs)
viewname = bits[0]
return reverse(bits[0], None, *bits[1:3])
return inner
class LazyDate(object): class LazyDate(object):
""" """
Use in limit_choices_to to compare the field to dates calculated at run time Use in limit_choices_to to compare the field to dates calculated at run time
@ -35,7 +47,7 @@ class LazyDate(object):
return "<LazyDate: %s>" % self.delta return "<LazyDate: %s>" % self.delta
def __get_value__(self): def __get_value__(self):
return datetime.datetime.now() + self.delta return (datetime.datetime.now() + self.delta).date()
def __getattr__(self, attr): def __getattr__(self, attr):
return getattr(self.__get_value__(), attr) return getattr(self.__get_value__(), attr)

View File

@ -44,7 +44,7 @@ class ModelBase(type):
new_class._meta.app_label = model_module.__name__.split('.')[-2] new_class._meta.app_label = model_module.__name__.split('.')[-2]
# Bail out early if we have already created this class. # Bail out early if we have already created this class.
m = get_model(new_class._meta.app_label, name) m = get_model(new_class._meta.app_label, name, False)
if m is not None: if m is not None:
return m return m
@ -73,7 +73,7 @@ class ModelBase(type):
# the first class for this model to register with the framework. There # the first class for this model to register with the framework. There
# should only be one class for each model, so we must always return the # should only be one class for each model, so we must always return the
# registered version. # registered version.
return get_model(new_class._meta.app_label, name) return get_model(new_class._meta.app_label, name, False)
class Model(object): class Model(object):
__metaclass__ = ModelBase __metaclass__ = ModelBase
@ -181,11 +181,12 @@ class Model(object):
# If it does already exist, do an UPDATE. # If it does already exist, do an UPDATE.
if cursor.fetchone(): if cursor.fetchone():
db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ if db_values:
(backend.quote_name(self._meta.db_table), cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), (backend.quote_name(self._meta.db_table),
backend.quote_name(self._meta.pk.column)), ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
db_values + [pk_val]) backend.quote_name(self._meta.pk.column)),
db_values + [pk_val])
else: else:
record_exists = False record_exists = False
if not pk_set or not record_exists: if not pk_set or not record_exists:

View File

@ -20,7 +20,7 @@ BLANK_CHOICE_DASH = [("", "---------")]
BLANK_CHOICE_NONE = [("", "None")] BLANK_CHOICE_NONE = [("", "None")]
# prepares a value for use in a LIKE query # prepares a value for use in a LIKE query
prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_") prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
# returns the <ul> class for a given radio_admin value # returns the <ul> class for a given radio_admin value
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
@ -247,9 +247,9 @@ class Field(object):
params['is_required'] = not self.blank and not self.primary_key and not rel params['is_required'] = not self.blank and not self.primary_key and not rel
# BooleanFields (CheckboxFields) are a special case. They don't take # BooleanFields (CheckboxFields) are a special case. They don't take
# is_required or validator_list. # is_required.
if isinstance(self, BooleanField): if isinstance(self, BooleanField):
del params['validator_list'], params['is_required'] del params['is_required']
# If this field is in a related context, check whether any other fields # If this field is in a related context, check whether any other fields
# in the related object have core=True. If so, add a validator -- # in the related object have core=True. If so, add a validator --
@ -289,8 +289,11 @@ class Field(object):
if self.choices: if self.choices:
return first_choice + list(self.choices) return first_choice + list(self.choices)
rel_model = self.rel.to rel_model = self.rel.to
return first_choice + [(x._get_pk_val(), str(x)) if hasattr(self.rel, 'get_related_field'):
for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)] lst = [(getattr(x, self.rel.get_related_field().attname), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
else:
lst = [(x._get_pk_val(), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
return first_choice + lst
def get_choices_default(self): def get_choices_default(self):
if self.radio_admin: if self.radio_admin:

View File

@ -25,7 +25,7 @@ def add_lookup(rel_cls, field):
key = (module, name) key = (module, name)
# Has the model already been loaded? # Has the model already been loaded?
# If so, resolve the string reference right away # If so, resolve the string reference right away
model = get_model(rel_cls._meta.app_label,field.rel.to) model = get_model(rel_cls._meta.app_label, field.rel.to, False)
if model: if model:
field.rel.to = model field.rel.to = model
field.do_related_class(model, rel_cls) field.do_related_class(model, rel_cls)

View File

@ -32,7 +32,7 @@ def get_apps():
_app_errors[app_name] = e _app_errors[app_name] = e
return _app_list return _app_list
def get_app(app_label, emptyOK = False): def get_app(app_label, emptyOK=False):
"Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None." "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
for app_name in settings.INSTALLED_APPS: for app_name in settings.INSTALLED_APPS:
@ -75,11 +75,15 @@ def get_models(app_mod=None):
model_list.extend(get_models(app_mod)) model_list.extend(get_models(app_mod))
return model_list return model_list
def get_model(app_label, model_name): def get_model(app_label, model_name, seed_cache=True):
""" """
Returns the model matching the given app_label and case-insensitive model_name. Returns the model matching the given app_label and case-insensitive
model_name.
Returns None if no model is found. Returns None if no model is found.
""" """
if seed_cache:
get_apps()
try: try:
model_dict = _app_models[app_label] model_dict = _app_models[app_label]
except KeyError: except KeyError:

View File

@ -138,7 +138,7 @@ class AutomaticManipulator(forms.Manipulator):
child_follow = self.follow.get(related.name, None) child_follow = self.follow.get(related.name, None)
if child_follow: if child_follow:
obj_list = expanded_data[related.var_name].items() obj_list = expanded_data.get(related.var_name, {}).items()
if not obj_list: if not obj_list:
continue continue

View File

@ -434,10 +434,12 @@ class HiddenField(FormField):
(self.get_id(), self.field_name, escape(data)) (self.get_id(), self.field_name, escape(data))
class CheckboxField(FormField): class CheckboxField(FormField):
def __init__(self, field_name, checked_by_default=False): def __init__(self, field_name, checked_by_default=False, validator_list=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
self.checked_by_default = checked_by_default self.checked_by_default = checked_by_default
self.is_required, self.validator_list = False, [] # because the validator looks for these self.is_required = False # because the validator looks for these
self.validator_list = validator_list[:]
def render(self, data): def render(self, data):
checked_html = '' checked_html = ''

View File

@ -203,11 +203,14 @@ class HttpResponse(object):
if val is not None: if val is not None:
self.cookies[key][var.replace('_', '-')] = val self.cookies[key][var.replace('_', '-')] = val
def delete_cookie(self, key): def delete_cookie(self, key, path='/', domain=None):
try: self.cookies[key] = ''
self.cookies[key]['max_age'] = 0 if path is not None:
except KeyError: self.cookies[key]['path'] = path
pass if domain is not None:
self.cookies[key]['domain'] = path
self.cookies[key]['expires'] = 0
self.cookies[key]['max-age'] = 0
def _get_content(self): def _get_content(self):
content = ''.join(self._iterator) content = ''.join(self._iterator)

View File

@ -12,7 +12,11 @@ class GZipMiddleware(object):
""" """
def process_response(self, request, response): def process_response(self, request, response):
patch_vary_headers(response, ('Accept-Encoding',)) patch_vary_headers(response, ('Accept-Encoding',))
if response.has_header('Content-Encoding'):
# Avoid gzipping if we've already got a content-encoding or if the
# content-type is Javascript (silly IE...)
is_js = "javascript" in response.headers.get('Content-Type', '').lower()
if response.has_header('Content-Encoding') or is_js:
return response return response
ae = request.META.get('HTTP_ACCEPT_ENCODING', '') ae = request.META.get('HTTP_ACCEPT_ENCODING', '')

View File

@ -339,7 +339,7 @@ def date(value, arg=None):
def time(value, arg=None): def time(value, arg=None):
"Formats a time according to the given format" "Formats a time according to the given format"
from django.utils.dateformat import time_format from django.utils.dateformat import time_format
if not value: if value in (None, ''):
return '' return ''
if arg is None: if arg is None:
arg = settings.TIME_FORMAT arg = settings.TIME_FORMAT

View File

@ -50,6 +50,8 @@ class ExtendsNode(Node):
if self.parent_name_expr: if self.parent_name_expr:
error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr. error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr.
raise TemplateSyntaxError, error_msg raise TemplateSyntaxError, error_msg
if hasattr(parent, 'render'):
return parent
try: try:
source, origin = find_template_source(parent, self.template_dirs) source, origin = find_template_source(parent, self.template_dirs)
except TemplateDoesNotExist: except TemplateDoesNotExist:
@ -137,8 +139,9 @@ def do_extends(parser, token):
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes) This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend, uses the literal value "base" as the name of the parent template to extend,
or ``{% extends variable %}`` uses the value of ``variable`` as the name or ``{% extends variable %}`` uses the value of ``variable`` as either the
of the parent template to extend. name of the parent template to extend (if it evaluates to a string,) or as
the parent tempate itelf (if it evaluates to a Template object).
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 2: if len(bits) != 2:

View File

@ -17,7 +17,7 @@ def load_template_source(template_name, template_dirs=None):
return (open(filepath).read(), filepath) return (open(filepath).read(), filepath)
except IOError: except IOError:
tried.append(filepath) tried.append(filepath)
if template_dirs: if tried:
error_msg = "Tried %s" % tried error_msg = "Tried %s" % tried
else: else:
error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory." error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."

View File

@ -35,6 +35,14 @@ try:
except ImportError: except ImportError:
import dummy_thread as thread import dummy_thread as thread
# This import does nothing, but it's necessary to avoid some race conditions
# in the threading module. See http://code.djangoproject.com/ticket/2330 .
try:
import threading
except ImportError:
pass
RUN_RELOADER = True RUN_RELOADER = True
def reloader_thread(): def reloader_thread():

View File

@ -6,6 +6,7 @@ from django.contrib.auth.views import redirect_to_login
from django.template import RequestContext from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.utils.translation import gettext
def create_object(request, model, template_name=None, def create_object(request, model, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None, template_loader=loader, extra_context=None, post_save_redirect=None,
@ -39,7 +40,7 @@ def create_object(request, model, template_name=None,
new_object = manipulator.save(new_data) new_object = manipulator.save(new_data)
if request.user.is_authenticated(): if request.user.is_authenticated():
request.user.message_set.create(message="The %s was created successfully." % model._meta.verbose_name) request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
# Redirect to the new object: first by trying post_save_redirect, # Redirect to the new object: first by trying post_save_redirect,
# then by obj.get_absolute_url; fail if neither works. # then by obj.get_absolute_url; fail if neither works.
@ -113,7 +114,7 @@ def update_object(request, model, object_id=None, slug=None,
object = manipulator.save(new_data) object = manipulator.save(new_data)
if request.user.is_authenticated(): if request.user.is_authenticated():
request.user.message_set.create(message="The %s was updated successfully." % model._meta.verbose_name) request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
# Do a post-after-redirect so that reload works, etc. # Do a post-after-redirect so that reload works, etc.
if post_save_redirect: if post_save_redirect:
@ -180,7 +181,7 @@ def delete_object(request, model, post_delete_redirect,
if request.method == 'POST': if request.method == 'POST':
object.delete() object.delete()
if request.user.is_authenticated(): if request.user.is_authenticated():
request.user.message_set.create(message="The %s was deleted." % model._meta.verbose_name) request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
return HttpResponseRedirect(post_delete_redirect) return HttpResponseRedirect(post_delete_redirect)
else: else:
if not template_name: if not template_name:

View File

@ -2,12 +2,15 @@
The "contrib" add-ons The "contrib" add-ons
===================== =====================
Django aims to follow Python's "batteries included" philosophy. It ships with a Django aims to follow Python's `"batteries included" philosophy`_. It ships
variety of extra, optional tools that solve common Web-development problems. with a variety of extra, optional tools that solve common Web-development
problems.
This code lives in ``django/contrib`` in the Django distribution. Here's a This code lives in ``django/contrib`` in the Django distribution. Here's a
rundown of the packages in ``contrib``: rundown of the packages in ``contrib``:
.. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included
admin admin
===== =====

View File

@ -6,6 +6,9 @@ Although Django has not reached a 1.0 release, the bulk of Django's public APIs
stable as of the 0.95 release. This document explains which APIs will and will not stable as of the 0.95 release. This document explains which APIs will and will not
change before the 1.0 release. change before the 1.0 release.
What "stable" means
===================
In this context, stable means: In this context, stable means:
- All the public APIs -- everything documented in the linked documents, and - All the public APIs -- everything documented in the linked documents, and
@ -24,6 +27,9 @@ In this context, stable means:
- We'll only break backwards compatibility of these APIs if a bug or - We'll only break backwards compatibility of these APIs if a bug or
security hole makes it completely unavoidable. security hole makes it completely unavoidable.
Stable APIs
===========
These APIs are stable: These APIs are stable:
- `Caching`_. - `Caching`_.

View File

@ -578,6 +578,9 @@ related ``Person`` *and* the related ``City``::
p = b.author # Hits the database. p = b.author # Hits the database.
c = p.hometown # Hits the database. c = p.hometown # Hits the database.
Note that ``select_related()`` does not follow foreign keys that have
``null=True``.
``extra(select=None, where=None, params=None, tables=None)`` ``extra(select=None, where=None, params=None, tables=None)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1468,11 +1471,12 @@ the ``ForeignKey`` ``Manager`` has these additional methods:
b.entry_set.remove(e) # Disassociates Entry e from Blog b. b.entry_set.remove(e) # Disassociates Entry e from Blog b.
In order to prevent database inconsistency, this method only exists on In order to prevent database inconsistency, this method only exists on
``ForeignKey``s where ``null=True``. If the related field can't be set to ``ForeignKey`` objects where ``null=True``. If the related field can't be
``None`` (``NULL``), then an object can't be removed from a relation set to ``None`` (``NULL``), then an object can't be removed from a
without being added to another. In the above example, removing ``e`` from relation without being added to another. In the above example, removing
``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because ``e`` from ``b.entry_set()`` is equivalent to doing ``e.blog = None``,
the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid. and because the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this
is invalid.
* ``clear()``: Removes all objects from the related object set. * ``clear()``: Removes all objects from the related object set.

148
docs/documentation.txt Normal file
View File

@ -0,0 +1,148 @@
====================================
How to read the Django documentation
====================================
We've put a lot of effort into making Django's documentation useful, easy to
read and as complete as possible. Here are a few tips on how to make the best
of it, along with some style guidelines.
(Yes, this is documentation about documentation. Rest assured we have no plans
to write a document about how to read the document about documentation.)
How documentation is updated
============================
Just as the Django code base is developed and improved on a daily basis, our
documentation is consistently improving. We improve documentation for several
reasons:
* To make content fixes, such as grammar/typo corrections.
* To add information and/or examples to existing sections that need to be
expanded.
* To document Django features that aren't yet documented. (The list of
such features is shrinking but exists nonetheless.)
* To add documentation for new features as new features get added, or as
Django APIs or behaviors change.
Django's documentation is kept in the same source control system as its code.
It lives in the `django/trunk/docs`_ directory of our Subversion repository.
Each document is a separate text file that covers a narrowly focused topic,
such as the "generic views" framework or how to construct a database model.
.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs
Where to get it
===============
You can read Django documentation in several ways. They are, in order of
preference:
On the Web
----------
The most recent version of the Django documentation lives at
http://www.djangoproject.com/documentation/ . These HTML pages are generated
automatically from the text files in source control every 15 minutes. That
means they reflect the "latest and greatest" in Django -- they include the very
latest corrections and additions, and they discuss the latest Django features,
which may only be available to users of the Django development version. (See
"Differences between versions" below.)
A key advantage of the Web-based documentation is the comment section at the
bottom of each document. This is an area for anybody to submit changes,
corrections and suggestions about the given document. The Django developers
frequently monitor the comments there and use them to improve the documentation
for everybody.
We encourage you to help improve the docs: it's easy! Note, however, that
comments should explicitly relate to the documentation, rather than asking
broad tech-support questions. If you need help with your particular Django
setup, try the `django-users mailing list`_ instead of posting a comment to the
documentation.
.. _django-users mailing list: http://groups.google.com/group/django-users
In plain text
-------------
For offline reading, or just for convenience, you can read the Django
documentation in plain text.
If you're using an official release of Django, note that the zipped package
(tarball) of the code includes a ``docs/`` directory, which contains all the
documentation for that release.
If you're using the development version of Django (aka the Subversion "trunk"),
note that the ``docs/`` directory contains all of the documentation. You can
``svn update`` it, just as you ``svn update`` the Python code, in order to get
the latest changes.
You can check out the latest Django documentation from Subversion using this
shell command::
svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs
One low-tech way of taking advantage of the text documentation is by using the
Unix ``grep`` utility to search for a phrase in all of the documentation. For
example, this will show you each mention of the phrase "edit_inline" in any
Django document::
grep edit_inline /path/to/django/docs/*.txt
Formatting
~~~~~~~~~~
The text documentation is written in ReST (ReStructured Text) format. That
means it's easy to read but is also formatted in a way that makes it easy to
convert into other formats, such as HTML. If you're interested, the script that
converts the ReST text docs into djangoproject.com's HTML lives at
`djangoproject.com/django_website/apps/docs/parts/build_documentation.py`_ in
the Django Subversion repository.
.. _djangoproject.com/django_website/apps/docs/parts/build_documentation.py: http://code.djangoproject.com/browser/djangoproject.com/django_website/apps/docs/parts/build_documentation.py
Differences between versions
============================
As previously mentioned, the text documentation in our Subversion repository
contains the "latest and greatest" changes and additions. These changes often
include documentation of new features added in the Django development version
-- the Subversion ("trunk") version of Django. For that reason, it's worth
pointing out our policy on keeping straight the documentation for various
versions of the framework.
We follow this policy:
* The primary documentation on djangoproject.com is an HTML version of the
latest docs in Subversion. These docs always correspond to the latest
official Django release, plus whatever features we've added/changed in
the framework *since* the latest release.
* As we add features to Django's development version, we try to update the
documentation in the same Subversion commit transaction.
* To distinguish feature changes/additions in the docs, we use the phrase
**New in Django development version**. In practice, this means that the
current documentation on djangoproject.com can be used by users of either
the latest release *or* the development version.
* Documentation for a particular Django release is frozen once the version
has been released officially. It remains a snapshot of the docs as of the
moment of the release. We will make exceptions to this rule in
the case of retroactive security updates or other such retroactive
changes. Once documentation is frozen, we add a note to the top of each
frozen document that says "These docs are frozen for Django version XXX"
and links to the current version of that document.
* Once a document is frozen for a Django release, we remove comments from
that page, in favor of having comments on the latest version of that
document. This is for the sake of maintainability and usability, so that
users have one, and only one, place to leave comments on a particular
document. We realize that some people may be stuck on a previous version
of Django, but we believe the usability problems with multiple versions
of a document the outweigh the benefits.
* The `main documentation Web page`_ includes links to documentation for
all previous versions.
.. _main documentation Web page: http://www.djangoproject.com/documentation/

View File

@ -251,6 +251,16 @@ information than the docs that come with the latest Django release.
.. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs .. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs
Where can I find Django developers for hire?
--------------------------------------------
Consult our `developers for hire page`_ for a list of Django developers who
would be happy to help you.
You might also be interested in posting a job to http://www.gypsyjobs.com/ .
.. _developers for hire page: http://code.djangoproject.com/wiki/DevelopersForHire
Installation questions Installation questions
====================== ======================
@ -610,13 +620,10 @@ like to make should be possible by editing the stylesheet. We've got a
How do I create users without having to edit password hashes? How do I create users without having to edit password hashes?
------------------------------------------------------------- -------------------------------------------------------------
We don't recommend you create users via the admin interface, because at the If you'd like to use the admin site to create users, upgrade to the Django
moment it requires you to edit password hashes manually. (Passwords are hashed development version, where this problem was fixed on Aug. 4, 2006.
using one-way hash algorithms for security; there's currently no Web interface
for changing passwords by entering the actual password rather than the hash.)
To create a user, you'll have to use the Python API. See `creating users`_ for You can also use the Python API. See `creating users`_ for full info.
full info.
.. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users .. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users

View File

@ -405,6 +405,43 @@ Here's a simple function that might drive the above form::
form = forms.FormWrapper(manipulator, new_data, errors) form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('contact_form.html', {'form': form}) return render_to_response('contact_form.html', {'form': form})
``FileField`` and ``ImageField`` special cases
==============================================
Dealing with ``FileField`` and ``ImageField`` objects is a little more
complicated.
First, you'll need to make sure that your ``<form>`` element correctly defines
the ``enctype`` as ``"multipart/form-data"``, in order to upload files::
<form enctype="multipart/form-data" method="post" action="/foo/">
Next, you'll need to treat the field in the template slightly differently. A
``FileField`` or ``ImageField`` is represented by *two* HTML form elements.
For example, given this field in a model::
photo = model.ImageField('/path/to/upload/location')
You'd need to display two formfields in the template::
<p><label for="id_photo">Photo:</label> {{ form.photo }}{{ form.photo_file }}</p>
The first bit (``{{ form.photo }}``) displays the currently-selected file,
while the second (``{{ form.photo_file }}``) actually contains the file upload
form field. Thus, at the validation layer you need to check the ``photo_file``
key.
Finally, in your view, make sure to access ``request.FILES``, rather than
``request.POST``, for the uploaded files. This is necessary because
``request.POST`` does not contain file-upload data.
For example, following the ``new_data`` convention, you might do something like
this::
new_data = request.POST.copy()
new_data.update(request.FILES)
Validators Validators
========== ==========

View File

@ -127,7 +127,7 @@ If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410).
This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``:: This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``::
urlpatterns = patterns('django.views.generic.simple', urlpatterns = patterns('django.views.generic.simple',
('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}), ('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
) )
This example returns a 410 HTTP error for requests to ``/bar/``:: This example returns a 410 HTTP error for requests to ``/bar/``::

View File

@ -77,9 +77,9 @@ It's easy either way.
Installing the official version Installing the official version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Download Django-0.91.tar.gz from our `download page`_. 1. Download Django-0.95.tar.gz from our `download page`_.
2. ``tar xzvf Django-0.91.tar.gz`` 2. ``tar xzvf Django-0.95.tar.gz``
3. ``cd Django-0.91`` 3. ``cd Django-0.95``
4. ``sudo python setup.py install`` 4. ``sudo python setup.py install``
Note that the last command will automatically download and install setuptools_ Note that the last command will automatically download and install setuptools_
@ -89,14 +89,6 @@ connection.
This will install Django in your Python installation's ``site-packages`` This will install Django in your Python installation's ``site-packages``
directory. directory.
.. note::
Due to recent backwards-incompatible changes, it is strongly recommended
that you use the development version (below) for any new applications or
if you are just starting to work with Django. The 0.91 release is a
dead-end branch that is primarily of use for supporting legacy Django
applications.
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
Installing the development version Installing the development version

View File

@ -223,6 +223,13 @@ steps:
the absolute URL to your image in a template with ``{{ the absolute URL to your image in a template with ``{{
object.get_mug_shot_url }}``. object.get_mug_shot_url }}``.
For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and
``upload_to`` is set to ``'photos/%Y/%m/%d'``. The ``'%Y/%m/%d'`` part of
``upload_to`` is strftime formatting; ``'%Y'`` is the four-digit year,
``'%m'`` is the two-digit month and ``'%d'`` is the two-digit day. If you
upload a file on Jan. 15, 2007, it will be saved in the directory
``/home/media/photos/2007/01/15``.
.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
``FilePathField`` ``FilePathField``

126
docs/release_notes_0.95.txt Normal file
View File

@ -0,0 +1,126 @@
=================================
Django version 0.95 release notes
=================================
Welcome to the Django 0.95 release.
This represents a significant advance in Django development since the 0.91
release in January 2006. The details of every change in this release would be
too extensive to list in full, but a summary is presented below.
Suitability and API stability
=============================
This release is intended to provide a stable reference point for developers
wanting to work on production-level applications that use Django.
However, it's not the 1.0 release, and we'll be introducing further changes
before 1.0. For a clear look at which areas of the framework will change (and
which ones will *not* change) before 1.0, see the api-stability.txt file, which
lives in the docs/ directory of the distribution.
You may have a need to use some of the features that are marked as
"subject to API change" in that document, but that's OK with us as long as it's
OK with you, and as long as you understand APIs may change in the future.
Fortunately, most of Django's core APIs won't be changing before version 1.0.
There likely won't be as big of a change between 0.95 and 1.0 versions as there
was between 0.91 and 0.95.
Changes and new features
========================
The major changes in this release (for developers currently using the 0.91
release) are a result of merging the 'magic-removal' branch of development.
This branch removed a number of constraints in the way Django code had to be
written that were a consequence of decisions made in the early days of Django,
prior to its open-source release. It's now possible to write more natural,
Pythonic code that works as expected, and there's less "black magic" happening
behind the scenes.
Aside from that, another main theme of this release is a dramatic increase in
usability. We've made countless improvements in error messages, documentation,
etc., to improve developers' quality of life.
The new features and changes introduced in 0.95 include:
* Django now uses a more consistent and natural filtering interface for
retrieving objects from the database.
* User-defined models, functions and constants now appear in the module
namespace they were defined in. (Previously everything was magically
transferred to the django.models.* namespace.)
* Some optional applications, such as the FlatPage, Sites and Redirects
apps, have been decoupled and moved into django.contrib. If you don't
want to use these applications, you no longer have to install their
database tables.
* Django now has support for managing database transactions.
* We've added the ability to write custom authentication and authorization
backends for authenticating users against alternate systems, such as
LDAP.
* We've made it easier to add custom table-level functions to models,
through a new "Manager" API.
* It's now possible to use Django without a database. This simply means
that the framework no longer requires you to have a working database set
up just to serve dynamic pages. In other words, you can just use
URLconfs/views on their own. Previously, the framework required that a
database be configured, regardless of whether you actually used it.
* It's now more explicit and natural to override save() and delete()
methods on models, rather than needing to hook into the pre_save() and
post_save() method hooks.
* Individual pieces of the framework now can be configured without
requiring the setting of an environment variable. This permits use of,
for example, the Django templating system inside other applications.
* More and more parts of the framework have been internationalized, as
we've expanded internationalization (i18n) support. The Django
codebase, including code and templates, has now been translated, at least
in part, into 31 languages. From Arabic to Chinese to Hungarian to Welsh,
it is now possible to use Django's admin site in your native language.
The number of changes required to port from 0.91-compatible code to the 0.95
code base are significant in some cases. However, they are, for the most part,
reasonably routine and only need to be done once. A list of the necessary
changes is described in the `Removing The Magic`_ wiki page. There is also an
easy checklist_ for reference when undertaking the porting operation.
.. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic
.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1
Problem reports and getting help
================================
Need help resolving a problem with Django? The documentation in the
distribution is also available online_ at the `Django website`_. The FAQ_
document is especially recommended, as it contains a number of issues that
come up time and again.
For more personalized help, the `django-users`_ mailing list is a very active
list, with more than 2,000 subscribers who can help you solve any sort of
Django problem. We recommend you search the archives first, though, because
many common questions appear with some regularity, and any particular problem
may already have been answered.
Finally, for those who prefer the more immediate feedback offered by IRC,
there's a #django channel or irc.freenode.net that is regularly populated by
Django users and developers from around the world. Friendly people are usually
available at any hour of the day -- to help, or just to chat.
.. _online: http://www.djangoproject.com/documentation/
.. _Django website: http://www.djangoproject.com/
.. _FAQ: http://www.djangoproject.com/documentation/faq/
.. _django-users: http://groups.google.com/group/django-users
Thanks for using Django!
The Django Team
July 2006

View File

@ -380,10 +380,14 @@ Methods
.. _`cookie Morsel`: http://www.python.org/doc/current/lib/morsel-objects.html .. _`cookie Morsel`: http://www.python.org/doc/current/lib/morsel-objects.html
``delete_cookie(key)`` ``delete_cookie(key, path='/', domain=None)``
Deletes the cookie with the given key. Fails silently if the key doesn't Deletes the cookie with the given key. Fails silently if the key doesn't
exist. exist.
The ``path`` and ``domain`` arguments are new in the Django development version.
Due to the way cookies work, ``path`` and ``domain`` should be the same
values you used in ``set_cookie()`` -- otherwise the cookie may not be deleted.
``content`` ``content``
Returns the content as a Python string, encoding it from a Unicode object Returns the content as a Python string, encoding it from a Unicode object
if necessary. Note this is a property, not a method, so use ``r.content`` if necessary. Note this is a property, not a method, so use ``r.content``

View File

@ -245,6 +245,17 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want. The name of the cookie to use for sessions. This can be whatever you want.
SESSION_COOKIE_SECURE
---------------------
**New in Django development version**
Default: ``False``
Whether to use a secure cookie for the session cookie. If this is set to
``True``, the cookie will be marked as "secure," which means browsers may
ensure that the cookie is only sent under an HTTPS connection.
SESSION_EXPIRE_AT_BROWSER_CLOSE SESSION_EXPIRE_AT_BROWSER_CLOSE
------------------------------- -------------------------------

View File

@ -647,6 +647,18 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want. The name of the cookie to use for sessions. This can be whatever you want.
See the `session docs`_. See the `session docs`_.
SESSION_COOKIE_SECURE
---------------------
**New in Django development version**
Default: ``False``
Whether to use a secure cookie for the session cookie. If this is set to
``True``, the cookie will be marked as "secure," which means browsers may
ensure that the cookie is only sent under an HTTPS connection.
See the `session docs`_.
SESSION_EXPIRE_AT_BROWSER_CLOSE SESSION_EXPIRE_AT_BROWSER_CLOSE
------------------------------- -------------------------------

View File

@ -363,10 +363,15 @@ extends
Signal that this template extends a parent template. Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base.html" %}`` (with quotes) This tag can be used in two ways:
uses the literal value "base.html" as the name of the parent template to
extend, or ``{% extends variable %}`` uses the value of ``variable`` as the * ``{% extends "base.html" %}`` (with quotes) uses the literal value
name of the parent template to extend. ``"base.html"`` as the name of the parent template to extend.
* ``{% extends variable %}`` uses the value of ``variable``. If the variable
evaluates to a string, Django will use that string as the name of the
parent template. If the variable evaluates to a ``Template`` object,
Django will use that object as the parent template.
See `Template inheritance`_ for more information. See `Template inheritance`_ for more information.
@ -493,6 +498,11 @@ If you need to combine ``and`` and ``or`` to do advanced logic, just use nested
{% endif %} {% endif %}
{% endif %} {% endif %}
Multiple uses of the same logical operator are fine, as long as you use the
same operator. For example, this is valid::
{% if athlete_list or coach_list or parent_list or teacher_list %}
ifchanged ifchanged
~~~~~~~~~ ~~~~~~~~~

View File

@ -198,21 +198,6 @@ some things to keep in mind:
How invalid variables are handled How invalid variables are handled
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Django 0.91, if a variable doesn't exist, the template system fails
silently. The variable is replaced with an empty string::
>>> t = Template("My name is {{ my_name }}.")
>>> c = Context({"foo": "bar"})
>>> t.render(c)
"My name is ."
This applies to any level of lookup::
>>> t = Template("My name is {{ person.fname }} {{ person.lname }}.")
>>> c = Context({"person": {"fname": "Stan"}})
>>> t.render(c)
"My name is Stan ."
If a variable doesn't exist, the template system inserts the value of the If a variable doesn't exist, the template system inserts the value of the
``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty
string) by default. string) by default.

View File

@ -81,7 +81,7 @@ the following output on the command line::
Validating models... Validating models...
0 errors found. 0 errors found.
Django version 0.95 (post-magic-removal), using settings 'mysite.settings' Django version 0.95, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/ Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).

View File

@ -263,12 +263,12 @@ Here's the example URLconf from the `Django overview`_::
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'), (r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'), (r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'), (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'),
) )
In this example, each view has a common prefix -- ``'myproject.news.views'``. In this example, each view has a common prefix -- ``'mysite.news.views'``.
Instead of typing that out for each entry in ``urlpatterns``, you can use the Instead of typing that out for each entry in ``urlpatterns``, you can use the
first argument to the ``patterns()`` function to specify a prefix to apply to first argument to the ``patterns()`` function to specify a prefix to apply to
each view function. each view function.
@ -277,7 +277,7 @@ With this in mind, the above example can be written more concisely as::
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
urlpatterns = patterns('myproject.news.views', urlpatterns = patterns('mysite.news.views',
(r'^articles/(\d{4})/$', 'year_archive'), (r'^articles/(\d{4})/$', 'year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
@ -389,3 +389,90 @@ to pass metadata and options to views.
.. _generic views: http://www.djangoproject.com/documentation/generic_views/ .. _generic views: http://www.djangoproject.com/documentation/generic_views/
.. _syndication framework: http://www.djangoproject.com/documentation/syndication/ .. _syndication framework: http://www.djangoproject.com/documentation/syndication/
Passing extra options to ``include()``
--------------------------------------
**New in the Django development version.**
Similarly, you can pass extra options to ``include()``. When you pass extra
options to ``include()``, *each* line in the included URLconf will be passed
the extra options.
For example, these two URLconf sets are functionally identical:
Set one::
# main.py
urlpatterns = patterns('',
(r'^blog/', include('inner'), {'blogid': 3}),
)
# inner.py
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive'),
(r'^about/$', 'mysite.views.about'),
)
Set two::
# main.py
urlpatterns = patterns('',
(r'^blog/', include('inner')),
)
# inner.py
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
(r'^about/$', 'mysite.views.about', {'blogid': 3}),
)
Note that extra options will *always* be passed to *every* line in the included
URLconf, regardless of whether the line's view actually accepts those options
as valid. For this reason, this technique is only useful if you're certain that
every view in the the included URLconf accepts the extra options you're passing.
Passing callable objects instead of strings
===========================================
**New in the Django development version.**
Some developers find it more natural to pass the actual Python function object
rather than a string containing the path to its module. This alternative is
supported -- you can pass any callable object as the view.
For example, given this URLconf in "string" notation::
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive'),
(r'^about/$', 'mysite.views.about'),
(r'^contact/$', 'mysite.views.contact'),
)
You can accomplish the same thing by passing objects rather than strings. Just
be sure to import the objects::
from mysite.views import archive, about, contact
urlpatterns = patterns('',
(r'^archive/$', archive),
(r'^about/$', about),
(r'^contact/$', contact),
)
The following example is functionally identical. It's just a bit more compact
because it imports the module that contains the views, rather than importing
each view individually::
from mysite import views
urlpatterns = patterns('',
(r'^archive/$', views.archive),
(r'^about/$', views.about),
(r'^contact/$', views.contact),
)
The style you use is up to you.
Note that if you use this technique -- passing objects rather than strings --
the view prefix (as explained in "The view prefix" above) will have no effect.

View File

@ -14,38 +14,9 @@ setup(
packages = find_packages(exclude=['examples', 'examples.*']), packages = find_packages(exclude=['examples', 'examples.*']),
package_data = { package_data = {
'': ['*.TXT'], '': ['*.TXT'],
'django.conf': ['locale/ar/LC_MESSAGES/*', 'django.conf': ['locale/*/LC_MESSAGES/*'],
'locale/bn/LC_MESSAGES/*',
'locale/cs/LC_MESSAGES/*',
'locale/cy/LC_MESSAGES/*',
'locale/da/LC_MESSAGES/*',
'locale/de/LC_MESSAGES/*',
'locale/el/LC_MESSAGES/*',
'locale/en/LC_MESSAGES/*',
'locale/es/LC_MESSAGES/*',
'locale/es_AR/LC_MESSAGES/*',
'locale/fr/LC_MESSAGES/*',
'locale/gl/LC_MESSAGES/*',
'locale/hu/LC_MESSAGES/*',
'locale/he/LC_MESSAGES/*',
'locale/is/LC_MESSAGES/*',
'locale/it/LC_MESSAGES/*',
'locale/ja/LC_MESSAGES/*',
'locale/nl/LC_MESSAGES/*',
'locale/no/LC_MESSAGES/*',
'locale/pl/LC_MESSAGES/*',
'locale/pt_BR/LC_MESSAGES/*',
'locale/ro/LC_MESSAGES/*',
'locale/ru/LC_MESSAGES/*',
'locale/sk/LC_MESSAGES/*',
'locale/sl/LC_MESSAGES/*',
'locale/sr/LC_MESSAGES/*',
'locale/sv/LC_MESSAGES/*',
'locale/ta/LC_MESSAGES/*',
'locale/uk/LC_MESSAGES/*',
'locale/zh_CN/LC_MESSAGES/*',
'locale/zh_TW/LC_MESSAGES/*'],
'django.contrib.admin': ['templates/admin/*.html', 'django.contrib.admin': ['templates/admin/*.html',
'templates/admin/auth/user/*.html',
'templates/admin_doc/*.html', 'templates/admin_doc/*.html',
'templates/registration/*.html', 'templates/registration/*.html',
'templates/widget/*.html', 'templates/widget/*.html',

View File

@ -20,5 +20,7 @@ API_TESTS = """
2 2
>>> m.id is not None >>> m.id is not None
True True
>>> existing = Empty(m.id)
>>> existing.save()
""" """

View File

@ -15,7 +15,7 @@ class Article(models.Model):
def __str__(self): def __str__(self):
return self.headline return self.headline
API_TESTS = """ API_TESTS = r"""
# Create a couple of Articles. # Create a couple of Articles.
>>> from datetime import datetime >>> from datetime import datetime
>>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26)) >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
@ -161,13 +161,14 @@ DoesNotExist: Article matching query does not exist.
<Article: Article 1> <Article: Article 1>
# Underscores and percent signs have special meaning in the underlying # Underscores and percent signs have special meaning in the underlying
# database library, but Django handles the quoting of them automatically. # SQL code, but Django handles the quoting of them automatically.
>>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20)) >>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
>>> a8.save() >>> a8.save()
>>> Article.objects.filter(headline__startswith='Article') >>> Article.objects.filter(headline__startswith='Article')
[<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] [<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
>>> Article.objects.filter(headline__startswith='Article_') >>> Article.objects.filter(headline__startswith='Article_')
[<Article: Article_ with underscore>] [<Article: Article_ with underscore>]
>>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21)) >>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
>>> a9.save() >>> a9.save()
>>> Article.objects.filter(headline__startswith='Article') >>> Article.objects.filter(headline__startswith='Article')
@ -182,4 +183,12 @@ DoesNotExist: Article matching query does not exist.
[<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] [<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
>>> Article.objects.exclude(headline="Article 7") >>> Article.objects.exclude(headline="Article 7")
[<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>] [<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
# Backslashes also have special meaning in the underlying SQL code, but Django
# automatically quotes them appropriately.
>>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
>>> a10.save()
>>> Article.objects.filter(headline__contains='\\')
[<Article: Article with \ backslash>]
""" """

View File

@ -231,6 +231,9 @@ False
>>> time(datetime.time(13), "h") >>> time(datetime.time(13), "h")
'01' '01'
>>> time(datetime.time(0), "h")
'12'
# real testing is done in timesince.py, where we can provide our own 'now' # real testing is done in timesince.py, where we can provide our own 'now'
>>> timesince(datetime.datetime.now() - datetime.timedelta(1)) >>> timesince(datetime.datetime.now() - datetime.timedelta(1))
'1 day' '1 day'

View File

@ -410,6 +410,12 @@ TEMPLATE_TESTS = {
# Three-level inheritance with {{ block.super }} from parent and grandparent # Three-level inheritance with {{ block.super }} from parent and grandparent
'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'), 'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'),
# Inheritance from local context without use of template loader
'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'),
# Inheritance from local context with variable parent template
'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'),
### I18N ################################################################## ### I18N ##################################################################
# {% spaceless %} tag # {% spaceless %} tag

View File

@ -0,0 +1,47 @@
"Unit tests for reverse URL lookup"
from django.core.urlresolvers import reverse_helper, NoReverseMatch
import re
test_data = (
('^places/(\d+)/$', 'places/3/', [3], {}),
('^places/(\d+)/$', 'places/3/', ['3'], {}),
('^places/(\d+)/$', NoReverseMatch, ['a'], {}),
('^places/(\d+)/$', NoReverseMatch, [], {}),
('^places/(?P<id>\d+)/$', 'places/3/', [], {'id': 3}),
('^people/(?P<name>\w+)/$', 'people/adrian/', ['adrian'], {}),
('^people/(?P<name>\w+)/$', 'people/adrian/', [], {'name': 'adrian'}),
('^people/(?P<name>\w+)/$', NoReverseMatch, ['name with spaces'], {}),
('^people/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'name with spaces'}),
('^people/(?P<name>\w+)/$', NoReverseMatch, [], {}),
('^hardcoded/$', 'hardcoded/', [], {}),
('^hardcoded/$', 'hardcoded/', ['any arg'], {}),
('^hardcoded/$', 'hardcoded/', [], {'kwarg': 'foo'}),
('^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'people/il/adrian/', [], {'state': 'il', 'name': 'adrian'}),
('^people/(?P<state>\w\w)/(?P<name>\d)/$', NoReverseMatch, [], {'state': 'il', 'name': 'adrian'}),
('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'state': 'il'}),
('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'adrian'}),
('^people/(?P<state>\w\w)/(\w+)/$', NoReverseMatch, ['il'], {'name': 'adrian'}),
('^people/(?P<state>\w\w)/(\w+)/$', 'people/il/adrian/', ['adrian'], {'state': 'il'}),
)
def run_tests(verbosity=0):
for regex, expected, args, kwargs in test_data:
passed = True
try:
got = reverse_helper(re.compile(regex), *args, **kwargs)
except NoReverseMatch, e:
if expected != NoReverseMatch:
passed, got = False, str(e)
else:
if got != expected:
passed, got = False, got
if passed and verbosity:
print "Passed: %s" % regex
elif not passed:
print "REVERSE LOOKUP FAILED: %s" % regex
print " Got: %s" % got
print " Expected: %r" % expected
if __name__ == "__main__":
run_tests(1)