1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +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
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
internationalization support, manages i18n contributions and has made a ton
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
admin application to allow for easier reuse and has made a ton of excellent
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/>
ChaosKCW
Ian Clelland <clelland@gmail.com>
crankycoder@gmail.com
Matt Croydon <http://www.postneo.com/>
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
Jason Davies (Esaj) <http://www.jasondavies.com/>
@ -59,6 +71,8 @@ answer newbie questions, and generally made Django that much better:
Clint Ecker
gandalf@owca.info
Baishampayan Ghose
martin.glueck@gmail.com
Simon Greenhill <dev@simon.net.nz>
Espen Grindhaug <http://grindhaug.org/>
Brant Harris
hipertracker@gmail.com
@ -70,7 +84,6 @@ answer newbie questions, and generally made Django that much better:
Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com
junzhang.jn@gmail.com
Russell Keith-Magee <freakboy@iinet.net.au>
Garth Kidd <http://www.deadlybloodyserious.com/>
kilian <kilian.cavalotti@lip6.fr>
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/>
Neal Norwitz <nnorwitz@google.com>
oggie rob <oz.robharvey@gmail.com>
Jay Parlar <parlar@gmail.com>
pgross@thoughtworks.com
phaedo <http://phaedo.cx/>
phil@produxion.net
@ -112,13 +126,14 @@ answer newbie questions, and generally made Django that much better:
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
David Schein
sopel
Thomas Steinacher <tom@eggdrop.ch>
Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/>
Tom Tobin
Tom Insam
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
Malcolm Tredinnick
Karen Tracey <graybark@bellsouth.net>
Amit Upadhyay
Geert Vanderkelen
Milton Waddams

19
INSTALL
View File

@ -1,7 +1,22 @@
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.

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"
sys.exit(1)
for (dirpath, dirnames, filenames) in os.walk(basedir):
for dirpath, dirnames, filenames in os.walk(basedir):
for f in filenames:
if f.endswith('.po'):
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_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_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_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.

View File

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

View File

@ -10,8 +10,10 @@ include = lambda urlconf_module: [urlconf_module]
def patterns(prefix, *tuples):
pattern_list = []
for t in tuples:
if type(t[1]) == list:
pattern_list.append(RegexURLResolver(t[0], t[1][0]))
regex, view_or_include = t[:2]
default_kwargs = t[2:]
if type(view_or_include) == list:
pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs))
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

View File

