1
0
mirror of https://github.com/django/django.git synced 2025-07-03 17:29:12 +00:00

multi-auth: Merged to [3151]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multi-auth@3152 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2006-06-19 15:23:57 +00:00
parent e976ed1f79
commit adf4b9311d
101 changed files with 3639 additions and 2565 deletions

View File

@ -71,6 +71,7 @@ answer newbie questions, and generally made Django that much better:
Russell Keith-Magee <freakboy@iinet.net.au> Russell Keith-Magee <freakboy@iinet.net.au>
Garth Kidd <http://www.deadlybloodyserious.com/> Garth Kidd <http://www.deadlybloodyserious.com/>
Sune Kirkeby <http://ibofobi.dk/> Sune Kirkeby <http://ibofobi.dk/>
Cameron Knight (ckknight)
Bruce Kroeze <http://coderseye.com/> Bruce Kroeze <http://coderseye.com/>
Joseph Kocherhans Joseph Kocherhans
lakin.wecker@gmail.com lakin.wecker@gmail.com

View File

@ -12,7 +12,7 @@ from django.conf import global_settings
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings: class LazySettings(object):
""" """
A lazy proxy for either global Django settings or a custom settings object. A lazy proxy for either global Django settings or a custom settings object.
The user can manually configure settings prior to using them. Otherwise, The user can manually configure settings prior to using them. Otherwise,
@ -67,7 +67,7 @@ class LazySettings:
setattr(holder, name, value) setattr(holder, name, value)
self._target = holder self._target = holder
class Settings: class Settings(object):
def __init__(self, settings_module): def __init__(self, settings_module):
# update this dict from global settings (but only for ALL_CAPS settings) # update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings): for setting in dir(global_settings):
@ -112,7 +112,7 @@ class Settings:
def get_all_members(self): def get_all_members(self):
return dir(self) return dir(self)
class UserSettingsHolder: class UserSettingsHolder(object):
""" """
Holder for user configured settings. Holder for user configured settings.
""" """

View File

@ -12,7 +12,7 @@ msgstr ""
"Last-Translator: Gaël Chardon <gael.dev_at_nospam_4now.net>\n" "Last-Translator: Gaël Chardon <gael.dev_at_nospam_4now.net>\n"
"Language-Team: français <fr@li.org>\n" "Language-Team: français <fr@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: contrib/comments/models.py:67 contrib/comments/models.py:166 #: contrib/comments/models.py:67 contrib/comments/models.py:166
@ -2010,4 +2010,4 @@ msgstr "oui,non,peut-être"
#~ msgstr "paquetages" #~ msgstr "paquetages"
#~ msgid "Messages" #~ msgid "Messages"
#~ msgstr "Messages" #~ msgstr "Messages"

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
# Copyright (C) 2006 THE djangojs'S COPYRIGHT HOLDER # Copyright (C) 2006 THE djangojs'S COPYRIGHT HOLDER
# This file is distributed under the same license as the djangojs package. # This file is distributed under the same license as the djangojs package.
# Meir Kriheli <meir@mksoft.co.il>, 2006. # Meir Kriheli <meir@mksoft.co.il>, 2006.
# , fuzzy
# #
# #
msgid "" msgid ""
@ -53,7 +52,7 @@ msgstr "%s נבחרות"
#: contrib/admin/media/js/SelectFilter2.js:54 #: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click " msgid "Select your choice(s) and click "
msgstr "יש לסמן את ההרשאות המבוקשות וללחוץ על" msgstr "יש לסמן את ההרשאות המבוקשות וללחוץ על "
#: contrib/admin/media/js/SelectFilter2.js:59 #: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all" msgid "Clear all"

View File