@ -8,7 +8,9 @@ var DateTimeShortcuts = {
clockInputs: [],
calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled
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
clockLinkName: 'clocklink', // name of the link that is used to toggle
admin_media_prefix: '',
init: function() {
// 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')));
var clock_link = document.createElement('a');
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'));
shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(now_link);
@ -69,17 +72,6 @@ var DateTimeShortcuts = {
var clock_box = document.createElement('div');
clock_box.style.display = 'none';
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.setAttribute('id', DateTimeShortcuts.clockDivName + num);
document.body.appendChild(clock_box);
@ -98,7 +90,25 @@ var DateTimeShortcuts = {
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + 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; });
},
dismissClock: function(num) {
@ -123,6 +133,7 @@ var DateTimeShortcuts = {
today_link.appendChild(document.createTextNode(gettext('Today')));
var cal_link = document.createElement('a');
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'));
shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(today_link);
@ -149,18 +160,6 @@ var DateTimeShortcuts = {
var cal_box = document.createElement('div');
cal_box.style.display = 'none';
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.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
document.body.appendChild(cal_box);
@ -195,7 +194,24 @@ var DateTimeShortcuts = {
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + 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; });
},
dismissCalendar: function(num) {

View File

@ -11,7 +11,7 @@ function showRelatedObjectLookupPopup(triggeringLink) {
} else {
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();
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%}
</ul>
{% 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>
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% 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>
{% endif %}
{% endfor %}
</tr></thead>
{% for fcw in bound_related_object.form_field_collection_wrappers %}
{% if change %}{% if original_row_needed %}
{% 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():
title, body, metadata = utils.parse_docstring(tag_func.__doc__)
if title:
title = utils.parse_rst(title, 'tag', 'tag:' + tag_name)
title = utils.parse_rst(title, 'tag', _('tag:') + tag_name)
if body:
body = utils.parse_rst(body, 'tag', 'tag:' + tag_name)
body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
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:
tag_library = None
else:
@ -74,11 +74,11 @@ def template_filter_index(request):
for filter_name, filter_func in library.filters.items():
title, body, metadata = utils.parse_docstring(filter_func.__doc__)
if title:
title = utils.parse_rst(title, 'filter', 'filter:' + filter_name)
title = utils.parse_rst(title, 'filter', _('filter:') + filter_name)
if body:
body = utils.parse_rst(body, 'filter', 'filter:' + filter_name)
body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
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:
tag_library = None
else:
@ -132,11 +132,11 @@ def view_detail(request, view):
raise Http404
title, body, metadata = utils.parse_docstring(view_func.__doc__)
if title:
title = utils.parse_rst(title, 'view', 'view:' + view)
title = utils.parse_rst(title, 'view', _('view:') + view)
if body:
body = utils.parse_rst(body, 'view', 'view:' + view)
body = utils.parse_rst(body, 'view', _('view:') + view)
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', {
'name': view,
'summary': title,
@ -161,14 +161,14 @@ def model_detail(request, app_label, model_name):
try:
app_mod = models.get_app(app_label)
except ImproperlyConfigured:
raise Http404, "App %r not found" % app_label
raise Http404, _("App %r not found") % app_label
model = None
for m in models.get_models(app_mod):
if m._meta.object_name.lower() == model_name:
model = m
break
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
@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name):
if isinstance(field, models.ForeignKey):
data_type = related_object_name = field.rel.to.__name__
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:
data_type = get_readable_field_data_type(field)
verbose = field.verbose_name
@ -202,7 +202,7 @@ def model_detail(request, app_label, model_name):
continue
verbose = func.__doc__
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({
'name': 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
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()
fields.append({
'name' : "%s.all" % accessor,
'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({
'name' : "%s.count" % accessor,
'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', {
@ -336,7 +336,7 @@ def extract_views_from_urlpatterns(urlpatterns, base=''):
elif hasattr(p, '_get_url_patterns'):
views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern))
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
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"
return HttpResponseRedirect(post_url_continue % pk_value)
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('"', '\\"')))
elif request.POST.has_key("_addanother"):
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())))
_checklogin.__doc__ = view_func.__doc__
_checklogin.__dict__ = view_func.__dict__
_checklogin.__name__ = view_func.__name__
return _checklogin
return _dec

View File

@ -5,6 +5,28 @@ from django.template import Context, loader
from django.core import validators
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):
"""
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:
* 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
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,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
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

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"))
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 = []
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 = {}
app_models = models.get_models(app)
for model in app_models:
output, references = _get_sql_model_create(model, known_models)
@ -118,10 +121,13 @@ def get_sql_create(app):
# but don't exist physically
not_installed_models = set(pending_references.keys())
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:
final_output.extend(['-- ' + sql for sql in
alter_sql.extend(['-- ' + sql for sql in
_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
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
final_output = []
reference_names = {}
if backend.supports_constraints:
opts = model._meta
if model in pending_references:
@ -202,12 +207,9 @@ def _get_sql_for_pending_references(model, pending_references):
r_col = f.column
table = opts.db_table
col = opts.get_field(f.rel.field_name).column
r_name = '%s_referencing_%s_%s' % (r_col, table, col)
if r_name in reference_names:
reference_names[r_name] += 1
r_name += '_%s' % reference_names[r_name]
else:
reference_names[r_name] = 0
# For MySQL, r_name must be unique in the first 64 characters.
# So we are careful with character usage here.
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
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_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_TABLE(backend.quote_name(table)),
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]
# Output DROP TABLE statements for many-to-many tables.
@ -696,9 +698,7 @@ def inspectdb():
introspection_module = get_introspection_module()
def table2model(table_name):
object_name = table_name.title().replace('_', '')
return object_name.endswith('s') and object_name[:-1] or object_name
table2model = lambda table_name: table_name.title().replace('_', '')
cursor = connection.cursor()
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.
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):
extra_params['db_column'] = att_name
att_name += '_field'
@ -957,6 +961,12 @@ def get_validation_errors(outfile, app=None):
f = opts.get_field(fn)
except models.FieldDoesNotExist:
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.
if opts.ordering:
@ -1132,7 +1142,14 @@ def dbshell():
dbshell.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
runfastcgi(args)
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:
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
# way. For example, if this file (manage.py) lives in a directory
# "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.
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()
# 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"
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)
elif isinstance(o, datetime.time):
return o.strftime(self.TIME_FORMAT)
elif isinstance(o, datetime.datetime):
return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
else:
return super(self, DateTimeAwareJSONEncoder).default(o)

View File

@ -547,10 +547,6 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
env['PATH_INFO'] = urllib.unquote(path)
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]
if self.headers.typeheader is None:

View File

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

View File

@ -16,6 +16,18 @@ from django.utils.text import capfirst
# Admin stages.
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):
"""
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
def __get_value__(self):
return datetime.datetime.now() + self.delta
return (datetime.datetime.now() + self.delta).date()
def __getattr__(self, 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]
# 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:
return m
@ -73,7 +73,7 @@ class ModelBase(type):
# 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
# registered version.
return get_model(new_class._meta.app_label, name)
return get_model(new_class._meta.app_label, name, False)
class Model(object):
__metaclass__ = ModelBase
@ -181,11 +181,12 @@ class Model(object):
# If it does already exist, do an UPDATE.
if cursor.fetchone():
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" % \
(backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.column)),
db_values + [pk_val])
if db_values:
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.column)),
db_values + [pk_val])
else:
record_exists = False
if not pk_set or not record_exists:

View File

@ -20,7 +20,7 @@ BLANK_CHOICE_DASH = [("", "---------")]
BLANK_CHOICE_NONE = [("", "None")]
# 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
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
# BooleanFields (CheckboxFields) are a special case. They don't take
# is_required or validator_list.
# is_required.
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
# in the related object have core=True. If so, add a validator --
@ -289,8 +289,11 @@ class Field(object):
if self.choices:
return first_choice + list(self.choices)
rel_model = self.rel.to
return first_choice + [(x._get_pk_val(), str(x))
for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
if hasattr(self.rel, 'get_related_field'):
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):
if self.radio_admin:

View File

@ -25,7 +25,7 @@ def add_lookup(rel_cls, field):
key = (module, name)
# Has the model already been loaded?
# 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:
field.rel.to = model
field.do_related_class(model, rel_cls)

View File

@ -32,7 +32,7 @@ def get_apps():
_app_errors[app_name] = e
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."
get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
for app_name in settings.INSTALLED_APPS:
@ -75,11 +75,15 @@ def get_models(app_mod=None):
model_list.extend(get_models(app_mod))
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.
"""
if seed_cache:
get_apps()
try:
model_dict = _app_models[app_label]
except KeyError:

View File

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

View File

@ -434,10 +434,12 @@ class HiddenField(FormField):
(self.get_id(), self.field_name, escape(data))
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.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):
checked_html = ''

View File

@ -38,7 +38,7 @@ class HttpRequest(object):
def get_full_path(self):
return ''
def is_secure(self):
return os.environ.get("HTTPS") == "on"
@ -203,11 +203,14 @@ class HttpResponse(object):
if val is not None:
self.cookies[key][var.replace('_', '-')] = val
def delete_cookie(self, key):
try:
self.cookies[key]['max_age'] = 0
except KeyError:
pass
def delete_cookie(self, key, path='/', domain=None):
self.cookies[key] = ''
if path is not None:
self.cookies[key]['path'] = path
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):
content = ''.join(self._iterator)

View File

@ -12,7 +12,11 @@ class GZipMiddleware(object):
"""
def process_response(self, request, response):
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
ae = request.META.get('HTTP_ACCEPT_ENCODING', '')

View File