@ -11,7 +11,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-05-16 10:13+0200\n" "POT-Creation-Date: 2006-05-16 10:13+0200\n"
"PO-Revision-Date: 2006-02-21 11:10+0100\n" "PO-Revision-Date: 2006-02-21 11:10+0100\n"
"Last-Translator: GNOME PL Team <translators@gnome.pl>\n" "Last-Translator: Piotr Maliński <admin@rk.edu.pl>\n"
"Language-Team: Polish <pl@li.org>\n" "Language-Team: Polish <pl@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -19,7 +19,7 @@ msgstr ""
#: contrib/comments/models.py:67 contrib/comments/models.py:166 #: contrib/comments/models.py:67 contrib/comments/models.py:166
msgid "object ID" msgid "object ID"
msgstr "" msgstr "ID obiektu"
#: contrib/comments/models.py:68 #: contrib/comments/models.py:68
msgid "headline" msgid "headline"
@ -32,43 +32,43 @@ msgstr "komentarz"
#: contrib/comments/models.py:70 #: contrib/comments/models.py:70
msgid "rating #1" msgid "rating #1"
msgstr "" msgstr "ocena #1"
#: contrib/comments/models.py:71 #: contrib/comments/models.py:71
msgid "rating #2" msgid "rating #2"
msgstr "" msgstr "ocena #2"
#: contrib/comments/models.py:72 #: contrib/comments/models.py:72
msgid "rating #3" msgid "rating #3"
msgstr "" msgstr "ocena #3"
#: contrib/comments/models.py:73 #: contrib/comments/models.py:73
msgid "rating #4" msgid "rating #4"
msgstr "" msgstr "ocena #4"
#: contrib/comments/models.py:74 #: contrib/comments/models.py:74
msgid "rating #5" msgid "rating #5"
msgstr "" msgstr "ocena #5"
#: contrib/comments/models.py:75 #: contrib/comments/models.py:75
msgid "rating #6" msgid "rating #6"
msgstr "" msgstr "ocena #6"
#: contrib/comments/models.py:76 #: contrib/comments/models.py:76
msgid "rating #7" msgid "rating #7"
msgstr "" msgstr "ocena #7"
#: contrib/comments/models.py:77 #: contrib/comments/models.py:77
msgid "rating #8" msgid "rating #8"
msgstr "" msgstr "ocena #8"
#: contrib/comments/models.py:82 #: contrib/comments/models.py:82
msgid "is valid rating" msgid "is valid rating"
msgstr "" msgstr "jest poprawną oceną"
#: contrib/comments/models.py:83 contrib/comments/models.py:169 #: contrib/comments/models.py:83 contrib/comments/models.py:169
msgid "date/time submitted" msgid "date/time submitted"
msgstr "" msgstr "data/czas dodania"
#: contrib/comments/models.py:84 contrib/comments/models.py:170 #: contrib/comments/models.py:84 contrib/comments/models.py:170
msgid "is public" msgid "is public"
@ -87,15 +87,16 @@ msgid ""
"Check this box if the comment is inappropriate. A \"This comment has been " "Check this box if the comment is inappropriate. A \"This comment has been "
"removed\" message will be displayed instead." "removed\" message will be displayed instead."
msgstr "" msgstr ""
"Zaznacz to pole jeżeli komentarz jest nieodpowiedni. Wyświetlony zostanie tekst \"Ten "
"komentarz został usunięty\". "
#: contrib/comments/models.py:91 #: contrib/comments/models.py:91
#, fuzzy
msgid "comments" msgid "comments"
msgstr "komentarz" msgstr "komentarze"
#: contrib/comments/models.py:131 contrib/comments/models.py:207 #: contrib/comments/models.py:131 contrib/comments/models.py:207
msgid "Content object" msgid "Content object"
msgstr "" msgstr "Obiekt Treści"
#: contrib/comments/models.py:159 #: contrib/comments/models.py:159
#, python-format #, python-format
@ -106,6 +107,11 @@ msgid ""
"\n" "\n"
"http://%(domain)s%(url)s" "http://%(domain)s%(url)s"
msgstr "" msgstr ""
"Dodane przez %(user)s dnia %(date)s\n"
"\n"
"%(comment)y\n"
"\n"
"http://%(domain)s%(url)s"
#: contrib/comments/models.py:168 #: contrib/comments/models.py:168
msgid "person's name" msgid "person's name"
@ -122,12 +128,12 @@ msgstr "zaakceptowano"
#: contrib/comments/models.py:176 #: contrib/comments/models.py:176
#, fuzzy #, fuzzy
msgid "free comment" msgid "free comment"
msgstr "Wolny komentarz" msgstr "wolny komentarz"
#: contrib/comments/models.py:177 #: contrib/comments/models.py:177
#, fuzzy #, fuzzy
msgid "free comments" msgid "free comments"
msgstr "Wolne komentarze" msgstr "wolne komentarze"
#: contrib/comments/models.py:233 #: contrib/comments/models.py:233
msgid "score" msgid "score"
@ -135,7 +141,7 @@ msgstr "ilość punktów"
#: contrib/comments/models.py:234 #: contrib/comments/models.py:234
msgid "score date" msgid "score date"
msgstr "" msgstr "data przyznania punktów"
#: contrib/comments/models.py:237 #: contrib/comments/models.py:237
#, fuzzy #, fuzzy
@ -144,12 +150,12 @@ msgstr "ilość punktów"
#: contrib/comments/models.py:238 #: contrib/comments/models.py:238
msgid "karma scores" msgid "karma scores"
msgstr "" msgstr "wyniki"
#: contrib/comments/models.py:242 #: contrib/comments/models.py:242
#, python-format #, python-format
msgid "%(score)d rating by %(user)s" msgid "%(score)d rating by %(user)s"
msgstr "" msgstr "%(score)d ocenę przez %(user)s"
#: contrib/comments/models.py:258 #: contrib/comments/models.py:258
#, python-format #, python-format
@ -158,57 +164,62 @@ msgid ""
"\n" "\n"
"%(text)s" "%(text)s"
msgstr "" msgstr ""
"Komentarz oflagowany przez %(user)s:\n"
"\n"
"%(text)s"
#: contrib/comments/models.py:265 #: contrib/comments/models.py:265
msgid "flag date" msgid "flag date"
msgstr "" msgstr "data flagi"
#: contrib/comments/models.py:268 #: contrib/comments/models.py:268
msgid "user flag" msgid "user flag"
msgstr "" msgstr "flaga użytkownika"
#: contrib/comments/models.py:269 #: contrib/comments/models.py:269
msgid "user flags" msgid "user flags"
msgstr "" msgstr "flagi użytkownika"
#: contrib/comments/models.py:273 #: contrib/comments/models.py:273
#, python-format #, python-format
msgid "Flag by %r" msgid "Flag by %r"
msgstr "" msgstr "Flaga %r"
#: contrib/comments/models.py:278 #: contrib/comments/models.py:278
msgid "deletion date" msgid "deletion date"
msgstr "" msgstr "data skasowania"
#: contrib/comments/models.py:280 #: contrib/comments/models.py:280
msgid "moderator deletion" msgid "moderator deletion"
msgstr "" msgstr "usunięcie moderatora"
#: contrib/comments/models.py:281 #: contrib/comments/models.py:281
msgid "moderator deletions" msgid "moderator deletions"
msgstr "" msgstr "usunięcia moderatorów"
#: contrib/comments/models.py:285 #: contrib/comments/models.py:285
#, python-format #, python-format
msgid "Moderator deletion by %r" msgid "Moderator deletion by %r"
msgstr "" msgstr "Usunięcie moderatora przez %r"
#: contrib/comments/views/karma.py:19 #: contrib/comments/views/karma.py:19
msgid "Anonymous users cannot vote" msgid "Anonymous users cannot vote"
msgstr "" msgstr "Anonimowi użytkownicy nie mogą głosować"
#: contrib/comments/views/karma.py:23 #: contrib/comments/views/karma.py:23
msgid "Invalid comment ID" msgid "Invalid comment ID"
msgstr "" msgstr "Błędny ID komentarza"
#: contrib/comments/views/karma.py:25 #: contrib/comments/views/karma.py:25
msgid "No voting for yourself" msgid "No voting for yourself"
msgstr "" msgstr "Nie można głosować na siebie"
#: contrib/comments/views/comments.py:28 #: contrib/comments/views/comments.py:28
msgid "" msgid ""
"This rating is required because you've entered at least one other rating." "This rating is required because you've entered at least one other rating."
msgstr "" msgstr ""
"Ta ocena jest wymagana gdyż podałeś przynajmniej jedną inną ocenę."
#: contrib/comments/views/comments.py:112 #: contrib/comments/views/comments.py:112
#, python-format #, python-format
@ -236,12 +247,12 @@ msgstr ""
#: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:189
#: contrib/comments/views/comments.py:280 #: contrib/comments/views/comments.py:280
msgid "Only POSTs are allowed" msgid "Only POSTs are allowed"
msgstr "" msgstr "Dozwolone tylko POSTy"
#: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:193
#: contrib/comments/views/comments.py:284 #: contrib/comments/views/comments.py:284
msgid "One or more of the required fields wasn't submitted" msgid "One or more of the required fields wasn't submitted"
msgstr "" msgstr "Jedno lub więcej wymaganych pól nie zostało wypełnionych"
#: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:197
#: contrib/comments/views/comments.py:286 #: contrib/comments/views/comments.py:286
@ -264,17 +275,16 @@ msgstr ""
#: contrib/comments/templates/comments/form.html:8 #: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/login.html:17 #: contrib/admin/templates/admin/login.html:17
msgid "Username:" msgid "Username:"
msgstr "Nazwa użytkownika" msgstr "Nazwa użytkownika:"
#: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:6
#: contrib/admin/templates/admin/login.html:20 #: contrib/admin/templates/admin/login.html:20
msgid "Password:" msgid "Password:"
msgstr "Hasło" msgstr "Hasło:"
#: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:6
#, fuzzy
msgid "Forgotten your password?" msgid "Forgotten your password?"
msgstr "Zmień hasło" msgstr "Zapomniałeś hasło?"
#: contrib/comments/templates/comments/form.html:8 #: contrib/comments/templates/comments/form.html:8
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
@ -385,7 +395,7 @@ msgstr "id obiektu"
#: contrib/admin/models.py:20 #: contrib/admin/models.py:20
msgid "object repr" msgid "object repr"
msgstr "" msgstr "reprezentacj obiektu"
#: contrib/admin/models.py:21 #: contrib/admin/models.py:21
msgid "action flag" msgid "action flag"
@ -426,12 +436,16 @@ msgid ""
"Please log in again, because your session has expired. Don't worry: Your " "Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved." "submission has been saved."
msgstr "" msgstr ""
"Zaloguj się ponownie. Twoja sesja wygasła lecz twoje zgłoszenie "
"zostało zapisane."
#: contrib/admin/views/decorators.py:68 #: contrib/admin/views/decorators.py:68
msgid "" msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable " "Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again." "cookies, reload this page, and try again."
msgstr "" msgstr ""
"Twoja przeglądarka nie chce akceptować ciasteczek. Zmień "
"jej ustawienia i spróbuj ponownie."
#: contrib/admin/views/decorators.py:82 #: contrib/admin/views/decorators.py:82
msgid "Usernames cannot contain the '@' character." msgid "Usernames cannot contain the '@' character."
@ -449,16 +463,16 @@ msgstr "Administracja stroną"
#: contrib/admin/views/main.py:260 #: contrib/admin/views/main.py:260
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully." msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "" msgstr "%(name)s \"%(obj)s\" dodany pomyślnie."
#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 #: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348
msgid "You may edit it again below." msgid "You may edit it again below."
msgstr "Możesz to ponownie edytować poniżej." msgstr "Możesz ponownie edytować wpis poniżej."
#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 #: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357
#, python-format #, python-format
msgid "You may add another %s below." msgid "You may add another %s below."
msgstr "Możesz dodać nowe %s poniżej." msgstr "Możesz dodać nowy wpis %s poniżej."
#: contrib/admin/views/main.py:290 #: contrib/admin/views/main.py:290
#, python-format #, python-format
@ -499,6 +513,8 @@ msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
msgid "" msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr "" msgstr ""
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
#: contrib/admin/views/main.py:392 #: contrib/admin/views/main.py:392
#, python-format #, python-format
@ -508,21 +524,21 @@ msgstr "Zmień %s"
#: contrib/admin/views/main.py:470 #: contrib/admin/views/main.py:470
#, python-format #, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "" msgstr "Jedno lub więcej %(fieldname)s w %(name)s: %(obj)s"
#: contrib/admin/views/main.py:475 #: contrib/admin/views/main.py:475
#, python-format #, python-format
msgid "One or more %(fieldname)s in %(name)s:" msgid "One or more %(fieldname)s in %(name)s:"
msgstr "" msgstr "Jedno lub więcej %(fieldname)s w %(name)s:"
#: contrib/admin/views/main.py:508 #: contrib/admin/views/main.py:508
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "" msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
#: contrib/admin/views/main.py:511 #: contrib/admin/views/main.py:511
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Czy na pewno?" msgstr "Jesteś pewien?"
#: contrib/admin/views/main.py:533 #: contrib/admin/views/main.py:533
#, python-format #, python-format
@ -552,7 +568,7 @@ msgstr "Wartość logiczna (True, False - prawda lub fałsz)"
#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 #: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296
#, python-format #, python-format
msgid "String (up to %(maxlength)s)" msgid "String (up to %(maxlength)s)"
msgstr "" msgstr "Łańcuch (do %(maxlength)s znaków)"
#: contrib/admin/views/doc.py:280 #: contrib/admin/views/doc.py:280
msgid "Comma-separated integers" msgid "Comma-separated integers"
@ -604,11 +620,11 @@ msgstr "URL"
#: contrib/admin/views/doc.py:301 #: contrib/admin/views/doc.py:301
msgid "U.S. state (two uppercase letters)" msgid "U.S. state (two uppercase letters)"
msgstr "" msgstr "Stan USA (dwie duże litery)"
#: contrib/admin/views/doc.py:302 #: contrib/admin/views/doc.py:302
msgid "XML text" msgid "XML text"
msgstr "Text XML" msgstr "Tekst XML"
#: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/object_history.html:3
#: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_list.html:5
@ -682,6 +698,8 @@ msgid ""
"This object doesn't have a change history. It probably wasn't added via this " "This object doesn't have a change history. It probably wasn't added via this "
"admin site." "admin site."
msgstr "" msgstr ""
"Ten obiekt nie ma historii zmian. Najprawdopodobniej wpis te nie "
"został dodany poprzez panel admina"
#: contrib/admin/templates/admin/base_site.html:4 #: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin" msgid "Django site admin"
@ -701,13 +719,15 @@ msgstr "Bład serwera (500)"
#: contrib/admin/templates/admin/500.html:9 #: contrib/admin/templates/admin/500.html:9
msgid "Server Error <em>(500)</em>" msgid "Server Error <em>(500)</em>"
msgstr "" msgstr "Błąd Serwera <em>(500)</em>"
#: contrib/admin/templates/admin/500.html:10 #: contrib/admin/templates/admin/500.html:10
msgid "" msgid ""
"There's been an error. It's been reported to the site administrators via e-" "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." "mail and should be fixed shortly. Thanks for your patience."
msgstr "" msgstr ""
"Wystąpił niespodziewany błąd. Raport został wysłany emailem "
"administratorowi strony."
#: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:4
#: contrib/admin/templates/admin/404.html:8 #: contrib/admin/templates/admin/404.html:8
@ -716,12 +736,12 @@ msgstr "Strona nie znaleziona"
#: contrib/admin/templates/admin/404.html:10 #: contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found." msgid "We're sorry, but the requested page could not be found."
msgstr "" msgstr "Niestety nie można znaleźć rządanej strony."
#: contrib/admin/templates/admin/index.html:17 #: contrib/admin/templates/admin/index.html:17
#, python-format #, python-format
msgid "Models available in the %(name)s application." msgid "Models available in the %(name)s application."
msgstr "" msgstr "Modele dostępne w aplikacji %(name)s."
#: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15 #: contrib/admin/templates/admin/change_form.html:15
@ -734,7 +754,7 @@ msgstr "Zmień"
#: contrib/admin/templates/admin/index.html:44 #: contrib/admin/templates/admin/index.html:44
msgid "You don't have permission to edit anything." msgid "You don't have permission to edit anything."
msgstr "" msgstr "Nie masz uprawnień by edytować cokolwiek"
#: contrib/admin/templates/admin/index.html:52 #: contrib/admin/templates/admin/index.html:52
msgid "Recent Actions" msgid "Recent Actions"
@ -746,7 +766,7 @@ msgstr "Moje akcje"
#: contrib/admin/templates/admin/index.html:57 #: contrib/admin/templates/admin/index.html:57
msgid "None available" msgid "None available"
msgstr "Nic nie dostępne" msgstr "Brak"
#: contrib/admin/templates/admin/change_list.html:11 #: contrib/admin/templates/admin/change_list.html:11
#, python-format #, python-format
@ -756,7 +776,7 @@ msgstr "Dodaj %(name)s"
#: contrib/admin/templates/admin/login.html:22 #: contrib/admin/templates/admin/login.html:22
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
msgstr "" msgstr ""
"Czy aby na pewno <a href=\"/password_reset/\">zapomniałeś/łaś</a> hasła?" "Czy <a href=\"/password_reset/\">zapomniałeś/łaś</a> hasła?"
#: contrib/admin/templates/admin/base.html:23 #: contrib/admin/templates/admin/base.html:23
msgid "Welcome," msgid "Welcome,"
@ -816,11 +836,11 @@ msgstr "Porządek:"
#: contrib/admin/templates/admin/submit_line.html:4 #: contrib/admin/templates/admin/submit_line.html:4
msgid "Save as new" msgid "Save as new"
msgstr "Zapisz" msgstr "Zapisz jako nowe"
#: contrib/admin/templates/admin/submit_line.html:5 #: contrib/admin/templates/admin/submit_line.html:5
msgid "Save and add another" msgid "Save and add another"
msgstr "Zapisz i dodaj" msgstr "Zapisz i dodaj nowe"
#: contrib/admin/templates/admin/submit_line.html:6 #: contrib/admin/templates/admin/submit_line.html:6
msgid "Save and continue editing" msgid "Save and continue editing"
@ -858,6 +878,8 @@ msgid ""
"Forgotten your password? Enter your e-mail address below, and we'll reset " "Forgotten your password? Enter your e-mail address below, and we'll reset "
"your password and e-mail the new one to you." "your password and e-mail the new one to you."
msgstr "" msgstr ""
"Podaj swój adres email. Hasło zostanie zresetowane i wysłane na twój "
"adres email."
#: contrib/admin/templates/registration/password_reset_form.html:16 #: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:" msgid "E-mail address:"
@ -869,7 +891,7 @@ msgstr "Zresetuj moje hasło"
#: contrib/admin/templates/registration/logged_out.html:8 #: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today." msgid "Thanks for spending some quality time with the Web site today."
msgstr "" msgstr "Dziękujemy za odwiedzenie serwisu."
#: contrib/admin/templates/registration/logged_out.html:10 #: contrib/admin/templates/registration/logged_out.html:10
msgid "Log in again" msgid "Log in again"
@ -878,19 +900,21 @@ msgstr "Zaloguj ponownie"
#: contrib/admin/templates/registration/password_reset_done.html:6 #: contrib/admin/templates/registration/password_reset_done.html:6
#: contrib/admin/templates/registration/password_reset_done.html:10 #: contrib/admin/templates/registration/password_reset_done.html:10
msgid "Password reset successful" msgid "Password reset successful"
msgstr "" msgstr "Udane resetowanie hasła"
#: contrib/admin/templates/registration/password_reset_done.html:12 #: contrib/admin/templates/registration/password_reset_done.html:12
msgid "" msgid ""
"We've e-mailed a new password to the e-mail address you submitted. You " "We've e-mailed a new password to the e-mail address you submitted. You "
"should be receiving it shortly." "should be receiving it shortly."
msgstr "" msgstr ""
"Nowe hasło zostało wysłane na podany adres email. Powinieneś "
"otrzymać je niebawem."
#: contrib/admin/templates/registration/password_change_form.html:12 #: contrib/admin/templates/registration/password_change_form.html:12
msgid "" msgid ""
"Please enter your old password, for security's sake, and then enter your new " "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." "password twice so we can verify you typed it in correctly."
msgstr "" msgstr "Podaj swoje stare hasło i dwa razy nowe."
#: contrib/admin/templates/registration/password_change_form.html:17 #: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:" msgid "Old password:"
@ -910,12 +934,12 @@ msgstr "Zmień hasło"
#: contrib/admin/templates/registration/password_reset_email.html:2 #: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset" msgid "You're receiving this e-mail because you requested a password reset"
msgstr "" msgstr "Otrzymałeś email gdyż zarządałeś zresetowania hasła"
#: contrib/admin/templates/registration/password_reset_email.html:3 #: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format #, python-format
msgid "for your user account at %(site_name)s" msgid "for your user account at %(site_name)s"
msgstr "" msgstr "dla twojego konta użytkownika na stronie %(site_name)s"
#: contrib/admin/templates/registration/password_reset_email.html:5 #: contrib/admin/templates/registration/password_reset_email.html:5
#, python-format #, python-format
@ -924,11 +948,11 @@ msgstr "Twoje nowe hasło to: %(new_password)s"
#: contrib/admin/templates/registration/password_reset_email.html:7 #: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:" msgid "Feel free to change this password by going to this page:"
msgstr "" msgstr "Możesz zmienić je na stronie:"
#: contrib/admin/templates/registration/password_reset_email.html:11 #: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:" msgid "Your username, in case you've forgotten:"
msgstr "" msgstr "Twój login:"
#: contrib/admin/templates/registration/password_reset_email.html:13 #: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!" msgid "Thanks for using our site!"
@ -960,7 +984,7 @@ msgstr ""
#: contrib/admin/templates/admin_doc/bookmarklets.html:19 #: contrib/admin/templates/admin_doc/bookmarklets.html:19
msgid "Documentation for this page" msgid "Documentation for this page"
msgstr "" msgstr "Dokumentacja dla tej strony"
#: contrib/admin/templates/admin_doc/bookmarklets.html:20 #: contrib/admin/templates/admin_doc/bookmarklets.html:20
msgid "" msgid ""
@ -970,37 +994,39 @@ msgstr ""
#: contrib/admin/templates/admin_doc/bookmarklets.html:22 #: contrib/admin/templates/admin_doc/bookmarklets.html:22
msgid "Show object ID" msgid "Show object ID"
msgstr "" msgstr "Pokaż ID obiektu"
#: contrib/admin/templates/admin_doc/bookmarklets.html:23 #: contrib/admin/templates/admin_doc/bookmarklets.html:23
msgid "" msgid ""
"Shows the content-type and unique ID for pages that represent a single " "Shows the content-type and unique ID for pages that represent a single "
"object." "object."
msgstr "" msgstr ""
"Pokazuje typ i unikalne ID dla stron, które reprezentują "
"pojedynczy obiekt."
#: contrib/admin/templates/admin_doc/bookmarklets.html:25 #: contrib/admin/templates/admin_doc/bookmarklets.html:25
msgid "Edit this object (current window)" msgid "Edit this object (current window)"
msgstr "" msgstr "Edytuj ten obiekt (bierzące okno)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:26 #: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object." msgid "Jumps to the admin page for pages that represent a single object."
msgstr "" msgstr "Przeskok do panelu admina dla stron reprezentujących pojedynczy obiekt"
#: contrib/admin/templates/admin_doc/bookmarklets.html:28 #: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)" msgid "Edit this object (new window)"
msgstr "" msgstr "Edytuj ten obiekt (nowe onko)"
#: contrib/admin/templates/admin_doc/bookmarklets.html:29 #: contrib/admin/templates/admin_doc/bookmarklets.html:29
msgid "As above, but opens the admin page in a new window." msgid "As above, but opens the admin page in a new window."
msgstr "" msgstr "Jak wyżej, tyle że otwiera nowe okno."
#: contrib/admin/templates/widget/date_time.html:3 #: contrib/admin/templates/widget/date_time.html:3
msgid "Date:" msgid "Date:"
msgstr "data" msgstr "Data:"
#: contrib/admin/templates/widget/date_time.html:4 #: contrib/admin/templates/widget/date_time.html:4
msgid "Time:" msgid "Time:"
msgstr "Czas" msgstr "Czas:"
#: contrib/admin/templates/widget/file.html:2 #: contrib/admin/templates/widget/file.html:2
msgid "Currently:" msgid "Currently:"
@ -1012,36 +1038,40 @@ msgstr "Zmień:"
#: contrib/redirects/models.py:7 #: contrib/redirects/models.py:7
msgid "redirect from" msgid "redirect from"
msgstr "" msgstr "przekieruj z"
#: contrib/redirects/models.py:8 #: contrib/redirects/models.py:8
msgid "" msgid ""
"This should be an absolute path, excluding the domain name. Example: '/" "This should be an absolute path, excluding the domain name. Example: '/"
"events/search/'." "events/search/'."
msgstr "" msgstr ""
"Podaj pełną ścieżkę bez nazwy domeny. Przykład: '/"
"events/search/'."
#: contrib/redirects/models.py:9 #: contrib/redirects/models.py:9
msgid "redirect to" msgid "redirect to"
msgstr "" msgstr "przekierowanie do"
#: contrib/redirects/models.py:10 #: contrib/redirects/models.py:10
msgid "" msgid ""
"This can be either an absolute path (as above) or a full URL starting with " "This can be either an absolute path (as above) or a full URL starting with "
"'http://'." "'http://'."
msgstr "" msgstr "Ścieżka jak wyżej lub pełny URL z http://"
#: contrib/redirects/models.py:12 #: contrib/redirects/models.py:12
msgid "redirect" msgid "redirect"
msgstr "" msgstr "przekieruj"
#: contrib/redirects/models.py:13 #: contrib/redirects/models.py:13
msgid "redirects" msgid "redirects"
msgstr "" msgstr "przekierowania"
#: contrib/flatpages/models.py:8 #: contrib/flatpages/models.py:8
msgid "" msgid ""
"Example: '/about/contact/'. Make sure to have leading and trailing slashes." "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
msgstr "" msgstr ""
"Przykład: '/about/contact/'. Upewnij się że wpisałeś otwierający i zamykający slash."
#: contrib/flatpages/models.py:9 #: contrib/flatpages/models.py:9
msgid "title" msgid "title"
@ -1053,11 +1083,11 @@ msgstr "zawartość"
#: contrib/flatpages/models.py:11 #: contrib/flatpages/models.py:11
msgid "enable comments" msgid "enable comments"
msgstr "" msgstr "włącz komentarze"
#: contrib/flatpages/models.py:12 #: contrib/flatpages/models.py:12
msgid "template name" msgid "template name"
msgstr "" msgstr "nazwa szablonu"
#: contrib/flatpages/models.py:13 #: contrib/flatpages/models.py:13
msgid "" msgid ""
@ -1067,11 +1097,11 @@ msgstr ""
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "registration required" msgid "registration required"
msgstr "" msgstr "wymagana rejestracja"
#: contrib/flatpages/models.py:14 #: contrib/flatpages/models.py:14
msgid "If this is checked, only logged-in users will be able to view the page." msgid "If this is checked, only logged-in users will be able to view the page."
msgstr "" msgstr "Jeżeli zaznaczone - tylko zalogowani użytkownicy będą mogli zobaczyć stronę."
#: contrib/flatpages/models.py:18 #: contrib/flatpages/models.py:18
msgid "flat page" msgid "flat page"
@ -1091,31 +1121,31 @@ msgstr ""
#: contrib/auth/models.py:17 #: contrib/auth/models.py:17
msgid "permission" msgid "permission"
msgstr "" msgstr "uprawnienie"
#: contrib/auth/models.py:18 contrib/auth/models.py:27 #: contrib/auth/models.py:18 contrib/auth/models.py:27
msgid "permissions" msgid "permissions"
msgstr "" msgstr "uprawnienia"
#: contrib/auth/models.py:29 #: contrib/auth/models.py:29
msgid "group" msgid "group"
msgstr "" msgstr "grupa"
#: contrib/auth/models.py:30 contrib/auth/models.py:65 #: contrib/auth/models.py:30 contrib/auth/models.py:65
msgid "groups" msgid "groups"
msgstr "" msgstr "grupy"
#: contrib/auth/models.py:55 #: contrib/auth/models.py:55
msgid "username" msgid "username"
msgstr "" msgstr "użytkownik"
#: contrib/auth/models.py:56 #: contrib/auth/models.py:56
msgid "first name" msgid "first name"
msgstr "" msgstr "Imię"
#: contrib/auth/models.py:57 #: contrib/auth/models.py:57
msgid "last name" msgid "last name"
msgstr "" msgstr "Nazwisko"
#: contrib/auth/models.py:58 #: contrib/auth/models.py:58
msgid "e-mail address" msgid "e-mail address"
@ -1127,15 +1157,15 @@ msgstr "hasło"
#: contrib/auth/models.py:59 #: contrib/auth/models.py:59
msgid "Use '[algo]$[salt]$[hexdigest]'" msgid "Use '[algo]$[salt]$[hexdigest]'"
msgstr "" msgstr "Użyj '[algo]$[salt]$[hexdigest]'"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "staff status" msgid "staff status"
msgstr "" msgstr "stan w zespole"
#: contrib/auth/models.py:60 #: contrib/auth/models.py:60
msgid "Designates whether the user can log into this admin site." msgid "Designates whether the user can log into this admin site."
msgstr "" msgstr "Oznaczy czy użytkownik może zalogować się do panelu admina."
#: contrib/auth/models.py:61 #: contrib/auth/models.py:61
msgid "active" msgid "active"
@ -1143,7 +1173,7 @@ msgstr "aktywny"
#: contrib/auth/models.py:62 #: contrib/auth/models.py:62
msgid "superuser status" msgid "superuser status"
msgstr "" msgstr "Główny Administrator"
#: contrib/auth/models.py:63 #: contrib/auth/models.py:63
msgid "last login" msgid "last login"
@ -1158,10 +1188,12 @@ msgid ""
"In addition to the permissions manually assigned, this user will also get " "In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in." "all permissions granted to each group he/she is in."
msgstr "" msgstr ""
"Oprócz uprawnień przypisanych bezpośrednio użytkownikowi otrzyma on "
"uprawnienia grup, do których należy."
#: contrib/auth/models.py:67 #: contrib/auth/models.py:67
msgid "user permissions" msgid "user permissions"
msgstr "" msgstr "uprawnienia użytkownika"
#: contrib/auth/models.py:70 #: contrib/auth/models.py:70
#, fuzzy #, fuzzy
@ -1175,62 +1207,64 @@ msgstr "Uzytkownicy"
#: contrib/auth/models.py:76 #: contrib/auth/models.py:76
msgid "Personal info" msgid "Personal info"
msgstr "" msgstr "Dane osobowe"
#: contrib/auth/models.py:77 #: contrib/auth/models.py:77
msgid "Permissions" msgid "Permissions"
msgstr "" msgstr "Uprawnienia"
#: contrib/auth/models.py:78 #: contrib/auth/models.py:78
msgid "Important dates" msgid "Important dates"
msgstr "" msgstr "Ważne daty"
#: contrib/auth/models.py:79 #: contrib/auth/models.py:79
msgid "Groups" msgid "Groups"
msgstr "" msgstr "Grupy"
#: contrib/auth/models.py:219 #: contrib/auth/models.py:219
#, fuzzy #, fuzzy
msgid "message" msgid "message"
msgstr "Wiadomość" msgstr "wiadomość"
#: contrib/auth/forms.py:30 #: contrib/auth/forms.py:30
msgid "" msgid ""
"Your Web browser doesn't appear to have cookies enabled. Cookies are " "Your Web browser doesn't appear to have cookies enabled. Cookies are "
"required for logging in." "required for logging in."
msgstr "" msgstr ""
"Twoja przeglądarka nie chce akceptować ciasteczek. Są one "
"wymagane do zalogowania się."
#: contrib/contenttypes/models.py:25 #: contrib/contenttypes/models.py:25
msgid "python model class name" msgid "python model class name"
msgstr "" msgstr "nazwa pythonowa modelu klasy"
#: contrib/contenttypes/models.py:28 #: contrib/contenttypes/models.py:28
msgid "content type" msgid "content type"
msgstr "" msgstr "typ zawartości"
#: contrib/contenttypes/models.py:29 #: contrib/contenttypes/models.py:29
msgid "content types" msgid "content types"
msgstr "" msgstr "typy zawartości"
#: contrib/sessions/models.py:35 #: contrib/sessions/models.py:35
msgid "session key" msgid "session key"
msgstr "" msgstr "klucz sesji"
#: contrib/sessions/models.py:36 #: contrib/sessions/models.py:36
msgid "session data" msgid "session data"
msgstr "" msgstr "data sesji"
#: contrib/sessions/models.py:37 #: contrib/sessions/models.py:37
msgid "expire date" msgid "expire date"
msgstr "" msgstr "data wygaśnięcia sesji"
#: contrib/sessions/models.py:41 #: contrib/sessions/models.py:41
msgid "session" msgid "session"
msgstr "" msgstr "sesja"
#: contrib/sessions/models.py:42 #: contrib/sessions/models.py:42
msgid "sessions" msgid "sessions"
msgstr "" msgstr "sesje"
#: contrib/sites/models.py:10 #: contrib/sites/models.py:10
msgid "domain name" msgid "domain name"
@ -1250,15 +1284,15 @@ msgstr "strony"
#: utils/translation.py:360 #: utils/translation.py:360
msgid "DATE_FORMAT" msgid "DATE_FORMAT"
msgstr "FORMAT_DATY" msgstr "Y-m-d"
#: utils/translation.py:361 #: utils/translation.py:361
msgid "DATETIME_FORMAT" msgid "DATETIME_FORMAT"
msgstr "" msgstr "Y-m-d H:i:s"
#: utils/translation.py:362 #: utils/translation.py:362
msgid "TIME_FORMAT" msgid "TIME_FORMAT"
msgstr "" msgstr "H:i:s"
#: utils/dates.py:6 #: utils/dates.py:6
msgid "Monday" msgid "Monday"
@ -1339,52 +1373,51 @@ msgstr "Grudzień"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy #, fuzzy
msgid "jan" msgid "jan"
msgstr "i" msgstr "sty"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "feb" msgid "feb"
msgstr "" msgstr "luty"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "mar" msgid "mar"
msgstr "" msgstr "marz"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "apr" msgid "apr"
msgstr "" msgstr "kwie"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "may" msgid "may"
msgstr "dzień" msgstr "maj"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "jun" msgid "jun"
msgstr "" msgstr "czerw"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "jul" msgid "jul"
msgstr "" msgstr "lip"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "aug" msgid "aug"
msgstr "" msgstr "sier"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "sep" msgid "sep"
msgstr "" msgstr "wrze"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "oct" msgid "oct"
msgstr "" msgstr "paź"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "nov" msgid "nov"
msgstr "" msgstr "list"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "dec" msgid "dec"
msgstr "" msgstr "gru"
#: utils/dates.py:27 #: utils/dates.py:27
msgid "Jan." msgid "Jan."
@ -1396,7 +1429,7 @@ msgstr "Lut."
#: utils/dates.py:28 #: utils/dates.py:28
msgid "Aug." msgid "Aug."
msgstr "Sier.." msgstr "Sier."
#: utils/dates.py:28 #: utils/dates.py:28
msgid "Sept." msgid "Sept."
@ -1415,31 +1448,28 @@ msgid "Dec."
msgstr "Gru." msgstr "Gru."
#: utils/timesince.py:12 #: utils/timesince.py:12
#, fuzzy
msgid "year" msgid "year"
msgid_plural "years" msgid_plural "years"
msgstr[0] "rok" msgstr[0] "rok"
msgstr[1] "rok" msgstr[1] "lat"
#: utils/timesince.py:13 #: utils/timesince.py:13
#, fuzzy
msgid "month" msgid "month"
msgid_plural "months" msgid_plural "months"
msgstr[0] "miesiąc" msgstr[0] "miesiąc"
msgstr[1] "miesiąc" msgstr[1] "miesięcy"
#: utils/timesince.py:14 #: utils/timesince.py:14
msgid "week" msgid "week"
msgid_plural "weeks" msgid_plural "weeks"
msgstr[0] "" msgstr[0] "tydzień"
msgstr[1] "" msgstr[1] "tygodni"
#: utils/timesince.py:15 #: utils/timesince.py:15
#, fuzzy
msgid "day" msgid "day"
msgid_plural "days" msgid_plural "days"
msgstr[0] "dzień" msgstr[0] "dzień"
msgstr[1] "dzień" msgstr[1] "dni"
#: utils/timesince.py:16 #: utils/timesince.py:16
#, fuzzy #, fuzzy
@ -1449,11 +1479,10 @@ msgstr[0] "godzina"
msgstr[1] "godzina" msgstr[1] "godzina"
#: utils/timesince.py:17 #: utils/timesince.py:17
#, fuzzy
msgid "minute" msgid "minute"
msgid_plural "minutes" msgid_plural "minutes"
msgstr[0] "minuta" msgstr[0] "minuta"
msgstr[1] "minuta" msgstr[1] "minut"
#: conf/global_settings.py:37 #: conf/global_settings.py:37
msgid "Bengali" msgid "Bengali"
@ -1477,7 +1506,7 @@ msgstr "Niemiecki"
#: conf/global_settings.py:42 #: conf/global_settings.py:42
msgid "Greek" msgid "Greek"
msgstr "" msgstr "Grecki"
#: conf/global_settings.py:43 #: conf/global_settings.py:43
msgid "English" msgid "English"
@ -1501,7 +1530,7 @@ msgstr ""
#: conf/global_settings.py:48 #: conf/global_settings.py:48
msgid "Hebrew" msgid "Hebrew"
msgstr "" msgstr "Hebrajski"
#: conf/global_settings.py:49 #: conf/global_settings.py:49
msgid "Icelandic" msgid "Icelandic"
@ -1517,7 +1546,7 @@ msgstr "Japoński"
#: conf/global_settings.py:52 #: conf/global_settings.py:52
msgid "Dutch" msgid "Dutch"
msgstr "" msgstr "Holenderski"
#: conf/global_settings.py:53 #: conf/global_settings.py:53
msgid "Norwegian" msgid "Norwegian"
@ -1570,11 +1599,10 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "To pole możei zawierać tylko litery, cyfry i podkreślenia" msgstr "To pole możei zawierać tylko litery, cyfry i podkreślenia"
#: core/validators.py:64 #: core/validators.py:64
#, fuzzy
msgid "" msgid ""
"This value must contain only letters, numbers, underscores, dashes or " "This value must contain only letters, numbers, underscores, dashes or "
"slashes." "slashes."
msgstr "To pole może zawierać jedynie litery, cyfry, podkreślenia i slasze" msgstr "To pole może zawierać jedynie litery, cyfry, podkreślenia i slasze."
#: core/validators.py:72 #: core/validators.py:72
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."
@ -1606,7 +1634,7 @@ msgstr "Tu mogą być tylko cyfry"
#: core/validators.py:111 #: core/validators.py:111
msgid "This value can't be comprised solely of digits." msgid "This value can't be comprised solely of digits."
msgstr "" msgstr "To pole nie może zawierać jedynie cyfr."
#: core/validators.py:116 #: core/validators.py:116
msgid "Enter a whole number." msgid "Enter a whole number."
@ -1777,6 +1805,7 @@ msgid ""
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
msgstr "" msgstr ""
#: core/validators.py:462 #: core/validators.py:462
#, python-format #, python-format
msgid "" msgid ""