@ -339,7 +339,7 @@ def date(value, arg=None):
def time(value, arg=None):
"Formats a time according to the given format"
from django.utils.dateformat import time_format
if not value:
if value in (None, ''):
return ''
if arg is None:
arg = settings.TIME_FORMAT
@ -437,7 +437,7 @@ def pluralize(value, arg='s'):
is used instead. If the provided argument contains a comma, the text before
the comma is used for the singular case.
"""
if not ',' in arg:
if not ',' in arg:
arg = ',' + arg
bits = arg.split(',')
if len(bits) > 2:

View File

@ -50,6 +50,8 @@ class ExtendsNode(Node):
if self.parent_name_expr:
error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr.
raise TemplateSyntaxError, error_msg
if hasattr(parent, 'render'):
return parent
try:
source, origin = find_template_source(parent, self.template_dirs)
except TemplateDoesNotExist:
@ -137,8 +139,9 @@ def do_extends(parser, token):
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,
or ``{% extends variable %}`` uses the value of ``variable`` as the name
of the parent template to extend.
or ``{% extends variable %}`` uses the value of ``variable`` as either the
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()
if len(bits) != 2:

View File

@ -17,7 +17,7 @@ def load_template_source(template_name, template_dirs=None):
return (open(filepath).read(), filepath)
except IOError:
tried.append(filepath)
if template_dirs:
if tried:
error_msg = "Tried %s" % tried
else:
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:
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
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.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.utils.translation import gettext
def create_object(request, model, template_name=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)
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,
# 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)
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.
if post_save_redirect:
@ -180,7 +181,7 @@ def delete_object(request, model, post_delete_redirect,
if request.method == 'POST':
object.delete()
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)
else:
if not template_name:

View File

@ -2,12 +2,15 @@
The "contrib" add-ons
=====================
Django aims to follow Python's "batteries included" philosophy. It ships with a
variety of extra, optional tools that solve common Web-development problems.
Django aims to follow Python's `"batteries included" philosophy`_. It ships
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
rundown of the packages in ``contrib``:
.. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included
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
change before the 1.0 release.
What "stable" means
===================
In this context, stable means:
- 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
security hole makes it completely unavoidable.
Stable APIs
===========
These APIs are stable:
- `Caching`_.
@ -114,4 +120,4 @@ change:
.. _url dispatch: http://www.djangoproject.com/documentation/url_dispatch/
.. _forms and validation: http://www.djangoproject.com/documentation/forms/
.. _serialization: http://www.djangoproject.com/documentation/serialization/
.. _authentication: http://www.djangoproject.com/documentation/authentication/
.. _authentication: http://www.djangoproject.com/documentation/authentication/

View File

@ -578,6 +578,9 @@ related ``Person`` *and* the related ``City``::
p = b.author # 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)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -715,12 +718,12 @@ The ``DoesNotExist`` exception inherits from
A convenience method for creating an object and saving it all in one step. Thus::
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and::
p = Person(first_name="Bruce", last_name="Springsteen")
p.save()
are equivalent.
``get_or_create(**kwargs)``
@ -1468,11 +1471,12 @@ the ``ForeignKey`` ``Manager`` has these additional methods:
b.entry_set.remove(e) # Disassociates Entry e from Blog b.
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
``None`` (``NULL``), then an object can't be removed from a relation
without being added to another. In the above example, removing ``e`` from
``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because
the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid.
``ForeignKey`` objects where ``null=True``. If the related field can't be
set to ``None`` (``NULL``), then an object can't be removed from a
relation without being added to another. In the above example, removing
``e`` from ``b.entry_set()`` is equivalent to doing ``e.blog = None``,
and because the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this
is invalid.
* ``clear()``: Removes all objects from the related object set.
@ -1556,13 +1560,13 @@ Queries over related objects
----------------------------
Queries involving related objects follow the same rules as queries involving
normal value fields. When specifying the the value for a query to match, you
may use either an object instance itself, or the primary key value for the
normal value fields. When specifying the the value for a query to match, you
may use either an object instance itself, or the primary key value for the
object.
For example, if you have a Blog object ``b`` with ``id=5``, the following
three queries would be identical::
Entry.objects.filter(blog=b) # Query using object instance
Entry.objects.filter(blog=b.id) # Query using id from instance
Entry.objects.filter(blog=5) # Query using id directly

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
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
======================
@ -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?
-------------------------------------------------------------
We don't recommend you create users via the admin interface, because at the
moment it requires you to edit password hashes manually. (Passwords are hashed
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.)
If you'd like to use the admin site to create users, upgrade to the Django
development version, where this problem was fixed on Aug. 4, 2006.
To create a user, you'll have to use the Python API. See `creating users`_ for
full info.
You can also use the Python API. See `creating users`_ for full info.
.. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users

View File

@ -404,6 +404,43 @@ Here's a simple function that might drive the above form::
errors = new_data = {}
form = forms.FormWrapper(manipulator, new_data, errors)
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
==========

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>/``::
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/``::

View File

@ -77,9 +77,9 @@ It's easy either way.
Installing the official version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Download Django-0.91.tar.gz from our `download page`_.
2. ``tar xzvf Django-0.91.tar.gz``
3. ``cd Django-0.91``
1. Download Django-0.95.tar.gz from our `download page`_.
2. ``tar xzvf Django-0.95.tar.gz``
3. ``cd Django-0.95``
4. ``sudo python setup.py install``
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``
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
Installing the development version

View File

@ -223,6 +223,13 @@ steps:
the absolute URL to your image in a template with ``{{
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
``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

@ -149,7 +149,7 @@ Methods
Returns the ``path``, plus an appended query string, if applicable.
Example: ``"/music/bands/the_beatles/?print=true"``
``is_secure()``
Returns ``True`` if the request is secure; that is, if it was made with
HTTPS.
@ -380,10 +380,14 @@ Methods
.. _`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
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``
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``

View File

@ -245,6 +245,17 @@ Default: ``'sessionid'``
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
-------------------------------

View File

@ -647,6 +647,18 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
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
-------------------------------

View File

@ -363,10 +363,15 @@ extends
Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base.html" %}`` (with quotes)
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
name of the parent template to extend.
This tag can be used in two ways:
* ``{% extends "base.html" %}`` (with quotes) uses the literal value
``"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.
@ -493,6 +498,11 @@ If you need to combine ``and`` and ``or`` to do advanced logic, just use nested
{% 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
~~~~~~~~~

View File

@ -198,21 +198,6 @@ some things to keep in mind:
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
``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty
string) by default.

View File

@ -81,7 +81,7 @@ the following output on the command line::
Validating models...
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/
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 *
urlpatterns = patterns('',
(r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'),
(r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'),
(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
first argument to the ``patterns()`` function to specify a prefix to apply to
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 *
urlpatterns = patterns('myproject.news.views',
urlpatterns = patterns('mysite.news.views',
(r'^articles/(\d{4})/$', 'year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
(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/
.. _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.*']),
package_data = {
'': ['*.TXT'],
'django.conf': ['locale/ar/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.conf': ['locale/*/LC_MESSAGES/*'],
'django.contrib.admin': ['templates/admin/*.html',
'templates/admin/auth/user/*.html',
'templates/admin_doc/*.html',
'templates/registration/*.html',
'templates/widget/*.html',

View File

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

View File

@ -15,7 +15,7 @@ class Article(models.Model):
def __str__(self):
return self.headline
API_TESTS = """
API_TESTS = r"""
# Create a couple of Articles.
>>> from datetime import datetime
>>> 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>
# 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.save()
>>> 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.objects.filter(headline__startswith='Article_')
[<Article: Article_ with underscore>]
>>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
>>> a9.save()
>>> 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.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>]
# 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")
'01'
>>> time(datetime.time(0), "h")
'12'
# real testing is done in timesince.py, where we can provide our own 'now'
>>> timesince(datetime.datetime.now() - datetime.timedelta(1))
'1 day'

View File

@ -410,6 +410,12 @@ TEMPLATE_TESTS = {
# Three-level inheritance with {{ block.super }} from parent and grandparent
'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 ##################################################################
# {% 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)