View File

@ -125,12 +125,10 @@ msgid "approved by staff"
msgstr "одобрено администрацией" msgstr "одобрено администрацией"
#: contrib/comments/models.py:176 #: contrib/comments/models.py:176
#, fuzzy
msgid "free comment" msgid "free comment"
msgstr "Свободный комментарий" msgstr "Свободный комментарий"
#: contrib/comments/models.py:177 #: contrib/comments/models.py:177
#, fuzzy
msgid "free comments" msgid "free comments"
msgstr "Свободные комментарии" msgstr "Свободные комментарии"
@ -143,13 +141,12 @@ msgid "score date"
msgstr "счёт времени" msgstr "счёт времени"
#: contrib/comments/models.py:237 #: contrib/comments/models.py:237
#, fuzzy
msgid "karma score" msgid "karma score"
msgstr "счёт" msgstr "Карма счёт"
#: contrib/comments/models.py:238 #: contrib/comments/models.py:238
msgid "karma scores" msgid "karma scores"
msgstr "" msgstr "Карма счета"
#: contrib/comments/models.py:242 #: contrib/comments/models.py:242
#, python-format #, python-format
@ -172,12 +169,10 @@ msgid "flag date"
msgstr "отметка даты" msgstr "отметка даты"
#: contrib/comments/models.py:268 #: contrib/comments/models.py:268
#, fuzzy
msgid "user flag" msgid "user flag"
msgstr "Признак пользователя" msgstr "Признак пользователя"
#: contrib/comments/models.py:269 #: contrib/comments/models.py:269
#, fuzzy
msgid "user flags" msgid "user flags"
msgstr "Признаки пользователя" msgstr "Признаки пользователя"
@ -191,14 +186,12 @@ msgid "deletion date"
msgstr "дата удаления" msgstr "дата удаления"
#: contrib/comments/models.py:280 #: contrib/comments/models.py:280
#, fuzzy
msgid "moderator deletion" msgid "moderator deletion"
msgstr "Удалено модератором" msgstr "Удаленно модератором"
#: contrib/comments/models.py:281 #: contrib/comments/models.py:281
#, fuzzy
msgid "moderator deletions" msgid "moderator deletions"
msgstr "Удалено модератором" msgstr "Удаления модератором"
#: contrib/comments/models.py:285 #: contrib/comments/models.py:285
#, python-format #, python-format
@ -742,7 +735,7 @@ msgstr "К сожалению, запрашиваемая вами страни
#: contrib/admin/templates/admin/index.html:17 #: contrib/admin/templates/admin/index.html:17
#, python-format #, python-format
msgid "Models available in the %(name)s application." msgid "Models available in the %(name)s application."
msgstr "" msgstr "Модели доступны в %(name)s приложении."
#: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15 #: contrib/admin/templates/admin/change_form.html:15
@ -818,11 +811,11 @@ msgstr ""
#: contrib/admin/templates/admin/search_form.html:8 #: contrib/admin/templates/admin/search_form.html:8
msgid "Go" msgid "Go"
msgstr "" msgstr "Вперёд"
#: contrib/admin/templates/admin/change_form.html:21 #: contrib/admin/templates/admin/change_form.html:21
msgid "View on site" msgid "View on site"
msgstr "" msgstr "Смотреть сайт"
#: contrib/admin/templates/admin/change_form.html:30 #: contrib/admin/templates/admin/change_form.html:30
msgid "Please correct the error below." msgid "Please correct the error below."
@ -832,7 +825,7 @@ msgstr[1] "Пожалуйста исправьте ошибки ниже."
#: contrib/admin/templates/admin/change_form.html:48 #: contrib/admin/templates/admin/change_form.html:48
msgid "Ordering" msgid "Ordering"
msgstr "" msgstr "Очерёдность"
#: contrib/admin/templates/admin/change_form.html:51 #: contrib/admin/templates/admin/change_form.html:51
msgid "Order:" msgid "Order:"
@ -967,11 +960,11 @@ msgstr "Спасибо за посещение нашего сайта!"
#: contrib/admin/templates/registration/password_reset_email.html:15 #: contrib/admin/templates/registration/password_reset_email.html:15
#, python-format #, python-format
msgid "The %(site_name)s team" msgid "The %(site_name)s team"
msgstr "Команда сайта di %(site_name)s" msgstr "Команда сайта %(site_name)s"
#: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3
msgid "Bookmarklets" msgid "Bookmarklets"
msgstr "" msgstr "Закладки"
#: contrib/admin/templates/admin_doc/bookmarklets.html:5 #: contrib/admin/templates/admin_doc/bookmarklets.html:5
msgid "Documentation bookmarklets" msgid "Documentation bookmarklets"
@ -1018,7 +1011,7 @@ msgstr "Редактировать данный обьект (в текущем
#: contrib/admin/templates/admin_doc/bookmarklets.html:26 #: contrib/admin/templates/admin_doc/bookmarklets.html:26
msgid "Jumps to the admin page for pages that represent a single object." msgid "Jumps to the admin page for pages that represent a single object."
msgstr "" msgstr "Перейти на страницу администратор для страниц представляющих один объект."
#: contrib/admin/templates/admin_doc/bookmarklets.html:28 #: contrib/admin/templates/admin_doc/bookmarklets.html:28
msgid "Edit this object (new window)" msgid "Edit this object (new window)"
@ -1129,22 +1122,18 @@ msgid "codename"
msgstr "код" msgstr "код"
#: contrib/auth/models.py:17 #: contrib/auth/models.py:17
#, fuzzy
msgid "permission" msgid "permission"
msgstr "Права" msgstr "Права"
#: contrib/auth/models.py:18 contrib/auth/models.py:27 #: contrib/auth/models.py:18 contrib/auth/models.py:27
#, fuzzy
msgid "permissions" msgid "permissions"
msgstr "Права" msgstr "Права"
#: contrib/auth/models.py:29 #: contrib/auth/models.py:29
#, fuzzy
msgid "group" msgid "group"
msgstr "Группа" msgstr "Группа"
#: contrib/auth/models.py:30 contrib/auth/models.py:65 #: contrib/auth/models.py:30 contrib/auth/models.py:65
#, fuzzy
msgid "groups" msgid "groups"
msgstr "Группы" msgstr "Группы"
@ -1205,17 +1194,14 @@ msgstr ""
"все права группы, к которой он принадлежит." "все права группы, к которой он принадлежит."
#: contrib/auth/models.py:67 #: contrib/auth/models.py:67
#, fuzzy
msgid "user permissions" msgid "user permissions"
msgstr "Права" msgstr "Права пользователя"
#: contrib/auth/models.py:70 #: contrib/auth/models.py:70
#, fuzzy
msgid "user" msgid "user"
msgstr "Пользователь" msgstr "Пользователь"
#: contrib/auth/models.py:71 #: contrib/auth/models.py:71
#, fuzzy
msgid "users" msgid "users"
msgstr "Пользователи" msgstr "Пользователи"
@ -1236,7 +1222,6 @@ msgid "Groups"
msgstr "Группы" msgstr "Группы"
#: contrib/auth/models.py:219 #: contrib/auth/models.py:219
#, fuzzy
msgid "message" msgid "message"
msgstr "Сообщение" msgstr "Сообщение"
@ -1247,9 +1232,8 @@ msgid ""
msgstr "" msgstr ""
#: contrib/contenttypes/models.py:25 #: contrib/contenttypes/models.py:25
#, fuzzy
msgid "python model class name" msgid "python model class name"
msgstr "имя python модуля" msgstr "имя класса python модуля"
#: contrib/contenttypes/models.py:28 #: contrib/contenttypes/models.py:28
msgid "content type" msgid "content type"
@ -1384,54 +1368,52 @@ msgid "December"
msgstr "Декабрь" msgstr "Декабрь"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "jan" msgid "jan"
msgstr "и" msgstr "янв"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "feb" msgid "feb"
msgstr "" msgstr "фев"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "mar" msgid "mar"
msgstr "" msgstr "мар"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "apr" msgid "apr"
msgstr "" msgstr "апр"
#: utils/dates.py:19 #: utils/dates.py:19
#, fuzzy
msgid "may" msgid "may"
msgstr "Май" msgstr "май"
#: utils/dates.py:19 #: utils/dates.py:19
msgid "jun" msgid "jun"
msgstr "" msgstr "июнь"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "jul" msgid "jul"
msgstr "" msgstr "июль"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "aug" msgid "aug"
msgstr "" msgstr "авг"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "sep" msgid "sep"
msgstr "" msgstr "сен"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "oct" msgid "oct"
msgstr "" msgstr "окт"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "nov" msgid "nov"
msgstr "" msgstr "нояб"
#: utils/dates.py:20 #: utils/dates.py:20
msgid "dec" msgid "dec"
msgstr "" msgstr "дек"
#: utils/dates.py:27 #: utils/dates.py:27
msgid "Jan." msgid "Jan."
@ -1476,8 +1458,8 @@ msgstr[1] "месяцев"
#: utils/timesince.py:14 #: utils/timesince.py:14
msgid "week" msgid "week"
msgid_plural "weeks" msgid_plural "weeks"
msgstr[0] "" msgstr[0] "неделя"
msgstr[1] "" msgstr[1] "недель"
#: utils/timesince.py:15 #: utils/timesince.py:15
msgid "day" msgid "day"
@ -1610,11 +1592,11 @@ msgid "This value must contain only letters, numbers and underscores."
msgstr "Значение может содержать только буквы, цифры и подчеркивания." msgstr "Значение может содержать только буквы, цифры и подчеркивания."
#: core/validators.py:64 #: core/validators.py:64
#, fuzzy
msgid "" msgid ""
"This value must contain only letters, numbers, underscores, dashes or " "This value must contain only letters, numbers, underscores, dashes or "
"slashes." "slashes."
msgstr "Значение может содержать только буквы, цифры и подчеркивания." msgstr "Значение может содержать только буквы, цифры, подчеркивания, дифисы или "
"тере."
#: core/validators.py:72 #: core/validators.py:72
msgid "Uppercase letters are not allowed here." msgid "Uppercase letters are not allowed here."

File diff suppressed because it is too large Load Diff

View File

@ -11,18 +11,18 @@ import datetime
class FilterSpec(object): class FilterSpec(object):
filter_specs = [] filter_specs = []
def __init__(self, f, request, params): def __init__(self, f, request, params, model):
self.field = f self.field = f
self.params = params self.params = params
def register(cls, test, factory): def register(cls, test, factory):
cls.filter_specs.append( (test, factory) ) cls.filter_specs.append((test, factory))
register = classmethod(register) register = classmethod(register)
def create(cls, f, request, params): def create(cls, f, request, params, model):
for test, factory in cls.filter_specs: for test, factory in cls.filter_specs:
if test(f): if test(f):
return factory(f, request, params) return factory(f, request, params, model)
create = classmethod(create) create = classmethod(create)
def has_output(self): def has_output(self):
@ -48,8 +48,8 @@ class FilterSpec(object):
return "".join(t) return "".join(t)
class RelatedFilterSpec(FilterSpec): class RelatedFilterSpec(FilterSpec):
def __init__(self, f, request, params): def __init__(self, f, request, params, model):
super(RelatedFilterSpec, self).__init__(f, request, params) super(RelatedFilterSpec, self).__init__(f, request, params, model)
if isinstance(f, models.ManyToManyField): if isinstance(f, models.ManyToManyField):
self.lookup_title = f.rel.to._meta.verbose_name self.lookup_title = f.rel.to._meta.verbose_name
else: else:
@ -71,31 +71,31 @@ class RelatedFilterSpec(FilterSpec):
for val in self.lookup_choices: for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to._meta.pk.attname) pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
yield {'selected': self.lookup_val == str(pk_val), yield {'selected': self.lookup_val == str(pk_val),
'query_string': cl.get_query_string( {self.lookup_kwarg: pk_val}), 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
'display': val} 'display': val}
FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec) FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
class ChoicesFilterSpec(FilterSpec): class ChoicesFilterSpec(FilterSpec):
def __init__(self, f, request, params): def __init__(self, f, request, params, model):
super(ChoicesFilterSpec, self).__init__(f, request, params) super(ChoicesFilterSpec, self).__init__(f, request, params, model)
self.lookup_kwarg = '%s__exact' % f.name self.lookup_kwarg = '%s__exact' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None) self.lookup_val = request.GET.get(self.lookup_kwarg, None)
def choices(self, cl): def choices(self, cl):
yield {'selected': self.lookup_val is None, yield {'selected': self.lookup_val is None,
'query_string': cl.get_query_string( {}, [self.lookup_kwarg]), 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')} 'display': _('All')}
for k, v in self.field.choices: for k, v in self.field.choices:
yield {'selected': str(k) == self.lookup_val, yield {'selected': str(k) == self.lookup_val,
'query_string': cl.get_query_string( {self.lookup_kwarg: k}), 'query_string': cl.get_query_string({self.lookup_kwarg: k}),
'display': v} 'display': v}
FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec) FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
class DateFieldFilterSpec(FilterSpec): class DateFieldFilterSpec(FilterSpec):
def __init__(self, f, request, params): def __init__(self, f, request, params, model):
super(DateFieldFilterSpec, self).__init__(f, request, params) super(DateFieldFilterSpec, self).__init__(f, request, params, model)
self.field_generic = '%s__' % self.field.name self.field_generic = '%s__' % self.field.name
@ -123,14 +123,14 @@ class DateFieldFilterSpec(FilterSpec):
def choices(self, cl): def choices(self, cl):
for title, param_dict in self.links: for title, param_dict in self.links:
yield {'selected': self.date_params == param_dict, yield {'selected': self.date_params == param_dict,
'query_string': cl.get_query_string( param_dict, self.field_generic), 'query_string': cl.get_query_string(param_dict, self.field_generic),
'display': title} 'display': title}
FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec) FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
class BooleanFieldFilterSpec(FilterSpec): class BooleanFieldFilterSpec(FilterSpec):
def __init__(self, f, request, params): def __init__(self, f, request, params, model):
super(BooleanFieldFilterSpec, self).__init__(f, request, params) super(BooleanFieldFilterSpec, self).__init__(f, request, params, model)
self.lookup_kwarg = '%s__exact' % f.name self.lookup_kwarg = '%s__exact' % f.name
self.lookup_kwarg2 = '%s__isnull' % f.name self.lookup_kwarg2 = '%s__isnull' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None) self.lookup_val = request.GET.get(self.lookup_kwarg, None)
@ -142,11 +142,34 @@ class BooleanFieldFilterSpec(FilterSpec):
def choices(self, cl): def choices(self, cl):
for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')): for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
yield {'selected': self.lookup_val == v and not self.lookup_val2, yield {'selected': self.lookup_val == v and not self.lookup_val2,
'query_string': cl.get_query_string( {self.lookup_kwarg: v}, [self.lookup_kwarg2]), 'query_string': cl.get_query_string({self.lookup_kwarg: v}, [self.lookup_kwarg2]),
'display': k} 'display': k}
if isinstance(self.field, models.NullBooleanField): if isinstance(self.field, models.NullBooleanField):
yield {'selected': self.lookup_val2 == 'True', yield {'selected': self.lookup_val2 == 'True',
'query_string': cl.get_query_string( {self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]), 'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
'display': _('Unknown')} 'display': _('Unknown')}
FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec) FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
# This should be registered last, because it's a last resort. For example,
# if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
# more appropriate, and the AllValuesFilterSpec won't get used for it.
class AllValuesFilterSpec(FilterSpec):
def __init__(self, f, request, params, model):
super(AllValuesFilterSpec, self).__init__(f, request, params, model)
self.lookup_val = request.GET.get(f.name, None)
self.lookup_choices = model._meta.admin.manager.distinct().order_by(f.name).values(f.name)
def title(self):
return self.field.verbose_name
def choices(self, cl):
yield {'selected': self.lookup_val is None,
'query_string': cl.get_query_string({}, [self.field.name]),
'display': _('All')}
for val in self.lookup_choices:
val = str(val[self.field.name])
yield {'selected': self.lookup_val == val,
'query_string': cl.get_query_string({self.field.name: val}),
'display': val}
FilterSpec.register(lambda f: True, AllValuesFilterSpec)

View File

@ -0,0 +1,46 @@
body { direction: rtl; }
/* login styles */
.login .form-row { float:right; }
.login .form-row label { float:right; padding-left:0.5em; padding-right:0; text-align:left;}
.login .submit-row { clear:both; padding:1em 9.4em 0 0; }
/* global styles */
th { text-align: right; }
.module h2, .module caption { text-align: right; }
.addlink, .changelink { padding-left:0px; padding-right:12px; background-position:100% 0.2em; }
.deletelink { padding-left:0px; padding-right:12px; background-position:100% 0.25em; }
.object-tools { float:left; }
/* layout styles */
#user-tools { right:auto; left:0; text-align:left; }
div.breadcrumbs { text-align:right; }
#content-main { float:right;}
#content-related { float:left; margin-left:-19em; margin-right:auto;}
.colMS { margin-left:20em !important; margin-right:10px !important;}
/* dashboard styles */
.dashboard .module table td a { padding-left:.6em; padding-right:12px; }
/* changelists styles */
.change-list .filtered { background:white url(../img/admin/changelist-bg_rtl.gif) top left repeat-y !important; }
.change-list .filtered table { border-left:1px solid #ddd; border-right:0px none; }
#changelist-filter { right:auto; left:0; border-left:0px none; border-right:1px solid #ddd;}
.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right:0px !important; margin-left:160px !important; }
#changelist-filter li.selected { border-left:0px none; padding-left:0px; margin-left:0; border-right:5px solid #ccc; padding-right:5px;margin-right:-10px; }
/* fomrs styles */
.aligned label { padding:0 0 3px 1em; float:right; }
.submit-row { text-align: left }
.vDateField, .vTimeField { margin-left:2px; }
/* widget styles */
.calendarnav-previous { top:0; left:auto; right:0; }
.calendarnav-next { top:0; right:auto; left:0;}
.calendar caption, .calendarbox h2 { text-align:center; }
.selector { float: right;}
.selector .selector-filter { text-align: right;}

View File

@ -31,7 +31,7 @@ var CollapsedFieldsets = {
collapse_link.id = 'fieldsetcollapser' + i; collapse_link.id = 'fieldsetcollapser' + i;
collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;'); collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;');
collapse_link.href = '#'; collapse_link.href = '#';
collapse_link.innerHTML = 'Show'; collapse_link.innerHTML = gettext('Show');
var h2 = fs.getElementsByTagName('h2')[0]; var h2 = fs.getElementsByTagName('h2')[0];
h2.appendChild(document.createTextNode(' (')); h2.appendChild(document.createTextNode(' ('));
h2.appendChild(collapse_link); h2.appendChild(collapse_link);
@ -60,7 +60,7 @@ var CollapsedFieldsets = {
// Toggle the "Show" link to a "Hide" link // Toggle the "Show" link to a "Hide" link
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;'); collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;');
collapse_link.innerHTML = 'Hide'; collapse_link.innerHTML = gettext('Hide');
}, },
hide: function(fieldset_index) { hide: function(fieldset_index) {
var fs = document.getElementsByTagName('fieldset')[fieldset_index]; var fs = document.getElementsByTagName('fieldset')[fieldset_index];
@ -69,9 +69,9 @@ var CollapsedFieldsets = {
// Toggle the "Hide" link to a "Show" link // Toggle the "Hide" link to a "Show" link
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;'); collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;');
collapse_link.innerHTML = 'Show'; collapse_link.innerHTML = gettext('Show');
}, },
uncollapse_all: function() { uncollapse_all: function() {
var fieldsets = document.getElementsByTagName('fieldset'); var fieldsets = document.getElementsByTagName('fieldset');
for (var i=0; i<fieldsets.length; i++) { for (var i=0; i<fieldsets.length; i++) {

View File

@ -69,7 +69,16 @@ var DateTimeShortcuts = {
var clock_box = document.createElement('div'); var clock_box = document.createElement('div');
clock_box.style.display = 'none'; clock_box.style.display = 'none';
clock_box.style.position = 'absolute'; clock_box.style.position = 'absolute';
clock_box.style.left = findPosX(clock_link) + 17 + 'px'; 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.style.top = findPosY(clock_link) - 30 + 'px';
clock_box.className = 'clockbox module'; clock_box.className = 'clockbox module';
clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num); clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
@ -140,7 +149,17 @@ var DateTimeShortcuts = {
var cal_box = document.createElement('div'); var cal_box = document.createElement('div');
cal_box.style.display = 'none'; cal_box.style.display = 'none';
cal_box.style.position = 'absolute'; cal_box.style.position = 'absolute';
cal_box.style.left = findPosX(cal_link) + 17 + 'px'; // 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.top = findPosY(cal_link) - 75 + 'px';
cal_box.className = 'calendarbox module'; cal_box.className = 'calendarbox module';
cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num); cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);

View File

@ -135,4 +135,21 @@ String.prototype.pad_left = function(pad_length, pad_string) {
new_string = pad_string + new_string; new_string = pad_string + new_string;
} }
return new_string; return new_string;
} }
// ----------------------------------------------------------------------------
// Get the computed style for and element
// ----------------------------------------------------------------------------
function getStyle(oElm, strCssRule){
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
}

View File

@ -1,8 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}"> <html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head> <head>
<title>{% block title %}{% endblock %}</title> <title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/base.css{% endblock %}" /> <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/base.css{% endblock %}" />
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
{% block extrastyle %}{% endblock %} {% block extrastyle %}{% endblock %}
{% block extrahead %}{% endblock %} {% block extrahead %}{% endblock %}
</head> </head>
@ -20,7 +21,7 @@
{% block branding %}{% endblock %} {% block branding %}{% endblock %}
</div> </div>
{% if not user.is_anonymous %}{% if user.is_staff %} {% if not user.is_anonymous %}{% if user.is_staff %}
<div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div> <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
{% endif %}{% endif %} {% endif %}{% endif %}
{% block nav-global %}{% endblock %} {% block nav-global %}{% endblock %}
</div> </div>

View File

@ -1,6 +1,7 @@
{% load admin_list %} {% load admin_list %}
{% load i18n %}
{% if cl.has_filters %}<div id="changelist-filter"> {% if cl.has_filters %}<div id="changelist-filter">
<h2>Filter</h2> <h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %} {% for spec in cl.filter_specs %}
{% filter cl spec %} {% filter cl spec %}
{% endfor %}</div>{% endif %} {% endfor %}</div>{% endif %}

View File

@ -1,4 +1,5 @@
{% load admin_list %} {% load admin_list %}
{% load i18n %}
<p class="paginator"> <p class="paginator">
{% if pagination_required %} {% if pagination_required %}
{% for i in page_range %} {% for i in page_range %}
@ -6,5 +7,5 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %} {{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">Show all</a>{% endif %} {% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
</p> </p>

View File

@ -7,7 +7,7 @@
<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" /> <input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" />
<input type="submit" value="{% trans 'Go' %}" /> <input type="submit" value="{% trans 'Go' %}" />
{% if show_result_count %} {% if show_result_count %}
<span class="small quiet">{{ cl.result_count }} result{{ cl.result_count|pluralize }} (<a href="?">{{ cl.full_result_count }} total</a>)</span> <span class="small quiet">{% blocktrans count cl.result_count as counter %}1 result{% plural %}{{ counter }} results{% endblocktrans %} (<a href="?">{% blocktrans with cl.full_result_count as full_result_count %}{{ full_result_count }} total{% endblocktrans %}</a>)</span>
{% endif %} {% endif %}
{% for pair in cl.params.items %} {% for pair in cl.params.items %}
{% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %} {% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %}

View File

@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
{% trans "You're receiving this e-mail because you requested a password reset" %} {% trans "You're receiving this e-mail because you requested a password reset" %}
{% trans "for your user account at %(site_name)s" %}. {% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
{% blocktrans %}Your new password is: {{ new_password }}{% endblocktrans %} {% blocktrans %}Your new password is: {{ new_password }}{% endblocktrans %}

View File

@ -131,7 +131,7 @@ def items_for_result(cl, result):
if isinstance(f.rel, models.ManyToOneRel): if isinstance(f.rel, models.ManyToOneRel):
if field_val is not None: if field_val is not None:
result_repr = getattr(result, f.name) result_repr = escape(getattr(result, f.name))
else: else:
result_repr = EMPTY_CHANGELIST_VALUE result_repr = EMPTY_CHANGELIST_VALUE
# Dates and times are special: They're formatted in a certain way. # Dates and times are special: They're formatted in a certain way.

View File

@ -18,6 +18,19 @@ def class_name_to_underscored(name):
return '_'.join([s.lower() for s in word_re.findall(name)[:-1]]) return '_'.join([s.lower() for s in word_re.findall(name)[:-1]])
def include_admin_script(script_path): def include_admin_script(script_path):
"""
Returns an HTML script element for including a script from the admin
media url.
Example usage::
{% include_admin_script js/calendar.js %}
could return::
<script type="text/javascript" src="/media/admin/js/calendar.js">
"""
return '<script type="text/javascript" src="%s%s"></script>' % (settings.ADMIN_MEDIA_PREFIX, script_path) return '<script type="text/javascript" src="%s%s"></script>' % (settings.ADMIN_MEDIA_PREFIX, script_path)
include_admin_script = register.simple_tag(include_admin_script) include_admin_script = register.simple_tag(include_admin_script)

View File

@ -574,7 +574,7 @@ class ChangeList(object):
filter_fields = [self.lookup_opts.get_field(field_name) \ filter_fields = [self.lookup_opts.get_field(field_name) \
for field_name in self.lookup_opts.admin.list_filter] for field_name in self.lookup_opts.admin.list_filter]
for f in filter_fields: for f in filter_fields:
spec = FilterSpec.create(f, request, self.params) spec = FilterSpec.create(f, request, self.params, self.model)
if spec and spec.has_output(): if spec and spec.has_output():
filter_specs.append(spec) filter_specs.append(spec)
return filter_specs, bool(filter_specs) return filter_specs, bool(filter_specs)

View File

@ -23,8 +23,6 @@ def create_permissions(app, created_models):
if not app_models: if not app_models:
return return
for klass in app_models: for klass in app_models:
if not klass._meta.admin:
continue
ctype = ContentType.objects.get_for_model(klass) ctype = ContentType.objects.get_for_model(klass)
for codename, name in _get_all_permissions(klass._meta): for codename, name in _get_all_permissions(klass._meta):
try: try:

View File

@ -8,7 +8,7 @@ class LazyUser(object):
self._user = get_user(request) self._user = get_user(request)
return self._user return self._user
class AuthenticationMiddleware: class AuthenticationMiddleware(object):
def process_request(self, request): def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.__class__.user = LazyUser() request.__class__.user = LazyUser()

View File

@ -8,7 +8,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME
def login(request): def login(request, template_name='registration/login.html'):
"Displays the login form and handles the login action." "Displays the login form and handles the login action."
manipulator = AuthenticationForm(request) manipulator = AuthenticationForm(request)
redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '') redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
@ -25,19 +25,19 @@ def login(request):
else: else:
errors = {} errors = {}
request.session.set_test_cookie() request.session.set_test_cookie()
return render_to_response('registration/login.html', { return render_to_response(template_name, {
'form': forms.FormWrapper(manipulator, request.POST, errors), 'form': forms.FormWrapper(manipulator, request.POST, errors),
REDIRECT_FIELD_NAME: redirect_to, REDIRECT_FIELD_NAME: redirect_to,
'site_name': Site.objects.get_current().name, 'site_name': Site.objects.get_current().name,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
def logout(request, next_page=None): def logout(request, next_page=None, template_name='registration/logged_out.html'):
"Logs out the user and displays 'You are logged out' message." "Logs out the user and displays 'You are logged out' message."
from django.contrib.auth import logout from django.contrib.auth import logout
try: try:
logout(request) logout(request)
except KeyError: except KeyError:
return render_to_response('registration/logged_out.html', {'title': 'Logged out'}, context_instance=RequestContext(request)) return render_to_response(template_name, {'title': _('Logged out')}, context_instance=RequestContext(request))
else: else:
# Redirect to this page until the session has been cleared. # Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page or request.path) return HttpResponseRedirect(next_page or request.path)
@ -50,7 +50,7 @@ def redirect_to_login(next, login_url=LOGIN_URL):
"Redirects the user to the login page, passing the given 'next' page" "Redirects the user to the login page, passing the given 'next' page"
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next)) return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next))
def password_reset(request, is_admin_site=False): def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html'):
new_data, errors = {}, {} new_data, errors = {}, {}
form = PasswordResetForm() form = PasswordResetForm()
if request.POST: if request.POST:
@ -62,13 +62,13 @@ def password_reset(request, is_admin_site=False):
else: else:
form.save() form.save()
return HttpResponseRedirect('%sdone/' % request.path) return HttpResponseRedirect('%sdone/' % request.path)
return render_to_response('registration/password_reset_form.html', {'form': forms.FormWrapper(form, new_data, errors)}, return render_to_response(template_name, {'form': forms.FormWrapper(form, new_data, errors)},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
def password_reset_done(request): def password_reset_done(request, template_name='registration/password_reset_done.html'):
return render_to_response('registration/password_reset_done.html', context_instance=RequestContext(request)) return render_to_response(template_name, context_instance=RequestContext(request))
def password_change(request): def password_change(request, template_name='registration/password_change_form.html'):
new_data, errors = {}, {} new_data, errors = {}, {}
form = PasswordChangeForm(request.user) form = PasswordChangeForm(request.user)
if request.POST: if request.POST:
@ -77,9 +77,9 @@ def password_change(request):
if not errors: if not errors:
form.save(new_data) form.save(new_data)
return HttpResponseRedirect('%sdone/' % request.path) return HttpResponseRedirect('%sdone/' % request.path)
return render_to_response('registration/password_change_form.html', {'form': forms.FormWrapper(form, new_data, errors)}, return render_to_response(template_name, {'form': forms.FormWrapper(form, new_data, errors)},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
password_change = login_required(password_change) password_change = login_required(password_change)
def password_change_done(request): def password_change_done(request, template_name='registration/password_change_done.html'):
return render_to_response('registration/password_change_done.html', context_instance=RequestContext(request)) return render_to_response(template_name, context_instance=RequestContext(request))

View File

@ -0,0 +1,24 @@
"""
Creates content types for all installed models.
"""
from django.dispatch import dispatcher
from django.db.models import get_models, signals
def create_contenttypes(app, created_models):
from django.contrib.contenttypes.models import ContentType
app_models = get_models(app)
if not app_models:
return
for klass in app_models:
opts = klass._meta
try:
ContentType.objects.get(app_label=opts.app_label,
model=opts.object_name.lower())
except ContentType.DoesNotExist:
ct = ContentType(name=str(opts.verbose_name),
app_label=opts.app_label, model=opts.object_name.lower())
ct.save()
print "Adding content type '%s | %s'" % (ct.app_label, ct.model)
dispatcher.connect(create_contenttypes, signal=signals.post_syncdb)

View File

@ -2,7 +2,7 @@ from django.contrib.flatpages.views import flatpage
from django.http import Http404 from django.http import Http404
from django.conf import settings from django.conf import settings
class FlatpageFallbackMiddleware: class FlatpageFallbackMiddleware(object):
def process_response(self, request, response): def process_response(self, request, response):
if response.status_code != 404: if response.status_code != 404:
return response # No need to check for a flatpage for non-404 responses. return response # No need to check for a flatpage for non-404 responses.

View File

@ -2,7 +2,7 @@ from django.contrib.redirects.models import Redirect
from django import http from django import http
from django.conf import settings from django.conf import settings
class RedirectFallbackMiddleware: class RedirectFallbackMiddleware(object):
def process_response(self, request, response): def process_response(self, request, response):
if response.status_code != 404: if response.status_code != 404:
return response # No need to check for a redirect for non-404 responses. return response # No need to check for a redirect for non-404 responses.

View File

@ -8,15 +8,17 @@ class Redirect(models.Model):
help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
new_path = models.CharField(_('redirect to'), maxlength=200, blank=True, new_path = models.CharField(_('redirect to'), maxlength=200, blank=True,
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
class Meta: class Meta:
verbose_name = _('redirect') verbose_name = _('redirect')
verbose_name_plural = _('redirects') verbose_name_plural = _('redirects')
db_table = 'django_redirect' db_table = 'django_redirect'
unique_together=(('site', 'old_path'),) unique_together=(('site', 'old_path'),)
ordering = ('old_path',) ordering = ('old_path',)
class Admin: class Admin:
list_filter = ('site',) list_filter = ('site',)
search_fields = ('old_path', 'new_path') search_fields = ('old_path', 'new_path')
def __repr__(self): def __str__(self):
return "%s ---> %s" % (self.old_path, self.new_path) return "%s ---> %s" % (self.old_path, self.new_path)

View File

@ -64,7 +64,7 @@ class SessionWrapper(object):
_session = property(_get_session) _session = property(_get_session)
class SessionMiddleware: class SessionMiddleware(object):
def process_request(self, request): def process_request(self, request):
request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)) request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))

View File

@ -12,7 +12,7 @@ def add_domain(domain, url):
class FeedDoesNotExist(ObjectDoesNotExist): class FeedDoesNotExist(ObjectDoesNotExist):
pass pass
class Feed: class Feed(object):
item_pubdate = None item_pubdate = None
item_enclosure_url = None item_enclosure_url = None
feed_type = feedgenerator.DefaultFeed feed_type = feedgenerator.DefaultFeed
@ -73,6 +73,7 @@ class Feed:
author_name = self.__get_dynamic_attr('author_name', obj), author_name = self.__get_dynamic_attr('author_name', obj),
author_link = self.__get_dynamic_attr('author_link', obj), author_link = self.__get_dynamic_attr('author_link', obj),
author_email = self.__get_dynamic_attr('author_email', obj), author_email = self.__get_dynamic_attr('author_email', obj),
categories = self.__get_dynamic_attr('categories', obj),
) )
try: try:
@ -110,5 +111,6 @@ class Feed:
author_name = author_name, author_name = author_name,
author_email = author_email, author_email = author_email,
author_link = author_link, author_link = author_link,
categories = self.__get_dynamic_attr('item_categories', item),
) )
return feed return feed

View File

@ -5,7 +5,7 @@ from django.core.exceptions import ImproperlyConfigured
class InvalidCacheBackendError(ImproperlyConfigured): class InvalidCacheBackendError(ImproperlyConfigured):
pass pass
class BaseCache: class BaseCache(object):
def __init__(self, params): def __init__(self, params):
timeout = params.get('timeout', 300) timeout = params.get('timeout', 300)
try: try:

View File

@ -36,6 +36,10 @@ def i18n(request):
context_extras['LANGUAGE_CODE'] = request.LANGUAGE_CODE context_extras['LANGUAGE_CODE'] = request.LANGUAGE_CODE
else: else:
context_extras['LANGUAGE_CODE'] = settings.LANGUAGE_CODE context_extras['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
from django.utils import translation
context_extras['LANGUAGE_BIDI'] = translation.get_language_bidi()
return context_extras return context_extras
def request(request): def request(request):
@ -44,7 +48,7 @@ def request(request):
# PermWrapper and PermLookupDict proxy the permissions system into objects that # PermWrapper and PermLookupDict proxy the permissions system into objects that
# the template system can understand. # the template system can understand.
class PermLookupDict: class PermLookupDict(object):
def __init__(self, user, module_name): def __init__(self, user, module_name):
self.user, self.module_name = user, module_name self.user, self.module_name = user, module_name
def __repr__(self): def __repr__(self):
@ -54,7 +58,7 @@ class PermLookupDict:
def __nonzero__(self): def __nonzero__(self):
return self.user.has_module_perms(self.module_name) return self.user.has_module_perms(self.module_name)
class PermWrapper: class PermWrapper(object):
def __init__(self, user): def __init__(self, user):
self.user = user self.user = user
def __getitem__(self, module_name): def __getitem__(self, module_name):

View File

@ -3,7 +3,7 @@ from django.dispatch import dispatcher
from django import http from django import http
import sys import sys
class BaseHandler: class BaseHandler(object):
def __init__(self): def __init__(self):
self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None

View File

@ -211,35 +211,38 @@ def _get_sql_for_pending_references(klass, pending_references):
def _get_many_to_many_sql_for_model(klass): def _get_many_to_many_sql_for_model(klass):
from django.db import backend, get_creation_module from django.db import backend, get_creation_module
from django.db.models import GenericRel
data_types = get_creation_module().DATA_TYPES data_types = get_creation_module().DATA_TYPES
opts = klass._meta opts = klass._meta
final_output = [] final_output = []
for f in opts.many_to_many: for f in opts.many_to_many:
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ if not isinstance(f.rel, GenericRel):
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' ('] table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
table_output.append(' %s %s %s,' % \ style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
(style.SQL_FIELD(backend.quote_name('id')), table_output.append(' %s %s %s,' % \
style.SQL_COLTYPE(data_types['AutoField']), (style.SQL_FIELD(backend.quote_name('id')),
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) style.SQL_COLTYPE(data_types['AutoField']),
table_output.append(' %s %s %s %s (%s),' % \ style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), table_output.append(' %s %s %s %s (%s),' % \
style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__), (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
style.SQL_KEYWORD('NOT NULL REFERENCES'), style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
style.SQL_TABLE(backend.quote_name(opts.db_table)), style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_FIELD(backend.quote_name(opts.pk.column)))) style.SQL_TABLE(backend.quote_name(opts.db_table)),
table_output.append(' %s %s %s %s (%s),' % \ style.SQL_FIELD(backend.quote_name(opts.pk.column))))
(style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), table_output.append(' %s %s %s %s (%s),' % \
style.SQL_COLTYPE(data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__), (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
style.SQL_KEYWORD('NOT NULL REFERENCES'), style.SQL_COLTYPE(data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__),
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)), style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)))) style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
table_output.append(' %s (%s, %s)' % \ style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column))))
(style.SQL_KEYWORD('UNIQUE'), table_output.append(' %s (%s, %s)' % \
style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), (style.SQL_KEYWORD('UNIQUE'),
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
table_output.append(');') style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
final_output.append('\n'.join(table_output)) table_output.append(');')
final_output.append('\n'.join(table_output))
return final_output return final_output
def get_sql_delete(app): def get_sql_delete(app):
@ -815,10 +818,8 @@ def get_validation_errors(outfile, app=None):
# Do field-specific validation. # Do field-specific validation.
for f in opts.fields: for f in opts.fields:
# Check for deprecated args if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
dep_args = getattr(f, 'deprecated_args', None) e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
if dep_args:
e.add(opts, "'%s' Initialized with deprecated args:%s" % (f.name, ",".join(dep_args)))
if isinstance(f, models.CharField) and f.maxlength in (None, 0): if isinstance(f, models.CharField) and f.maxlength in (None, 0):
e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name) e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
if isinstance(f, models.FloatField): if isinstance(f, models.FloatField):
@ -836,8 +837,8 @@ def get_validation_errors(outfile, app=None):
if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple): if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name) e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
if f.choices: if f.choices:
if not type(f.choices) in (tuple, list): if not hasattr(f.choices, '__iter__'):
e.add(opts, '"%s": "choices" should be either a tuple or list.' % f.name) e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
else: else:
for c in f.choices: for c in f.choices:
if not type(c) in (tuple, list) or len(c) != 2: if not type(c) in (tuple, list) or len(c) != 2:
@ -923,6 +924,7 @@ def get_validation_errors(outfile, app=None):
field_name = field_name[1:] field_name = field_name[1:]
if opts.order_with_respect_to and field_name == '_order': if opts.order_with_respect_to and field_name == '_order':
continue continue
if '.' in field_name: continue # Skip ordering in the format 'table.field'.
try: try:
opts.get_field(field_name, many_to_many=False) opts.get_field(field_name, many_to_many=False)
except models.FieldDoesNotExist: except models.FieldDoesNotExist:

View File

@ -4,7 +4,7 @@ from math import ceil
class InvalidPage(Exception): class InvalidPage(Exception):
pass pass
class ObjectPaginator: class ObjectPaginator(object):
""" """
This class makes pagination easy. Feed it a QuerySet, plus the number of This class makes pagination easy. Feed it a QuerySet, plus the number of
objects you want on each page. Then read the hits and pages properties to objects you want on each page. Then read the hits and pages properties to

View File

@ -21,7 +21,7 @@ software_version = server_version + ' ' + sys_version
class WSGIServerException(Exception): class WSGIServerException(Exception):
pass pass
class FileWrapper: class FileWrapper(object):
"""Wrapper to convert file-like objects to iterables""" """Wrapper to convert file-like objects to iterables"""
def __init__(self, filelike, blksize=8192): def __init__(self, filelike, blksize=8192):
@ -63,7 +63,7 @@ def _formatparam(param, value=None, quote=1):
else: else:
return param return param
class Headers: class Headers(object):
"""Manage a collection of HTTP response headers""" """Manage a collection of HTTP response headers"""
def __init__(self,headers): def __init__(self,headers):
if type(headers) is not ListType: if type(headers) is not ListType:
@ -218,7 +218,7 @@ def is_hop_by_hop(header_name):
"""Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header""" """Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header"""
return _hoppish(header_name.lower()) return _hoppish(header_name.lower())
class ServerHandler: class ServerHandler(object):
"""Manage the invocation of a WSGI application""" """Manage the invocation of a WSGI application"""
# Configuration parameters; can override per-subclass or per-instance # Configuration parameters; can override per-subclass or per-instance
@ -591,7 +591,7 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
return return
sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format % args)) sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format % args))
class AdminMediaHandler: class AdminMediaHandler(object):
""" """
WSGI middleware that intercepts calls to the admin media directory, as WSGI middleware that intercepts calls to the admin media directory, as
defined by the ADMIN_MEDIA_PREFIX setting, and serves those images. defined by the ADMIN_MEDIA_PREFIX setting, and serves those images.

View File

@ -83,7 +83,7 @@ class MatchChecker(object):
raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex)) raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
return str(value) # TODO: Unicode? return str(value) # TODO: Unicode?
class RegexURLPattern: class RegexURLPattern(object):
def __init__(self, regex, callback, default_args=None): def __init__(self, regex, callback, default_args=None):
# regex is a string representing a regular expression. # regex is a string representing a regular expression.
# callback is something like 'foo.views.news.stories.story_detail', # callback is something like 'foo.views.news.stories.story_detail',

View File

@ -237,7 +237,7 @@ def hasNoProfanities(field_data, all_data):
"Watch your mouth! The words %s are not allowed here.", plural) % \ "Watch your mouth! The words %s are not allowed here.", plural) % \
get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and') get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and')
class AlwaysMatchesOtherField: class AlwaysMatchesOtherField(object):
def __init__(self, other_field_name, error_message=None): def __init__(self, other_field_name, error_message=None):
self.other = other_field_name self.other = other_field_name
self.error_message = error_message or lazy_inter(gettext_lazy("This field must match the '%s' field."), self.other) self.error_message = error_message or lazy_inter(gettext_lazy("This field must match the '%s' field."), self.other)
@ -247,7 +247,7 @@ class AlwaysMatchesOtherField:
if field_data != all_data[self.other]: if field_data != all_data[self.other]:
raise ValidationError, self.error_message raise ValidationError, self.error_message
class ValidateIfOtherFieldEquals: class ValidateIfOtherFieldEquals(object):
def __init__(self, other_field, other_value, validator_list): def __init__(self, other_field, other_value, validator_list):
self.other_field, self.other_value = other_field, other_value self.other_field, self.other_value = other_field, other_value
self.validator_list = validator_list self.validator_list = validator_list
@ -258,7 +258,7 @@ class ValidateIfOtherFieldEquals:
for v in self.validator_list: for v in self.validator_list:
v(field_data, all_data) v(field_data, all_data)
class RequiredIfOtherFieldNotGiven: class RequiredIfOtherFieldNotGiven(object):
def __init__(self, other_field_name, error_message=gettext_lazy("Please enter something for at least one field.")): def __init__(self, other_field_name, error_message=gettext_lazy("Please enter something for at least one field.")):
self.other, self.error_message = other_field_name, error_message self.other, self.error_message = other_field_name, error_message
self.always_test = True self.always_test = True
@ -267,7 +267,7 @@ class RequiredIfOtherFieldNotGiven:
if not all_data.get(self.other, False) and not field_data: if not all_data.get(self.other, False) and not field_data:
raise ValidationError, self.error_message raise ValidationError, self.error_message
class RequiredIfOtherFieldsGiven: class RequiredIfOtherFieldsGiven(object):
def __init__(self, other_field_names, error_message=gettext_lazy("Please enter both fields or leave them both empty.")): def __init__(self, other_field_names, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
self.other, self.error_message = other_field_names, error_message self.other, self.error_message = other_field_names, error_message
self.always_test = True self.always_test = True
@ -282,7 +282,7 @@ class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven):
def __init__(self, other_field_name, error_message=gettext_lazy("Please enter both fields or leave them both empty.")): def __init__(self, other_field_name, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message) RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)
class RequiredIfOtherFieldEquals: class RequiredIfOtherFieldEquals(object):
def __init__(self, other_field, other_value, error_message=None): def __init__(self, other_field, other_value, error_message=None):
self.other_field = other_field self.other_field = other_field
self.other_value = other_value self.other_value = other_value
@ -294,7 +294,7 @@ class RequiredIfOtherFieldEquals:
if all_data.has_key(self.other_field) and all_data[self.other_field] == self.other_value and not field_data: if all_data.has_key(self.other_field) and all_data[self.other_field] == self.other_value and not field_data:
raise ValidationError(self.error_message) raise ValidationError(self.error_message)
class RequiredIfOtherFieldDoesNotEqual: class RequiredIfOtherFieldDoesNotEqual(object):
def __init__(self, other_field, other_value, error_message=None): def __init__(self, other_field, other_value, error_message=None):
self.other_field = other_field self.other_field = other_field
self.other_value = other_value self.other_value = other_value
@ -306,7 +306,7 @@ class RequiredIfOtherFieldDoesNotEqual:
if all_data.has_key(self.other_field) and all_data[self.other_field] != self.other_value and not field_data: if all_data.has_key(self.other_field) and all_data[self.other_field] != self.other_value and not field_data:
raise ValidationError(self.error_message) raise ValidationError(self.error_message)
class IsLessThanOtherField: class IsLessThanOtherField(object):
def __init__(self, other_field_name, error_message): def __init__(self, other_field_name, error_message):
self.other, self.error_message = other_field_name, error_message self.other, self.error_message = other_field_name, error_message
@ -314,7 +314,7 @@ class IsLessThanOtherField:
if field_data > all_data[self.other]: if field_data > all_data[self.other]:
raise ValidationError, self.error_message raise ValidationError, self.error_message
class UniqueAmongstFieldsWithPrefix: class UniqueAmongstFieldsWithPrefix(object):
def __init__(self, field_name, prefix, error_message): def __init__(self, field_name, prefix, error_message):
self.field_name, self.prefix = field_name, prefix self.field_name, self.prefix = field_name, prefix
self.error_message = error_message or gettext_lazy("Duplicate values are not allowed.") self.error_message = error_message or gettext_lazy("Duplicate values are not allowed.")
@ -324,7 +324,7 @@ class UniqueAmongstFieldsWithPrefix:
if field_name != self.field_name and value == field_data: if field_name != self.field_name and value == field_data:
raise ValidationError, self.error_message raise ValidationError, self.error_message
class IsAPowerOf: class IsAPowerOf(object):
""" """
>>> v = IsAPowerOf(2) >>> v = IsAPowerOf(2)
>>> v(4, None) >>> v(4, None)
@ -342,7 +342,7 @@ class IsAPowerOf:
if val != int(val): if val != int(val):
raise ValidationError, gettext("This value must be a power of %s.") % self.power_of raise ValidationError, gettext("This value must be a power of %s.") % self.power_of
class IsValidFloat: class IsValidFloat(object):
def __init__(self, max_digits, decimal_places): def __init__(self, max_digits, decimal_places):
self.max_digits, self.decimal_places = max_digits, decimal_places self.max_digits, self.decimal_places = max_digits, decimal_places
@ -355,11 +355,14 @@ class IsValidFloat:
if len(data) > (self.max_digits + 1): if len(data) > (self.max_digits + 1):
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.", raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
if (not '.' in data and len(data) > (self.max_digits - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
if '.' in data and len(data.split('.')[1]) > self.decimal_places: if '.' in data and len(data.split('.')[1]) > self.decimal_places:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.", raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
"Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
class HasAllowableSize: class HasAllowableSize(object):
""" """
Checks that the file-upload field data is a certain size. min_size and Checks that the file-upload field data is a certain size. min_size and
max_size are measurements in bytes. max_size are measurements in bytes.
@ -379,7 +382,7 @@ class HasAllowableSize:
if self.max_size is not None and len(content) > self.max_size: if self.max_size is not None and len(content) > self.max_size:
raise ValidationError, self.max_error_message raise ValidationError, self.max_error_message
class MatchesRegularExpression: class MatchesRegularExpression(object):
""" """
Checks that the field matches the given regular-expression. The regex Checks that the field matches the given regular-expression. The regex
should be in string format, not already compiled. should be in string format, not already compiled.
@ -392,7 +395,7 @@ class MatchesRegularExpression:
if not self.regexp.search(field_data): if not self.regexp.search(field_data):
raise ValidationError(self.error_message) raise ValidationError(self.error_message)
class AnyValidator: class AnyValidator(object):
""" """
This validator tries all given validators. If any one of them succeeds, This validator tries all given validators. If any one of them succeeds,
validation passes. If none of them succeeds, the given message is thrown validation passes. If none of them succeeds, the given message is thrown
@ -416,7 +419,7 @@ class AnyValidator:
pass pass
raise ValidationError(self.error_message) raise ValidationError(self.error_message)
class URLMimeTypeCheck: class URLMimeTypeCheck(object):
"Checks that the provided URL points to a document with a listed mime type" "Checks that the provided URL points to a document with a listed mime type"
class CouldNotRetrieve(ValidationError): class CouldNotRetrieve(ValidationError):
pass pass
@ -441,7 +444,7 @@ class URLMimeTypeCheck:
raise URLMimeTypeCheck.InvalidContentType, gettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { raise URLMimeTypeCheck.InvalidContentType, gettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
'url': field_data, 'contenttype': content_type} 'url': field_data, 'contenttype': content_type}
class RelaxNGCompact: class RelaxNGCompact(object):
"Validate against a Relax NG compact schema" "Validate against a Relax NG compact schema"
def __init__(self, schema_path, additional_root_element=None): def __init__(self, schema_path, additional_root_element=None):
self.schema_path = schema_path self.schema_path = schema_path

View File

@ -131,6 +131,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "DROP CONSTRAINT" return "DROP CONSTRAINT"
def get_pk_default_value():
return "DEFAULT"
OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'LIKE %s', 'iexact': 'LIKE %s',

View File

@ -158,6 +158,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "DROP FOREIGN KEY" return "DROP FOREIGN KEY"
def get_pk_default_value():
return "DEFAULT"
OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'LIKE %s', 'iexact': 'LIKE %s',

View File

@ -114,6 +114,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "DROP FOREIGN KEY" return "DROP FOREIGN KEY"
def get_pk_default_value():
return "DEFAULT"
OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'LIKE %s', 'iexact': 'LIKE %s',

View File

@ -108,6 +108,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "DROP CONSTRAINT" return "DROP CONSTRAINT"
def get_pk_default_value():
return "DEFAULT"
# Register these custom typecasts, because Django expects dates/times to be # Register these custom typecasts, because Django expects dates/times to be
# in Python's native (standard-library) datetime/time format, whereas psycopg # in Python's native (standard-library) datetime/time format, whereas psycopg
# use mx.DateTime by default. # use mx.DateTime by default.

View File

@ -114,6 +114,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "DROP CONSTRAINT" return "DROP CONSTRAINT"
def get_pk_default_value():
return "DEFAULT"
OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'ILIKE %s', 'iexact': 'ILIKE %s',

View File

@ -130,6 +130,9 @@ def get_fulltext_search_sql(field_name):
def get_drop_foreignkey_sql(): def get_drop_foreignkey_sql():
return "" return ""
def get_pk_default_value():
return "NULL"
def _sqlite_date_trunc(lookup_type, dt): def _sqlite_date_trunc(lookup_type, dt):
try: try:
dt = util.typecast_timestamp(dt) dt = util.typecast_timestamp(dt)

View File

@ -1,7 +1,7 @@
import datetime import datetime
from time import time from time import time
class CursorDebugWrapper: class CursorDebugWrapper(object):
def __init__(self, cursor, db): def __init__(self, cursor, db):
self.cursor = cursor self.cursor = cursor
self.db = db self.db = db

View File

@ -8,6 +8,7 @@ from django.db.models.manager import Manager
from django.db.models.base import Model, AdminOptions from django.db.models.base import Model, AdminOptions
from django.db.models.fields import * from django.db.models.fields import *
from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED
from django.db.models.fields.generic import GenericRelation, GenericRel, GenericForeignKey
from django.db.models import signals from django.db.models import signals
from django.utils.functional import curry from django.utils.functional import curry
from django.utils.text import capfirst from django.utils.text import capfirst
@ -15,7 +16,7 @@ from django.utils.text import capfirst
# Admin stages. # Admin stages.
ADD, CHANGE, BOTH = 1, 2, 3 ADD, CHANGE, BOTH = 1, 2, 3
class LazyDate: class LazyDate(object):
""" """
Use in limit_choices_to to compare the field to dates calculated at run time Use in limit_choices_to to compare the field to dates calculated at run time
instead of when the model is loaded. For example:: instead of when the model is loaded. For example::

View File

@ -107,6 +107,12 @@ class Model(object):
else: else:
val = kwargs.pop(f.attname, f.get_default()) val = kwargs.pop(f.attname, f.get_default())
setattr(self, f.attname, val) setattr(self, f.attname, val)
for prop in kwargs.keys():
try:
if isinstance(getattr(self.__class__, prop), property):
setattr(self, prop, kwargs.pop(prop))
except AttributeError:
pass
if kwargs: if kwargs:
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
for i, arg in enumerate(args): for i, arg in enumerate(args):
@ -165,7 +171,7 @@ class Model(object):
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table), (backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.attname)), backend.quote_name(self._meta.pk.column)),
db_values + [pk_val]) db_values + [pk_val])
else: else:
record_exists = False record_exists = False
@ -183,9 +189,16 @@ class Model(object):
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \ placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
(backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ if db_values:
(backend.quote_name(self._meta.db_table), ','.join(field_names), cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
','.join(placeholders)), db_values) (backend.quote_name(self._meta.db_table), ','.join(field_names),
','.join(placeholders)), db_values)
else:
# Create a new record with defaults for everything.
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
(backend.quote_name(self._meta.db_table),
backend.quote_name(self._meta.pk.column),
backend.get_pk_default_value()))
if self._meta.has_auto_field and not pk_set: if self._meta.has_auto_field and not pk_set:
setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
transaction.commit_unless_managed() transaction.commit_unless_managed()

View File

@ -535,7 +535,7 @@ class FileField(Field):
if not self.blank: if not self.blank:
if rel: if rel:
# This validator makes sure FileFields work in a related context. # This validator makes sure FileFields work in a related context.
class RequiredFileField: class RequiredFileField(object):
def __init__(self, other_field_names, other_file_field_name): def __init__(self, other_field_names, other_file_field_name):
self.other_field_names = other_field_names self.other_field_names = other_field_names
self.other_file_field_name = other_file_field_name self.other_file_field_name = other_file_field_name

View File

@ -0,0 +1,259 @@
"""
Classes allowing "generic" relations through ContentType and object-id fields.
"""
from django import forms
from django.core.exceptions import ObjectDoesNotExist
from django.db import backend
from django.db.models import signals
from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
from django.db.models.loading import get_model
from django.dispatch import dispatcher
from django.utils.functional import curry
class GenericForeignKey(object):
"""
Provides a generic relation to any object through content-type/object-id
fields.
"""
def __init__(self, ct_field="content_type", fk_field="object_id"):
self.ct_field = ct_field
self.fk_field = fk_field
def contribute_to_class(self, cls, name):
# Make sure the fields exist (these raise FieldDoesNotExist,
# which is a fine error to raise here)
self.name = name
self.model = cls
self.cache_attr = "_%s_cache" % name
# For some reason I don't totally understand, using weakrefs here doesn't work.
dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False)
# Connect myself as the descriptor for this field
setattr(cls, name, self)
def instance_pre_init(self, signal, sender, args, kwargs):
# Handle initalizing an object with the generic FK instaed of
# content-type/object-id fields.
if kwargs.has_key(self.name):
value = kwargs.pop(self.name)
kwargs[self.ct_field] = self.get_content_type(value)
kwargs[self.fk_field] = value._get_pk_val()
def get_content_type(self, obj):
# Convenience function using get_model avoids a circular import when using this model
ContentType = get_model("contenttypes", "contenttype")
return ContentType.objects.get_for_model(obj)
def __get__(self, instance, instance_type=None):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self.name
try:
return getattr(instance, self.cache_attr)
except AttributeError:
rel_obj = None
ct = getattr(instance, self.ct_field)
if ct:
try:
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
except ObjectDoesNotExist:
pass
setattr(instance, self.cache_attr, rel_obj)
return rel_obj
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
ct = None
fk = None
if value is not None:
ct = self.get_content_type(value)
fk = value._get_pk_val()
setattr(instance, self.ct_field, ct)
setattr(instance, self.fk_field, fk)
setattr(instance, self.cache_attr, value)
class GenericRelation(RelatedField, Field):
"""Provides an accessor to generic related objects (i.e. comments)"""
def __init__(self, to, **kwargs):
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
kwargs['rel'] = GenericRel(to,
related_name=kwargs.pop('related_name', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
symmetrical=kwargs.pop('symmetrical', True))
# Override content-type/object-id field names on the related class
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
kwargs['blank'] = True
kwargs['editable'] = False
Field.__init__(self, **kwargs)
def get_manipulator_field_objs(self):
choices = self.get_choices_default()
return [curry(forms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
def get_choices_default(self):
return Field.get_choices(self, include_blank=False)
def flatten_data(self, follow, obj = None):
new_data = {}
if obj:
instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]
new_data[self.name] = instance_ids
return new_data
def m2m_db_table(self):
return self.rel.to._meta.db_table
def m2m_column_name(self):
return self.object_id_field_name
def m2m_reverse_name(self):
return self.model._meta.pk.attname
def contribute_to_class(self, cls, name):
super(GenericRelation, self).contribute_to_class(cls, name)
# Save a reference to which model this class is on for future use
self.model = cls
# Add the descriptor for the m2m relation
setattr(cls, self.name, ReverseGenericRelatedObjectsDescriptor(self))
def contribute_to_related_class(self, cls, related):
pass
def set_attributes_from_rel(self):
pass
def get_internal_type(self):
return "ManyToManyField"
class ReverseGenericRelatedObjectsDescriptor(object):
"""
This class provides the functionality that makes the related-object
managers available as attributes on a model class, for fields that have
multiple "remote" values and have a GenericRelation defined in their model
(rather than having another model pointed *at* them). In the example
"article.publications", the publications attribute is a
ReverseGenericRelatedObjectsDescriptor instance.
"""
def __init__(self, field):
self.field = field
def __get__(self, instance, instance_type=None):
if instance is None:
raise AttributeError, "Manager must be accessed via instance"
# This import is done here to avoid circular import importing this module
from django.contrib.contenttypes.models import ContentType
# Dynamically create a class that subclasses the related model's
# default manager.
rel_model = self.field.rel.to
superclass = rel_model._default_manager.__class__
RelatedManager = create_generic_related_manager(superclass)
manager = RelatedManager(
model = rel_model,
instance = instance,
symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model),
join_table = backend.quote_name(self.field.m2m_db_table()),
source_col_name = backend.quote_name(self.field.m2m_column_name()),
target_col_name = backend.quote_name(self.field.m2m_reverse_name()),
content_type = ContentType.objects.get_for_model(self.field.model),
content_type_field_name = self.field.content_type_field_name,
object_id_field_name = self.field.object_id_field_name
)
return manager
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "Manager must be accessed via instance"
manager = self.__get__(instance)
manager.clear()
for obj in value:
manager.add(obj)
def create_generic_related_manager(superclass):
"""
Factory function for a manager that subclasses 'superclass' (which is a
Manager) and adds behavior for generic related objects.
"""
class GenericRelatedObjectManager(superclass):
def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
join_table=None, source_col_name=None, target_col_name=None, content_type=None,
content_type_field_name=None, object_id_field_name=None):
super(GenericRelatedObjectManager, self).__init__()
self.core_filters = core_filters or {}
self.model = model
self.content_type = content_type
self.symmetrical = symmetrical
self.instance = instance
self.join_table = join_table
self.join_table = model._meta.db_table
self.source_col_name = source_col_name
self.target_col_name = target_col_name
self.content_type_field_name = content_type_field_name
self.object_id_field_name = object_id_field_name
self.pk_val = self.instance._get_pk_val()
def get_query_set(self):
query = {
'%s__pk' % self.content_type_field_name : self.content_type.id,
'%s__exact' % self.object_id_field_name : self.pk_val,
}
return superclass.get_query_set(self).filter(**query)
def add(self, *objs):
for obj in objs:
setattr(obj, self.content_type_field_name, self.content_type)
setattr(obj, self.object_id_field_name, self.pk_val)
obj.save()
add.alters_data = True
def remove(self, *objs):
for obj in objs:
obj.delete()
remove.alters_data = True
def clear(self):
for obj in self.all():
obj.delete()
clear.alters_data = True
def create(self, **kwargs):
kwargs[self.content_type_field_name] = self.content_type
kwargs[self.object_id_field_name] = self.pk_val
obj = self.model(**kwargs)
obj.save()
return obj
create.alters_data = True
return GenericRelatedObjectManager
class GenericRel(ManyToManyRel):
def __init__(self, to, related_name=None, limit_choices_to=None, symmetrical=True):
self.to = to
self.num_in_admin = 0
self.related_name = related_name
self.filter_interface = None
self.limit_choices_to = limit_choices_to or {}
self.edit_inline = False
self.raw_id_admin = False
self.symmetrical = symmetrical
self.multiple = True
assert not (self.raw_id_admin and self.filter_interface), \
"Generic relations may not use both raw_id_admin and filter_interface"

View File

@ -667,7 +667,7 @@ class ManyToManyField(RelatedField, Field):
def set_attributes_from_rel(self): def set_attributes_from_rel(self):
pass pass
class ManyToOneRel: class ManyToOneRel(object):
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False): related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
@ -704,7 +704,7 @@ class OneToOneRel(ManyToOneRel):
self.raw_id_admin = raw_id_admin self.raw_id_admin = raw_id_admin
self.multiple = False self.multiple = False
class ManyToManyRel: class ManyToManyRel(object):
def __init__(self, to, num_in_admin=0, related_name=None, def __init__(self, to, num_in_admin=0, related_name=None,
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True): filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
self.to = to self.to = to

View File

@ -3,6 +3,7 @@ from django.db import backend, connection
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.db.models import signals from django.db.models import signals
from django.db.models.fields import FieldDoesNotExist
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
# Size of each "chunk" for get_iterator calls. # Size of each "chunk" for get_iterator calls.
@ -13,8 +14,11 @@ def ensure_default_manager(sender):
cls = sender cls = sender
if not hasattr(cls, '_default_manager'): if not hasattr(cls, '_default_manager'):
# Create the default manager, if needed. # Create the default manager, if needed.
if hasattr(cls, 'objects'): try:
raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name cls._meta.get_field('objects')
raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % cls.__name__
except FieldDoesNotExist:
pass
cls.add_to_class('objects', Manager()) cls.add_to_class('objects', Manager())
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared) dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
@ -65,6 +69,9 @@ class Manager(object):
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
return self.get_query_set().get(*args, **kwargs) return self.get_query_set().get(*args, **kwargs)
def get_or_create(self, *args, **kwargs):
return self.get_query_set().get_or_create(*args, **kwargs)
def filter(self, *args, **kwargs): def filter(self, *args, **kwargs):
return self.get_query_set().filter(*args, **kwargs) return self.get_query_set().filter(*args, **kwargs)

View File

@ -15,7 +15,7 @@ DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
'unique_together', 'permissions', 'get_latest_by', 'unique_together', 'permissions', 'get_latest_by',
'order_with_respect_to', 'app_label') 'order_with_respect_to', 'app_label')
class Options: class Options(object):
def __init__(self, meta): def __init__(self, meta):
self.fields, self.many_to_many = [], [] self.fields, self.many_to_many = [], []
self.module_name, self.verbose_name = None, None self.module_name, self.verbose_name = None, None
@ -195,7 +195,7 @@ class Options:
self._field_types[field_type] = False self._field_types[field_type] = False
return self._field_types[field_type] return self._field_types[field_type]
class AdminOptions: class AdminOptions(object):
def __init__(self, fields=None, js=None, list_display=None, list_filter=None, def __init__(self, fields=None, js=None, list_display=None, list_filter=None,
date_hierarchy=None, save_as=False, ordering=None, search_fields=None, date_hierarchy=None, save_as=False, ordering=None, search_fields=None,
save_on_top=False, list_select_related=False, manager=None, list_per_page=100): save_on_top=False, list_select_related=False, manager=None, list_per_page=100):

View File

@ -205,6 +205,23 @@ class QuerySet(object):
assert len(obj_list) == 1, "get() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.model._meta.object_name, len(obj_list), kwargs) assert len(obj_list) == 1, "get() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.model._meta.object_name, len(obj_list), kwargs)
return obj_list[0] return obj_list[0]
def get_or_create(self, **kwargs):
"""
Looks up an object with the given kwargs, creating one if necessary.
Returns a tuple of (object, created), where created is a boolean
specifying whether an object was created.
"""
assert len(kwargs), 'get_or_create() must be passed at least one keyword argument'
defaults = kwargs.pop('defaults', {})
try:
return self.get(**kwargs), False
except self.model.DoesNotExist:
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()
return obj, True
def latest(self, field_name=None): def latest(self, field_name=None):
""" """
Returns the latest object, according to the model's 'get_latest_by' Returns the latest object, according to the model's 'get_latest_by'
@ -529,7 +546,7 @@ class DateQuerySet(QuerySet):
c._order = self._order c._order = self._order
return c return c
class QOperator: class QOperator(object):
"Base class for QAnd and QOr" "Base class for QAnd and QOr"
def __init__(self, *args): def __init__(self, *args):
self.args = args self.args = args

View File

@ -114,7 +114,7 @@ def is_managed():
def managed(flag=True): def managed(flag=True):
""" """
Puts the transaction manager into a manual state: managed transactions have Puts the transaction manager into a manual state: managed transactions have
to be committed explicitely by the user. If you switch off transaction to be committed explicitly by the user. If you switch off transaction
management and there is a pending commit/rollback, the data will be management and there is a pending commit/rollback, the data will be
commited. commited.
""" """

View File

@ -101,7 +101,7 @@ class Manipulator(object):
for field in self.fields: for field in self.fields:
field.convert_post_data(new_data) field.convert_post_data(new_data)
class FormWrapper: class FormWrapper(object):
""" """
A wrapper linking a Manipulator to the template system. A wrapper linking a Manipulator to the template system.
This allows dictionary-style lookups of formfields. It also handles feeding This allows dictionary-style lookups of formfields. It also handles feeding
@ -150,7 +150,7 @@ class FormWrapper:
fields = property(_get_fields) fields = property(_get_fields)
class FormFieldWrapper: class FormFieldWrapper(object):
"A bridge between the template system and an individual form field. Used by FormWrapper." "A bridge between the template system and an individual form field. Used by FormWrapper."
def __init__(self, formfield, data, error_list): def __init__(self, formfield, data, error_list):
self.formfield, self.data, self.error_list = formfield, data, error_list self.formfield, self.data, self.error_list = formfield, data, error_list
@ -211,7 +211,7 @@ class FormFieldCollection(FormFieldWrapper):
def html_combined_error_list(self): def html_combined_error_list(self):
return ''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')]) return ''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')])
class InlineObjectCollection: class InlineObjectCollection(object):
"An object that acts like a sparse list of form field collections." "An object that acts like a sparse list of form field collections."
def __init__(self, parent_manipulator, rel_obj, data, errors): def __init__(self, parent_manipulator, rel_obj, data, errors):
self.parent_manipulator = parent_manipulator self.parent_manipulator = parent_manipulator
@ -269,7 +269,7 @@ class InlineObjectCollection:
self._collections = collections self._collections = collections
class FormField: class FormField(object):
"""Abstract class representing a form field. """Abstract class representing a form field.
Classes that extend FormField should define the following attributes: Classes that extend FormField should define the following attributes:
@ -613,9 +613,10 @@ class CheckboxSelectMultipleField(SelectMultipleField):
back into the single list that validators, renderers and save() expect. back into the single list that validators, renderers and save() expect.
""" """
requires_data_list = True requires_data_list = True
def __init__(self, field_name, choices=None, validator_list=None): def __init__(self, field_name, choices=None, ul_class='', validator_list=None):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
if choices is None: choices = [] if choices is None: choices = []
self.ul_class = ul_class
SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list) SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list)
def prepare(self, new_data): def prepare(self, new_data):
@ -628,7 +629,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
new_data.setlist(self.field_name, data_list) new_data.setlist(self.field_name, data_list)
def render(self, data): def render(self, data):
output = ['<ul>'] output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')]
str_data_list = map(str, data) # normalize to strings str_data_list = map(str, data) # normalize to strings
for value, choice in self.choices: for value, choice in self.choices:
checked_html = '' checked_html = ''
@ -897,10 +898,11 @@ class FilePathField(SelectField):
"A SelectField whose choices are the files in a given directory." "A SelectField whose choices are the files in a given directory."
def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None): def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None):
import os import os
from django.db.models import BLANK_CHOICE_DASH
if match is not None: if match is not None:
import re import re
match_re = re.compile(match) match_re = re.compile(match)
choices = [] choices = not is_required and BLANK_CHOICE_DASH[:] or []
if recursive: if recursive:
for root, dirs, files in os.walk(path): for root, dirs, files in os.walk(path):
for f in files: for f in files:

View File

@ -265,6 +265,12 @@ class HttpResponseForbidden(HttpResponse):
HttpResponse.__init__(self, *args, **kwargs) HttpResponse.__init__(self, *args, **kwargs)
self.status_code = 403 self.status_code = 403
class HttpResponseNotAllowed(HttpResponse):
def __init__(self, permitted_methods):
HttpResponse.__init__(self)
self['Allow'] = ', '.join(permitted_methods)
self.status_code = 405
class HttpResponseGone(HttpResponse): class HttpResponseGone(HttpResponse):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
HttpResponse.__init__(self, *args, **kwargs) HttpResponse.__init__(self, *args, **kwargs)

View File

@ -3,7 +3,7 @@ from django.core.cache import cache
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers
from django.http import HttpResponseNotModified from django.http import HttpResponseNotModified
class CacheMiddleware: class CacheMiddleware(object):
""" """
Cache middleware. If this is enabled, each Django-powered page will be Cache middleware. If this is enabled, each Django-powered page will be
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs. cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs.

View File

@ -3,7 +3,7 @@ from django import http
from django.core.mail import mail_managers from django.core.mail import mail_managers
import md5, os import md5, os
class CommonMiddleware: class CommonMiddleware(object):
""" """
"Common" middleware for taking care of some basic operations: "Common" middleware for taking care of some basic operations:
@ -39,6 +39,8 @@ class CommonMiddleware:
# trailing slash or a file extension. # trailing slash or a file extension.
if settings.APPEND_SLASH and (old_url[1][-1] != '/') and ('.' not in old_url[1].split('/')[-1]): if settings.APPEND_SLASH and (old_url[1][-1] != '/') and ('.' not in old_url[1].split('/')[-1]):
new_url[1] = new_url[1] + '/' new_url[1] = new_url[1] + '/'
if settings.DEBUG and request.META['REQUEST_METHOD'].lower() == 'post':
raise RuntimeError, "You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to %s%s (note the trailing slash), or set APPEND_SLASH=False in your Django settings." % (new_url[0], new_url[1])
if new_url != old_url: if new_url != old_url:
# Redirect # Redirect
if new_url[0]: if new_url[0]:

View File

@ -1,7 +1,7 @@
from django.conf import settings from django.conf import settings
from django import http from django import http
class XViewMiddleware: class XViewMiddleware(object):
""" """
Adds an X-View header to internal HEAD requests -- used by the documentation system. Adds an X-View header to internal HEAD requests -- used by the documentation system.
""" """

View File

@ -4,7 +4,7 @@ from django.utils.cache import patch_vary_headers
re_accepts_gzip = re.compile(r'\bgzip\b') re_accepts_gzip = re.compile(r'\bgzip\b')
class GZipMiddleware: class GZipMiddleware(object):
""" """
This middleware compresses content if the browser allows gzip compression. This middleware compresses content if the browser allows gzip compression.
It sets the Vary header accordingly, so that caches will base their storage It sets the Vary header accordingly, so that caches will base their storage

View File

@ -1,6 +1,6 @@
import datetime import datetime
class ConditionalGetMiddleware: class ConditionalGetMiddleware(object):
""" """
Handles conditional GET operations. If the response has a ETag or Handles conditional GET operations. If the response has a ETag or
Last-Modified header, and the request has If-None-Match or Last-Modified header, and the request has If-None-Match or

View File

@ -3,7 +3,7 @@
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils import translation from django.utils import translation
class LocaleMiddleware: class LocaleMiddleware(object):
""" """
This is a very simple middleware that parses a request This is a very simple middleware that parses a request
and decides what translation object to install in the current and decides what translation object to install in the current

View File

@ -1,7 +1,7 @@
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
class TransactionMiddleware: class TransactionMiddleware(object):
""" """
Transaction middleware. If this is enabled, each view function will be run Transaction middleware. If this is enabled, each view function will be run
with commit_on_response activated - that way a save() doesn't do a direct with commit_on_response activated - that way a save() doesn't do a direct

View File

@ -56,9 +56,10 @@ times with multiple contexts)
""" """
import re import re
from inspect import getargspec from inspect import getargspec
from django.utils.functional import curry
from django.conf import settings from django.conf import settings
from django.template.context import Context, RequestContext, ContextPopException from django.template.context import Context, RequestContext, ContextPopException
from django.utils.functional import curry
from django.utils.text import smart_split
__all__ = ('Template', 'Context', 'RequestContext', 'compile_string') __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@ -74,6 +75,8 @@ BLOCK_TAG_START = '{%'
BLOCK_TAG_END = '%}' BLOCK_TAG_END = '%}'
VARIABLE_TAG_START = '{{' VARIABLE_TAG_START = '{{'
VARIABLE_TAG_END = '}}' VARIABLE_TAG_END = '}}'
SINGLE_BRACE_START = '{'
SINGLE_BRACE_END = '}'
ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.' ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
@ -133,7 +136,7 @@ class StringOrigin(Origin):
def reload(self): def reload(self):
return self.source return self.source
class Template: class Template(object):
def __init__(self, template_string, origin=None): def __init__(self, template_string, origin=None):
"Compilation stage" "Compilation stage"
if settings.TEMPLATE_DEBUG and origin == None: if settings.TEMPLATE_DEBUG and origin == None:
@ -157,22 +160,18 @@ def compile_string(template_string, origin):
parser = parser_factory(lexer.tokenize()) parser = parser_factory(lexer.tokenize())
return parser.parse() return parser.parse()
class Token: class Token(object):
def __init__(self, token_type, contents): def __init__(self, token_type, contents):
"The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK" "The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK"
self.token_type, self.contents = token_type, contents self.token_type, self.contents = token_type, contents
def __str__(self): def __str__(self):
return '<%s token: "%s...">' % ( return '<%s token: "%s...">' % \
{TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type], ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
self.contents[:20].replace('\n', '') self.contents[:20].replace('\n', ''))
)
def __repr__(self): def split_contents(self):
return '<%s token: "%s">' % ( return smart_split(self.contents)
{TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
self.contents[:].replace('\n', '')
)
class Lexer(object): class Lexer(object):
def __init__(self, template_string, origin): def __init__(self, template_string, origin):
@ -367,7 +366,6 @@ class DebugParser(Parser):
if not hasattr(e, 'source'): if not hasattr(e, 'source'):
e.source = token.source e.source = token.source
def lexer_factory(*args, **kwargs): def lexer_factory(*args, **kwargs):
if settings.TEMPLATE_DEBUG: if settings.TEMPLATE_DEBUG:
return DebugLexer(*args, **kwargs) return DebugLexer(*args, **kwargs)
@ -380,8 +378,7 @@ def parser_factory(*args, **kwargs):
else: else:
return Parser(*args, **kwargs) return Parser(*args, **kwargs)
class TokenParser(object):
class TokenParser:
""" """
Subclass this and implement the top() method to parse a template line. When Subclass this and implement the top() method to parse a template line. When
instantiating the parser, pass in the line from the Django template parser. instantiating the parser, pass in the line from the Django template parser.
@ -544,7 +541,7 @@ class FilterExpression(object):
upto = match.end() upto = match.end()
if upto != len(token): if upto != len(token):
raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:]
self.var , self.filters = var, filters self.var, self.filters = var, filters
def resolve(self, context): def resolve(self, context):
try: try:
@ -564,7 +561,7 @@ class FilterExpression(object):
def args_check(name, func, provided): def args_check(name, func, provided):
provided = list(provided) provided = list(provided)
plen = len(provided) plen = len(provided)
(args, varargs, varkw, defaults) = getargspec(func) args, varargs, varkw, defaults = getargspec(func)
# First argument is filter input. # First argument is filter input.
args.pop(0) args.pop(0)
if defaults: if defaults:
@ -614,7 +611,7 @@ def resolve_variable(path, context):
(The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
""" """
if path[0] in '0123456789': if path[0].isdigit():
number_type = '.' in path and float or int number_type = '.' in path and float or int
try: try:
current = number_type(path) current = number_type(path)
@ -655,11 +652,11 @@ def resolve_variable(path, context):
if getattr(e, 'silent_variable_failure', False): if getattr(e, 'silent_variable_failure', False):
current = settings.TEMPLATE_STRING_IF_INVALID current = settings.TEMPLATE_STRING_IF_INVALID
else: else:
raise raise
del bits[0] del bits[0]
return current return current
class Node: class Node(object):
def render(self, context): def render(self, context):
"Return the node rendered as a string" "Return the node rendered as a string"
pass pass
@ -820,7 +817,7 @@ class Library(object):
return func return func
def simple_tag(self,func): def simple_tag(self,func):
(params, xx, xxx, defaults) = getargspec(func) params, xx, xxx, defaults = getargspec(func)
class SimpleNode(Node): class SimpleNode(Node):
def __init__(self, vars_to_resolve): def __init__(self, vars_to_resolve):
@ -837,7 +834,7 @@ class Library(object):
def inclusion_tag(self, file_name, context_class=Context, takes_context=False): def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
def dec(func): def dec(func):
(params, xx, xxx, defaults) = getargspec(func) params, xx, xxx, defaults = getargspec(func)
if takes_context: if takes_context:
if params[0] == 'context': if params[0] == 'context':
params = params[1:] params = params[1:]

View File

@ -7,7 +7,7 @@ class ContextPopException(Exception):
"pop() has been called more times than push()" "pop() has been called more times than push()"
pass pass
class Context: class Context(object):
"A stack container for variable context" "A stack container for variable context"
def __init__(self, dict_=None): def __init__(self, dict_=None):
dict_ = dict_ or {} dict_ = dict_ or {}

View File

@ -330,6 +330,8 @@ def get_digit(value, arg):
def date(value, arg=None): def date(value, arg=None):
"Formats a date according to the given format" "Formats a date according to the given format"
from django.utils.dateformat import format from django.utils.dateformat import format
if not value:
return ''
if arg is None: if arg is None:
arg = settings.DATE_FORMAT arg = settings.DATE_FORMAT
return format(value, arg) return format(value, arg)
@ -337,6 +339,8 @@ def date(value, arg=None):
def time(value, arg=None): def time(value, arg=None):
"Formats a time according to the given format" "Formats a time according to the given format"
from django.utils.dateformat import time_format from django.utils.dateformat import time_format
if not value:
return ''
if arg is None: if arg is None:
arg = settings.TIME_FORMAT arg = settings.TIME_FORMAT
return time_format(value, arg) return time_format(value, arg)
@ -344,6 +348,8 @@ def time(value, arg=None):
def timesince(value): def timesince(value):
'Formats a date as the time since that date (i.e. "4 days, 6 hours")' 'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
from django.utils.timesince import timesince from django.utils.timesince import timesince
if not value:
return ''
return timesince(value) return timesince(value)
################### ###################

View File

@ -1,7 +1,7 @@
"Default tags used by the template system, available to all templates." "Default tags used by the template system, available to all templates."
from django.template import Node, NodeList, Template, Context, resolve_variable from django.template import Node, NodeList, Template, Context, resolve_variable
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END
from django.template import get_library, Library, InvalidTemplateLibrary from django.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings from django.conf import settings
import sys import sys
@ -149,9 +149,10 @@ class IfEqualNode(Node):
return self.nodelist_false.render(context) return self.nodelist_false.render(context)
class IfNode(Node): class IfNode(Node):
def __init__(self, bool_exprs, nodelist_true, nodelist_false): def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
self.bool_exprs = bool_exprs self.bool_exprs = bool_exprs
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.link_type = link_type
def __repr__(self): def __repr__(self):
return "<If node>" return "<If node>"
@ -171,14 +172,28 @@ class IfNode(Node):
return nodes return nodes
def render(self, context): def render(self, context):
for ifnot, bool_expr in self.bool_exprs: if self.link_type == IfNode.LinkTypes.or_:
try: for ifnot, bool_expr in self.bool_exprs:
value = bool_expr.resolve(context) try:
except VariableDoesNotExist: value = bool_expr.resolve(context)
value = None except VariableDoesNotExist:
if (value and not ifnot) or (ifnot and not value): value = None
return self.nodelist_true.render(context) if (value and not ifnot) or (ifnot and not value):
return self.nodelist_false.render(context) return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
else:
for ifnot, bool_expr in self.bool_exprs:
try:
value = bool_expr.resolve(context)
except VariableDoesNotExist:
value = None
if not ((value and not ifnot) or (ifnot and not value)):
return self.nodelist_false.render(context)
return self.nodelist_true.render(context)
class LinkTypes:
and_ = 0,
or_ = 1
class RegroupNode(Node): class RegroupNode(Node):
def __init__(self, target, expression, var_name): def __init__(self, target, expression, var_name):
@ -260,7 +275,10 @@ class TemplateTagNode(Node):
mapping = {'openblock': BLOCK_TAG_START, mapping = {'openblock': BLOCK_TAG_START,
'closeblock': BLOCK_TAG_END, 'closeblock': BLOCK_TAG_END,
'openvariable': VARIABLE_TAG_START, 'openvariable': VARIABLE_TAG_START,
'closevariable': VARIABLE_TAG_END} 'closevariable': VARIABLE_TAG_END,
'openbrace': SINGLE_BRACE_START,
'closebrace': SINGLE_BRACE_END,
}
def __init__(self, tagtype): def __init__(self, tagtype):
self.tagtype = tagtype self.tagtype = tagtype
@ -487,7 +505,7 @@ def do_ifequal(parser, token, negate):
... ...
{% endifnotequal %} {% endifnotequal %}
""" """
bits = token.contents.split() bits = list(token.split_contents())
if len(bits) != 3: if len(bits) != 3:
raise TemplateSyntaxError, "%r takes two arguments" % bits[0] raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
end_tag = 'end' + bits[0] end_tag = 'end' + bits[0]
@ -561,11 +579,22 @@ def do_if(parser, token):
if not bits: if not bits:
raise TemplateSyntaxError, "'if' statement requires at least one argument" raise TemplateSyntaxError, "'if' statement requires at least one argument"
# bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
boolpairs = ' '.join(bits).split(' or ') bitstr = ' '.join(bits)
boolpairs = bitstr.split(' and ')
boolvars = [] boolvars = []
if len(boolpairs) == 1:
link_type = IfNode.LinkTypes.or_
boolpairs = bitstr.split(' or ')
else:
link_type = IfNode.LinkTypes.and_
if ' or ' in bitstr:
raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'"
for boolpair in boolpairs: for boolpair in boolpairs:
if ' ' in boolpair: if ' ' in boolpair:
not_, boolvar = boolpair.split() try:
not_, boolvar = boolpair.split()
except ValueError:
raise TemplateSyntaxError, "'if' statement improperly formatted"
if not_ != 'not': if not_ != 'not':
raise TemplateSyntaxError, "Expected 'not' in if statement" raise TemplateSyntaxError, "Expected 'not' in if statement"
boolvars.append((True, parser.compile_filter(boolvar))) boolvars.append((True, parser.compile_filter(boolvar)))
@ -578,7 +607,7 @@ def do_if(parser, token):
parser.delete_first_token() parser.delete_first_token()
else: else:
nodelist_false = NodeList() nodelist_false = NodeList()
return IfNode(boolvars, nodelist_true, nodelist_false) return IfNode(boolvars, nodelist_true, nodelist_false, link_type)
do_if = register.tag("if", do_if) do_if = register.tag("if", do_if)
#@register.tag #@register.tag
@ -783,6 +812,8 @@ def templatetag(parser, token):
``closeblock`` ``%}`` ``closeblock`` ``%}``
``openvariable`` ``{{`` ``openvariable`` ``{{``
``closevariable`` ``}}`` ``closevariable`` ``}}``
``openbrace`` ``{``
``closebrace`` ``}``
================== ======= ================== =======
""" """
bits = token.contents.split() bits = token.contents.split()

View File

@ -1,4 +1,4 @@
class MergeDict: class MergeDict(object):
""" """
A simple class for creating new "virtual" dictionaries that actualy look A simple class for creating new "virtual" dictionaries that actualy look
up values in more than one dictionary, passed in the constructor. up values in more than one dictionary, passed in the constructor.

View File

@ -19,7 +19,7 @@ import re, time
re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])') re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
re_escaped = re.compile(r'\\(.)') re_escaped = re.compile(r'\\(.)')
class Formatter: class Formatter(object):
def format(self, formatstr): def format(self, formatstr):
pieces = [] pieces = []
for i, piece in enumerate(re_formatchars.split(formatstr)): for i, piece in enumerate(re_formatchars.split(formatstr)):

View File

@ -36,7 +36,7 @@ def get_tag_uri(url, date):
tag = re.sub('#', '/', tag) tag = re.sub('#', '/', tag)
return 'tag:' + tag return 'tag:' + tag
class SyndicationFeed: class SyndicationFeed(object):
"Base class for all syndication feeds. Subclasses should provide write()" "Base class for all syndication feeds. Subclasses should provide write()"
def __init__(self, title, link, description, language=None, author_email=None, def __init__(self, title, link, description, language=None, author_email=None,
author_name=None, author_link=None, subtitle=None, categories=None, author_name=None, author_link=None, subtitle=None, categories=None,
@ -108,7 +108,7 @@ class SyndicationFeed:
else: else:
return datetime.datetime.now() return datetime.datetime.now()
class Enclosure: class Enclosure(object):
"Represents an RSS enclosure" "Represents an RSS enclosure"
def __init__(self, url, length, mime_type): def __init__(self, url, length, mime_type):
"All args are expected to be Python Unicode objects" "All args are expected to be Python Unicode objects"
@ -126,6 +126,8 @@ class RssFeed(SyndicationFeed):
handler.addQuickElement(u"description", self.feed['description']) handler.addQuickElement(u"description", self.feed['description'])
if self.feed['language'] is not None: if self.feed['language'] is not None:
handler.addQuickElement(u"language", self.feed['language']) handler.addQuickElement(u"language", self.feed['language'])
for cat in self.feed['categories']:
handler.addQuickElement(u"category", cat)
self.write_items(handler) self.write_items(handler)
self.endChannelElement(handler) self.endChannelElement(handler)
handler.endElement(u"rss") handler.endElement(u"rss")

View File

@ -109,3 +109,21 @@ def javascript_quote(s):
s = s.replace("'", "\\'") s = s.replace("'", "\\'")
return str(ustring_re.sub(fix, s)) return str(ustring_re.sub(fix, s))
smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)')
def smart_split(text):
"""
Generator that splits a string by spaces, leaving quoted phrases together.
Supports both single and double quotes, and supports escaping quotes with
backslashes. In the output, strings will keep their initial and trailing
quote marks.
>>> list(smart_split('This is "a person\'s" test.'))
['This', 'is', '"a person\'s"', 'test.']
"""
for bit in smart_split_re.finditer(text):
bit = bit.group(0)
if bit[0] == '"':
yield '"' + bit[1:-1].replace('\\"', '"').replace('\\\\', '\\') + '"'
elif bit[0] == "'":
yield "'" + bit[1:-1].replace("\\'", "'").replace("\\\\", "\\") + "'"
else:
yield bit

View File

@ -111,6 +111,12 @@ def technical_500_response(request, exc_type, exc_value, tb):
}) })
tb = tb.tb_next tb = tb.tb_next
if not frames:
frames = [{
'filename': '&lt;unknown&gt;',
'function': '?',
'lineno': '?',
}]
t = Template(TECHNICAL_500_TEMPLATE) t = Template(TECHNICAL_500_TEMPLATE)
c = Context({ c = Context({
'exception_type': exc_type.__name__, 'exception_type': exc_type.__name__,

View File

@ -106,6 +106,8 @@ def update_object(request, model, object_id=None, slug=None,
if request.POST: if request.POST:
new_data = request.POST.copy() new_data = request.POST.copy()
if model._meta.has_field_type(FileField):
new_data.update(request.FILES)
errors = manipulator.get_validation_errors(new_data) errors = manipulator.get_validation_errors(new_data)
manipulator.do_html2python(new_data) manipulator.do_html2python(new_data)
if not errors: if not errors:

View File

@ -49,8 +49,8 @@ humanize
======== ========
A set of Django template filters useful for adding a "human touch" to data. A set of Django template filters useful for adding a "human touch" to data.
To activate these filters, add ``'django.contrib.english'`` to your To activate these filters, add ``'django.contrib.humanize'`` to your
``INSTALLED_APPS`` setting. Once you've done that, use ``{% load english %}`` ``INSTALLED_APPS`` setting. Once you've done that, use ``{% load humanize %}``
in a template, and you'll have access to these filters: in a template, and you'll have access to these filters:
apnumber apnumber

View File

@ -355,8 +355,8 @@ Here's what ``django.contrib.auth.views.login`` does::
form. form.
It's your responsibility to provide the login form in a template called It's your responsibility to provide the login form in a template called
``registration/login.html``. This template gets passed three template context ``registration/login.html`` by default. This template gets passed three
variables: template context variables:
* ``form``: A ``FormWrapper`` object representing the login form. See the * ``form``: A ``FormWrapper`` object representing the login form. See the
`forms documentation`_ for more on ``FormWrapper`` objects. `forms documentation`_ for more on ``FormWrapper`` objects.
@ -365,6 +365,13 @@ variables:
* ``site_name``: The name of the current ``Site``, according to the * ``site_name``: The name of the current ``Site``, according to the
``SITE_ID`` setting. See the `site framework docs`_. ``SITE_ID`` setting. See the `site framework docs`_.
If you'd prefer not to call the template ``registration/login.html``, you can
pass the ``template_name`` parameter via the extra arguments to the view in
your URLconf. For example, this URLconf line would use ``myapp/login.html``
instead::
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),
Here's a sample ``registration/login.html`` template you can use as a starting Here's a sample ``registration/login.html`` template you can use as a starting
point. It assumes you have a ``base.html`` template that defines a ``content`` point. It assumes you have a ``base.html`` template that defines a ``content``
block:: block::

View File

@ -559,7 +559,7 @@ following models::
# ... # ...
hometown = models.ForeignKey(City) hometown = models.ForeignKey(City)
class Book(meta.Model): class Book(models.Model):
# ... # ...
author = models.ForeignKey(Person) author = models.ForeignKey(Person)
@ -705,6 +705,64 @@ The ``DoesNotExist`` exception inherits from
except ObjectDoesNotExist: except ObjectDoesNotExist:
print "Either the entry or blog doesn't exist." print "Either the entry or blog doesn't exist."
``get_or_create(**kwargs)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A convenience method for looking up an object with the given kwargs, creating
one if necessary.
Returns a tuple of ``(object, created)``, where ``object`` is the retrieved or
created object and ``created`` is a boolean specifying whether a new object was
created.
This is meant as a shortcut to boilerplatish code and is mostly useful for
data-import scripts. For example::
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
This pattern gets quite unwieldy as the number of fields in a model goes up.
The above example can be rewritten using ``get_or_create()`` like so::
obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)})
Any keyword arguments passed to ``get_or_create()`` -- *except* an optional one
called ``defaults`` -- will be used in a ``get()`` call. If an object is found,
``get_or_create()`` returns a tuple of that object and ``False``. If an object
is *not* found, ``get_or_create()`` will instantiate and save a new object,
returning a tuple of the new object and ``True``. The new object will be
created according to this algorithm::
defaults = kwargs.pop('defaults', {})
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()
In English, that means start with any non-``'defaults'`` keyword argument that
doesn't contain a double underscore (which would indicate a non-exact lookup).
Then add the contents of ``defaults``, overriding any keys if necessary, and
use the result as the keyword arguments to the model class.
If you have a field named ``defaults`` and want to use it as an exact lookup in
``get_or_create()``, just use ``'defaults__exact'``, like so::
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
Finally, a word on using ``get_or_create()`` in Django views. As mentioned
earlier, ``get_or_create()`` is mostly useful in scripts that need to parse
data and create new records if existing ones aren't available. But if you need
to use ``get_or_create()`` in a view, please make sure to use it only in
``POST`` requests unless you have a good reason not to. ``GET`` requests
shouldn't have any effect on data; use ``POST`` whenever a request to a page
has a side effect on your data. For more, see `Safe methods`_ in the HTTP spec.
.. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
``count()`` ``count()``
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -200,6 +200,23 @@ In the meantime, though, check out this `unofficial Django screencast`_.
.. _unofficial Django screencast: http://www.throwingbeans.org/django_screencasts.html .. _unofficial Django screencast: http://www.throwingbeans.org/django_screencasts.html
Is Django a content-management-system (CMS)?
--------------------------------------------
No, Django is not a CMS, or any sort of "turnkey product" in and of itself.
It's a Web framework; it's a programming tool that lets you build Web sites.
For example, it doesn't make much sense to compare Django to something like
Drupal_, because Django is something you use to *create* things like Drupal.
Of course, Django's automatic admin site is fantastic and timesaving -- but
the admin site is one module of Django the framework. Furthermore, although
Django has special conveniences for building "CMS-y" apps, that doesn't mean
it's not just as appropriate for building "non-CMS-y" apps (whatever that
means!).
.. _Drupal: http://drupal.org/
When will you release Django 1.0? When will you release Django 1.0?
--------------------------------- ---------------------------------
@ -222,7 +239,7 @@ How can I download the Django documentation to read it offline?
--------------------------------------------------------------- ---------------------------------------------------------------
The Django docs are available in the ``docs`` directory of each Django tarball The Django docs are available in the ``docs`` directory of each Django tarball
release. These docs are in ReST (restructured text) format, and each text file release. These docs are in ReST (ReStructured Text) format, and each text file
corresponds to a Web page on the official Django site. corresponds to a Web page on the official Django site.
Because the documentation is `stored in revision control`_, you can browse Because the documentation is `stored in revision control`_, you can browse
@ -297,13 +314,16 @@ as long as that server has WSGI_ hooks. See the `server arrangements wiki page`_
How do I install mod_python on Windows? How do I install mod_python on Windows?
--------------------------------------- ---------------------------------------
* For Python 2.4, check out this `guide to mod_python & Python 2.3`_. * For Python 2.4, grab mod_python from `win32 build of mod_python for
Python 2.4`_.
* For Python 2.4, check out this `Django on Windows howto`_.
* For Python 2.3, grab mod_python from http://www.modpython.org/ and read * For Python 2.3, grab mod_python from http://www.modpython.org/ and read
`Running mod_python on Apache on Windows2000`_. `Running mod_python on Apache on Windows2000`_.
* Also, try this (not Windows-specific) `guide to getting mod_python * Also, try this (not Windows-specific) `guide to getting mod_python
working`_. working`_.
.. _`guide to mod_python & Python 2.3`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24 .. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24
.. _`Django on Windows howto`: http://thinkhole.org/wp/2006/04/03/django-on-windows-howto/
.. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f .. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html .. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html
@ -388,19 +408,12 @@ Using a ``FileField`` or an ``ImageField`` in a model takes a few steps:
If I make changes to a model, how do I update the database? If I make changes to a model, how do I update the database?
----------------------------------------------------------- -----------------------------------------------------------
If you don't mind clearing data, just pipe the output of the appropriate If you don't mind clearing data, your project's ``manage.py`` utility has an
``django-admin.py sqlreset`` command into your database's command-line utility. option to reset the SQL for a particular application::
For example::
django-admin.py sqlreset appname | psql dbname manage.py reset appname
That "psql" assumes you're using PostgreSQL. If you're using MySQL, use the This drops any tables associated with ``appname`` and recreates them.
appropriate command-line utility, ``mysql``.
``django-admin.py sqlreset`` outputs SQL that clears the app's database
table(s) and creates new ones. The above command uses a Unix pipe to send the
SQL directly to the PostgreSQL command-line utility, which accepts SQL as
input.
If you do care about deleting data, you'll have to execute the ``ALTER TABLE`` If you do care about deleting data, you'll have to execute the ``ALTER TABLE``
statements manually in your database. That's the way we've always done it, statements manually in your database. That's the way we've always done it,

View File

@ -15,6 +15,8 @@ We'll take a top-down approach to examining Django's form validation framework,
because much of the time you won't need to use the lower-level APIs. Throughout because much of the time you won't need to use the lower-level APIs. Throughout
this document, we'll be working with the following model, a "place" object:: this document, we'll be working with the following model, a "place" object::
from django.db import models
PLACE_TYPES = ( PLACE_TYPES = (
(1, 'Bar'), (1, 'Bar'),
(2, 'Restaurant'), (2, 'Restaurant'),
@ -22,13 +24,13 @@ this document, we'll be working with the following model, a "place" object::
(4, 'Secret Hideout'), (4, 'Secret Hideout'),
) )
class Place(meta.Model): class Place(models.Model):
name = meta.CharField(maxlength=100) name = models.CharField(maxlength=100)
address = meta.CharField(maxlength=100, blank=True) address = models.CharField(maxlength=100, blank=True)
city = meta.CharField(maxlength=50, blank=True) city = models.CharField(maxlength=50, blank=True)
state = meta.USStateField() state = models.USStateField()
zip_code = meta.CharField(maxlength=5, blank=True) zip_code = models.CharField(maxlength=5, blank=True)
place_type = meta.IntegerField(choices=PLACE_TYPES) place_type = models.IntegerField(choices=PLACE_TYPES)
class Admin: class Admin:
pass pass

View File

@ -133,8 +133,8 @@ For example, to translate a model's ``help_text``, do the following::
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
class MyThing(meta.Model): class MyThing(models.Model):
name = meta.CharField(help_text=gettext_lazy('This is the help text')) name = models.CharField(help_text=gettext_lazy('This is the help text'))
In this example, ``gettext_lazy()`` stores a lazy reference to the string -- In this example, ``gettext_lazy()`` stores a lazy reference to the string --
not the actual translation. The translation itself will be done when the string not the actual translation. The translation itself will be done when the string
@ -145,8 +145,8 @@ If you don't like the verbose name ``gettext_lazy``, you can just alias it as
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class MyThing(meta.Model): class MyThing(models.Model):
name = meta.CharField(help_text=_('This is the help text')) name = models.CharField(help_text=_('This is the help text'))
Always use lazy translations in `Django models`_. And it's a good idea to add Always use lazy translations in `Django models`_. And it's a good idea to add
translations for the field names and table names, too. This means writing translations for the field names and table names, too. This means writing
@ -155,8 +155,8 @@ class, though::
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class MyThing(meta.Model): class MyThing(models.Model):
name = meta.CharField(_('name'), help_text=_('This is the help text')) name = models.CharField(_('name'), help_text=_('This is the help text'))
class Meta: class Meta:
verbose_name = _('my thing') verbose_name = _('my thing')
verbose_name_plural = _('mythings') verbose_name_plural = _('mythings')
@ -230,12 +230,17 @@ Each ``RequestContext`` has access to two translation-specific variables:
language code and the second is the language name (in that language). language code and the second is the language name (in that language).
* ``LANGUAGE_CODE`` is the current user's preferred language, as a string. * ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
Example: ``en-us``. (See "How language preference is discovered", below.) Example: ``en-us``. (See "How language preference is discovered", below.)
* ``LANGUAGE_BIDI`` is the current language's direction. If True, it's a
right-to-left language, e.g: Hebrew, Arabic. If False it's a
left-to-right language, e.g: English, French, German etc.
If you don't use the ``RequestContext`` extension, you can get those values with If you don't use the ``RequestContext`` extension, you can get those values with
two tags:: three tags::
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %} {% get_available_languages as LANGUAGES %}
{% get_current_language_bidi as LANGUAGE_BIDI %}
These tags also require a ``{% load i18n %}``. These tags also require a ``{% load i18n %}``.

View File

@ -445,7 +445,8 @@ empty value. If a field has ``blank=False``, the field will be required.
``choices`` ``choices``
~~~~~~~~~~~ ~~~~~~~~~~~
A list of 2-tuples to use as choices for this field. An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this
field.
If this is given, Django's admin will use a select box instead of the If this is given, Django's admin will use a select box instead of the
standard text field and will limit choices to the choices given. standard text field and will limit choices to the choices given.
@ -481,6 +482,12 @@ or outside your model class altogether::
class Foo(models.Model): class Foo(models.Model):
gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
Finally, note that choices can be any iterable object -- not necessarily a
list or tuple. This lets you construct choices dynamically. But if you find
yourself hacking ``choices`` to be dynamic, you're probably better off using
a proper database table with a ``ForeignKey``. ``choices`` is meant for static
data that doesn't change much, if ever.
``core`` ``core``
~~~~~~~~ ~~~~~~~~
@ -1627,10 +1634,10 @@ to happen whenever you save an object. For example::
name = models.CharField(maxlength=100) name = models.CharField(maxlength=100)
tagline = models.TextField() tagline = models.TextField()
def save(self): def save(self):
do_something() do_something()
super(Blog, self).save() # Call the "real" save() method. super(Blog, self).save() # Call the "real" save() method.
do_something_else() do_something_else()
You can also prevent saving:: You can also prevent saving::
@ -1638,11 +1645,11 @@ You can also prevent saving::
name = models.CharField(maxlength=100) name = models.CharField(maxlength=100)
tagline = models.TextField() tagline = models.TextField()
def save(self): def save(self):
if self.name == "Yoko Ono's blog": if self.name == "Yoko Ono's blog":
return # Yoko shall never have her own blog! return # Yoko shall never have her own blog!
else: else:
super(Blog, self).save() # Call the "real" save() method. super(Blog, self).save() # Call the "real" save() method.
.. _database API docs: http://www.djangoproject.com/documentation/db_api/ .. _database API docs: http://www.djangoproject.com/documentation/db_api/

View File

@ -400,6 +400,10 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
``HttpResponseForbidden`` ``HttpResponseForbidden``
Acts just like ``HttpResponse`` but uses a 403 status code. Acts just like ``HttpResponse`` but uses a 403 status code.
``HttpResponseNotAllowed``
Like ``HttpResponse``, but uses a 405 status code. Takes a single,
required argument: a list of permitted methods (e.g. ``['GET', 'POST']``).
``HttpResponseGone`` ``HttpResponseGone``
Acts just like ``HttpResponse`` but uses a 410 status code. Acts just like ``HttpResponse`` but uses a 410 status code.

View File

@ -439,6 +439,23 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
author_link = 'http://www.example.com/' # Hard-coded author URL. author_link = 'http://www.example.com/' # Hard-coded author URL.
# CATEGORIES -- One of the following three is optional. The framework
# looks for them in this order. In each case, the method/attribute
# should return an iterable object that returns strings.
def categories(self, obj):
"""
Takes the object returned by get_object() and returns the feed's
categories as iterable over strings.
"""
def categories(self):
"""
Returns the feed's categories as iterable over strings.
"""
categories = ("python", "django") # Hard-coded list of categories.
# ITEMS -- One of the following three is required. The framework looks # ITEMS -- One of the following three is required. The framework looks
# for them in this order. # for them in this order.
@ -602,6 +619,25 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate. item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate.
# ITEM CATEGORIES -- It's optional to use one of these three. This is
# a hook that specifies how to get the list of categories for a given
# item. In each case, the method/attribute should return an iterable
# object that returns strings.
def item_categories(self, item):
"""
Takes an item, as returned by items(), and returns the item's
categories.
"""
def item_categories(self):
"""
Returns the categories for every item in the feed.
"""
item_categories = ("python", "django") # Hard-coded categories.
The low-level framework The low-level framework
======================= =======================

View File

@ -454,8 +454,12 @@ displayed by the ``{{ athlete_list|length }}`` variable.
As you can see, the ``if`` tag can take an option ``{% else %}`` clause that As you can see, the ``if`` tag can take an option ``{% else %}`` clause that
will be displayed if the test fails. will be displayed if the test fails.
``if`` tags may use ``or`` or ``not`` to test a number of variables or to negate ``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or
a given variable:: to negate a given variable::
{% if athlete_list and coach_list %}
Both athletes and coaches are available.
{% endif %}
{% if not athlete_list %} {% if not athlete_list %}
There are no athletes. There are no athletes.
@ -468,16 +472,24 @@ a given variable::
{% if not athlete_list or coach_list %} {% if not athlete_list or coach_list %}
There are no athletes or there are some coaches (OK, so There are no athletes or there are some coaches (OK, so
writing English translations of boolean logic sounds writing English translations of boolean logic sounds
stupid; it's not my fault). stupid; it's not our fault).
{% endif %} {% endif %}
For simplicity, ``if`` tags do not allow ``and`` clauses; use nested ``if`` {% if athlete_list and not coach_list %}
tags instead:: There are some athletes and absolutely no coaches.
{% endif %}
``if`` tags don't allow ``and`` and ``or`` clauses within the same tag, because
the order of logic would be ambiguous. For example, this is invalid::
{% if athlete_list and coach_list or cheerleader_list %}
If you need to combine ``and`` and ``or`` to do advanced logic, just use nested
``if`` tags. For example::
{% if athlete_list %} {% if athlete_list %}
{% if coach_list %} {% if coach_list or cheerleader_list %}
Number of athletes: {{ athlete_list|length }}. We have athletes, and either coaches or cheerleaders!
Number of coaches: {{ coach_list|length }}.
{% endif %} {% endif %}
{% endif %} {% endif %}
@ -754,6 +766,8 @@ The argument tells which template bit to output:
``closeblock`` ``%}`` ``closeblock`` ``%}``
``openvariable`` ``{{`` ``openvariable`` ``{{``
``closevariable`` ``}}`` ``closevariable`` ``}}``
``openbrace`` ``{``
``closebrace`` ``}``
================== ======= ================== =======
widthratio widthratio

View File

@ -502,12 +502,13 @@ Although the Django template language comes with several default tags and
filters, you might want to write your own. It's easy to do. filters, you might want to write your own. It's easy to do.
First, create a ``templatetags`` package in the appropriate Django app's First, create a ``templatetags`` package in the appropriate Django app's
package. It should be on the same level as ``models``, ``views.py``, etc. For package. It should be on the same level as ``models.py``, ``views.py``, etc. For
example:: example::
polls/ polls/
models/ models.py
templatetags/ templatetags/
views.py
Add two files to the ``templatetags`` package: an ``__init__.py`` file and a Add two files to the ``templatetags`` package: an ``__init__.py`` file and a
file that will contain your custom tag/filter definitions. The name of the file that will contain your custom tag/filter definitions. The name of the

View File

@ -8,7 +8,8 @@ this behavior by explicitly adding ``primary_key=True`` to a field.
from django.db import models from django.db import models
class Employee(models.Model): class Employee(models.Model):
employee_code = models.CharField(maxlength=10, primary_key=True) employee_code = models.CharField(maxlength=10, primary_key=True,
db_column = 'code')
first_name = models.CharField(maxlength=20) first_name = models.CharField(maxlength=20)
last_name = models.CharField(maxlength=20) last_name = models.CharField(maxlength=20)
class Meta: class Meta:

View File

View File

@ -0,0 +1,24 @@
"""
Empty model tests
These test that things behave sensibly for the rare corner-case of a model with
no fields.
"""
from django.db import models
class Empty(models.Model):
pass
API_TESTS = """
>>> m = Empty()
>>> m.id
>>> m.save()
>>> m2 = Empty()
>>> m2.save()
>>> len(Empty.objects.all())
2
>>> m.id is not None
True
"""

View File

@ -0,0 +1,108 @@
"""
33. Generic relations
Generic relations let an object have a foreign key to any object through a
content-type/object-id field. A generic foreign key can point to any object,
be it animal, vegetable, or mineral.
The cannonical example is tags (although this example implementation is *far*
from complete).
"""
from django.db import models
from django.contrib.contenttypes.models import ContentType
class TaggedItem(models.Model):
"""A tag on an item."""
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = models.GenericForeignKey()
class Meta:
ordering = ["tag"]
def __str__(self):
return self.tag
class Animal(models.Model):
common_name = models.CharField(maxlength=150)
latin_name = models.CharField(maxlength=150)
tags = models.GenericRelation(TaggedItem)
def __str__(self):
return self.common_name
class Vegetable(models.Model):
name = models.CharField(maxlength=150)
is_yucky = models.BooleanField(default=True)
tags = models.GenericRelation(TaggedItem)
def __str__(self):
return self.name
class Mineral(models.Model):
name = models.CharField(maxlength=150)
hardness = models.PositiveSmallIntegerField()
# note the lack of an explicit GenericRelation here...
def __str__(self):
return self.name
API_TESTS = """
# Create the world in 7 lines of code...
>>> lion = Animal(common_name="Lion", latin_name="Panthera leo")
>>> platypus = Animal(common_name="Platypus", latin_name="Ornithorhynchus anatinus")
>>> eggplant = Vegetable(name="Eggplant", is_yucky=True)
>>> bacon = Vegetable(name="Bacon", is_yucky=False)
>>> quartz = Mineral(name="Quartz", hardness=7)
>>> for o in (lion, platypus, eggplant, bacon, quartz):
... o.save()
# Objects with declared GenericRelations can be tagged directly -- the API
# mimics the many-to-many API
>>> lion.tags.create(tag="yellow")
<TaggedItem: yellow>
>>> lion.tags.create(tag="hairy")
<TaggedItem: hairy>
>>> bacon.tags.create(tag="fatty")
<TaggedItem: fatty>
>>> bacon.tags.create(tag="salty")
<TaggedItem: salty>
>>> lion.tags.all()
[<TaggedItem: hairy>, <TaggedItem: yellow>]
>>> bacon.tags.all()
[<TaggedItem: fatty>, <TaggedItem: salty>]
# You can easily access the content object like a foreign key
>>> t = TaggedItem.objects.get(tag="salty")
>>> t.content_object
<Vegetable: Bacon>
# Recall that the Mineral class doesn't have an explicit GenericRelation
# defined. That's OK since you can create TaggedItems explicitally.
>>> tag1 = TaggedItem(content_object=quartz, tag="shiny")
>>> tag2 = TaggedItem(content_object=quartz, tag="clearish")
>>> tag1.save()
>>> tag2.save()
# However, not having the convience takes a small toll when it comes
# to do lookups
>>> from django.contrib.contenttypes.models import ContentType
>>> ctype = ContentType.objects.get_for_model(quartz)
>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
[<TaggedItem: clearish>, <TaggedItem: shiny>]
# You can set a generic foreign key in the way you'd expect
>>> tag1.content_object = platypus
>>> tag1.save()
>>> platypus.tags.all()
[<TaggedItem: shiny>]
>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id)
[<TaggedItem: clearish>]
"""

View File

@ -0,0 +1,52 @@
"""
32. get_or_create()
get_or_create() does what it says: it tries to look up an object with the given
parameters. If an object isn't found, it creates one with the given parameters.
"""
from django.db import models
class Person(models.Model):
first_name = models.CharField(maxlength=100)
last_name = models.CharField(maxlength=100)
birthday = models.DateField()
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
API_TESTS = """
# Acting as a divine being, create an Person.
>>> from datetime import date
>>> p = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
>>> p.save()
# Only one Person is in the database at this point.
>>> Person.objects.count()
1
# get_or_create() a person with similar first names.
>>> p, created = Person.objects.get_or_create(first_name='John', last_name='Lennon', defaults={'birthday': date(1940, 10, 9)})
# get_or_create() didn't have to create an object.
>>> created
False
# There's still only one Person in the database.
>>> Person.objects.count()
1
# get_or_create() a Person with a different name.
>>> p, created = Person.objects.get_or_create(first_name='George', last_name='Harrison', defaults={'birthday': date(1943, 2, 25)})
>>> created
True
>>> Person.objects.count()
2
# If we execute the exact same statement, it won't create a Person.
>>> p, created = Person.objects.get_or_create(first_name='George', last_name='Harrison', defaults={'birthday': date(1943, 2, 25)})
>>> created
False
>>> Person.objects.count()
2
"""

View File

@ -74,7 +74,7 @@ invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places"
invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple. invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple.
invalid_models.fielderrors: "choices": "choices" should be either a tuple or list. invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
invalid_models.fielderrors: "index": "db_index" should be either None, True or False. invalid_models.fielderrors: "index": "db_index" should be either None, True or False.

View File

@ -12,8 +12,14 @@ class Person(models.Model):
def _get_full_name(self): def _get_full_name(self):
return "%s %s" % (self.first_name, self.last_name) return "%s %s" % (self.first_name, self.last_name)
def _set_full_name(self, combined_name):
self.first_name, self.last_name = combined_name.split(' ', 1)
full_name = property(_get_full_name) full_name = property(_get_full_name)
full_name_2 = property(_get_full_name, _set_full_name)
API_TESTS = """ API_TESTS = """
>>> a = Person(first_name='John', last_name='Lennon') >>> a = Person(first_name='John', last_name='Lennon')
>>> a.save() >>> a.save()
@ -25,4 +31,10 @@ API_TESTS = """
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: can't set attribute AttributeError: can't set attribute
# But "full_name_2" has, and it can be used to initialise the class.
>>> a2 = Person(full_name_2 = 'Paul McCartney')
>>> a2.save()
>>> a2.first_name
'Paul'
""" """

View File

@ -169,8 +169,7 @@ TEMPLATE_TESTS = {
'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"), 'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"),
### CYCLE TAG ############################################################# ### CYCLE TAG #############################################################
#'cycleXX': ('', {}, ''), 'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError),
'cycle01': ('{% cycle a, %}', {}, 'a'),
'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'), 'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'),
'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'), 'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'),
'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'), 'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'),
@ -193,13 +192,11 @@ TEMPLATE_TESTS = {
'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError), 'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
### FILTER TAG ############################################################ ### FILTER TAG ############################################################
#'filterXX': ('', {}, ''),
'filter01': ('{% filter upper %}{% endfilter %}', {}, ''), 'filter01': ('{% filter upper %}{% endfilter %}', {}, ''),
'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'), 'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'),
'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'), 'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'),
### FIRSTOF TAG ########################################################### ### FIRSTOF TAG ###########################################################
#'firstofXX': ('', {}, ''),
'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''), 'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''),
'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'), 'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'),
'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'), 'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
@ -220,8 +217,79 @@ TEMPLATE_TESTS = {
'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"), 'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"), 'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
# AND
'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'),
# OR
'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),
# TODO: multiple ORs
# NOT
'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),
'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'),
'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'),
'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),
# AND and OR raises a TemplateSyntaxError
'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
### IFCHANGED TAG ######################################################### ### IFCHANGED TAG #########################################################
#'ifchangedXX': ('', {}, ''),
'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'), 'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'), 'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'), 'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
@ -238,6 +306,18 @@ TEMPLATE_TESTS = {
'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"), 'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"),
'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"), 'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"),
# SMART SPLITTING
'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"),
'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"),
'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"),
'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"),
'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"),
'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"),
'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"),
'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"),
'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"),
'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"),
### IFNOTEQUAL TAG ######################################################## ### IFNOTEQUAL TAG ########################################################
'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"), 'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""), 'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
@ -388,7 +468,6 @@ TEMPLATE_TESTS = {
"""), """),
### REGROUP TAG ########################################################### ### REGROUP TAG ###########################################################
#'regroupXX': ('', {}, ''),
'regroup01': ('{% regroup data by bar as grouped %}' + \ 'regroup01': ('{% regroup data by bar as grouped %}' + \
'{% for group in grouped %}' + \ '{% for group in grouped %}' + \
'{{ group.grouper }}:' + \ '{{ group.grouper }}:' + \
@ -414,16 +493,18 @@ TEMPLATE_TESTS = {
{}, ''), {}, ''),
### TEMPLATETAG TAG ####################################################### ### TEMPLATETAG TAG #######################################################
#'templatetagXX': ('', {}, ''),
'templatetag01': ('{% templatetag openblock %}', {}, '{%'), 'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
'templatetag02': ('{% templatetag closeblock %}', {}, '%}'), 'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),
'templatetag03': ('{% templatetag openvariable %}', {}, '{{'), 'templatetag03': ('{% templatetag openvariable %}', {}, '{{'),
'templatetag04': ('{% templatetag closevariable %}', {}, '}}'), 'templatetag04': ('{% templatetag closevariable %}', {}, '}}'),
'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError), 'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError),
'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError), 'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError),
'templatetag07': ('{% templatetag openbrace %}', {}, '{'),
'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
### WIDTHRATIO TAG ######################################################## ### WIDTHRATIO TAG ########################################################
#'widthratioXX': ('', {}, ''),
'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'), 'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''), 'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''),
'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'), 'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'),
@ -440,11 +521,11 @@ TEMPLATE_TESTS = {
'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError), 'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError),
'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError), 'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError),
'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError), 'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError),
### NOW TAG ######################################################## ### NOW TAG ########################################################
# Simple case # Simple case
'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)), 'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
# Check parsing of escaped and special characters # Check parsing of escaped and special characters
'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError), 'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
# 'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)), # 'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),

Some files were not shown because too many files have changed in this diff Show More