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:
parent
e976ed1f79
commit
adf4b9311d
1
AUTHORS
1
AUTHORS
@ -71,6 +71,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Russell Keith-Magee <freakboy@iinet.net.au>
|
||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||
Sune Kirkeby <http://ibofobi.dk/>
|
||||
Cameron Knight (ckknight)
|
||||
Bruce Kroeze <http://coderseye.com/>
|
||||
Joseph Kocherhans
|
||||
lakin.wecker@gmail.com
|
||||
|
@ -12,7 +12,7 @@ from django.conf import global_settings
|
||||
|
||||
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
|
||||
|
||||
class LazySettings:
|
||||
class LazySettings(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,
|
||||
@ -67,7 +67,7 @@ class LazySettings:
|
||||
setattr(holder, name, value)
|
||||
self._target = holder
|
||||
|
||||
class Settings:
|
||||
class Settings(object):
|
||||
def __init__(self, settings_module):
|
||||
# update this dict from global settings (but only for ALL_CAPS settings)
|
||||
for setting in dir(global_settings):
|
||||
@ -112,7 +112,7 @@ class Settings:
|
||||
def get_all_members(self):
|
||||
return dir(self)
|
||||
|
||||
class UserSettingsHolder:
|
||||
class UserSettingsHolder(object):
|
||||
"""
|
||||
Holder for user configured settings.
|
||||
"""
|
||||
|
Binary file not shown.
@ -12,7 +12,7 @@ msgstr ""
|
||||
"Last-Translator: Gaël Chardon <gael.dev_at_nospam_4now.net>\n"
|
||||
"Language-Team: français <fr@li.org>\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"
|
||||
|
||||
#: contrib/comments/models.py:67 contrib/comments/models.py:166
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -2,7 +2,6 @@
|
||||
# Copyright (C) 2006 THE djangojs'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the djangojs package.
|
||||
# Meir Kriheli <meir@mksoft.co.il>, 2006.
|
||||
# , fuzzy
|
||||
#
|
||||
#
|
||||
msgid ""
|
||||
|
Binary file not shown.
@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-05-16 10:13+0200\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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -19,7 +19,7 @@ msgstr ""
|
||||
|
||||
#: contrib/comments/models.py:67 contrib/comments/models.py:166
|
||||
msgid "object ID"
|
||||
msgstr ""
|
||||
msgstr "ID obiektu"
|
||||
|
||||
#: contrib/comments/models.py:68
|
||||
msgid "headline"
|
||||
@ -32,43 +32,43 @@ msgstr "komentarz"
|
||||
|
||||
#: contrib/comments/models.py:70
|
||||
msgid "rating #1"
|
||||
msgstr ""
|
||||
msgstr "ocena #1"
|
||||
|
||||
#: contrib/comments/models.py:71
|
||||
msgid "rating #2"
|
||||
msgstr ""
|
||||
msgstr "ocena #2"
|
||||
|
||||
#: contrib/comments/models.py:72
|
||||
msgid "rating #3"
|
||||
msgstr ""
|
||||
msgstr "ocena #3"
|
||||
|
||||
#: contrib/comments/models.py:73
|
||||
msgid "rating #4"
|
||||
msgstr ""
|
||||
msgstr "ocena #4"
|
||||
|
||||
#: contrib/comments/models.py:74
|
||||
msgid "rating #5"
|
||||
msgstr ""
|
||||
msgstr "ocena #5"
|
||||
|
||||
#: contrib/comments/models.py:75
|
||||
msgid "rating #6"
|
||||
msgstr ""
|
||||
msgstr "ocena #6"
|
||||
|
||||
#: contrib/comments/models.py:76
|
||||
msgid "rating #7"
|
||||
msgstr ""
|
||||
msgstr "ocena #7"
|
||||
|
||||
#: contrib/comments/models.py:77
|
||||
msgid "rating #8"
|
||||
msgstr ""
|
||||
msgstr "ocena #8"
|
||||
|
||||
#: contrib/comments/models.py:82
|
||||
msgid "is valid rating"
|
||||
msgstr ""
|
||||
msgstr "jest poprawną oceną"
|
||||
|
||||
#: contrib/comments/models.py:83 contrib/comments/models.py:169
|
||||
msgid "date/time submitted"
|
||||
msgstr ""
|
||||
msgstr "data/czas dodania"
|
||||
|
||||
#: contrib/comments/models.py:84 contrib/comments/models.py:170
|
||||
msgid "is public"
|
||||
@ -87,15 +87,16 @@ msgid ""
|
||||
"Check this box if the comment is inappropriate. A \"This comment has been "
|
||||
"removed\" message will be displayed instead."
|
||||
msgstr ""
|
||||
"Zaznacz to pole jeżeli komentarz jest nieodpowiedni. Wyświetlony zostanie tekst \"Ten "
|
||||
"komentarz został usunięty\". "
|
||||
|
||||
#: contrib/comments/models.py:91
|
||||
#, fuzzy
|
||||
msgid "comments"
|
||||
msgstr "komentarz"
|
||||
msgstr "komentarze"
|
||||
|
||||
#: contrib/comments/models.py:131 contrib/comments/models.py:207
|
||||
msgid "Content object"
|
||||
msgstr ""
|
||||
msgstr "Obiekt Treści"
|
||||
|
||||
#: contrib/comments/models.py:159
|
||||
#, python-format
|
||||
@ -106,6 +107,11 @@ msgid ""
|
||||
"\n"
|
||||
"http://%(domain)s%(url)s"
|
||||
msgstr ""
|
||||
"Dodane przez %(user)s dnia %(date)s\n"
|
||||
"\n"
|
||||
"%(comment)y\n"
|
||||
"\n"
|
||||
"http://%(domain)s%(url)s"
|
||||
|
||||
#: contrib/comments/models.py:168
|
||||
msgid "person's name"
|
||||
@ -122,12 +128,12 @@ msgstr "zaakceptowano"
|
||||
#: contrib/comments/models.py:176
|
||||
#, fuzzy
|
||||
msgid "free comment"
|
||||
msgstr "Wolny komentarz"
|
||||
msgstr "wolny komentarz"
|
||||
|
||||
#: contrib/comments/models.py:177
|
||||
#, fuzzy
|
||||
msgid "free comments"
|
||||
msgstr "Wolne komentarze"
|
||||
msgstr "wolne komentarze"
|
||||
|
||||
#: contrib/comments/models.py:233
|
||||
msgid "score"
|
||||
@ -135,7 +141,7 @@ msgstr "ilość punktów"
|
||||
|
||||
#: contrib/comments/models.py:234
|
||||
msgid "score date"
|
||||
msgstr ""
|
||||
msgstr "data przyznania punktów"
|
||||
|
||||
#: contrib/comments/models.py:237
|
||||
#, fuzzy
|
||||
@ -144,12 +150,12 @@ msgstr "ilość punktów"
|
||||
|
||||
#: contrib/comments/models.py:238
|
||||
msgid "karma scores"
|
||||
msgstr ""
|
||||
msgstr "wyniki"
|
||||
|
||||
#: contrib/comments/models.py:242
|
||||
#, python-format
|
||||
msgid "%(score)d rating by %(user)s"
|
||||
msgstr ""
|
||||
msgstr "%(score)d ocenę przez %(user)s"
|
||||
|
||||
#: contrib/comments/models.py:258
|
||||
#, python-format
|
||||
@ -158,57 +164,62 @@ msgid ""
|
||||
"\n"
|
||||
"%(text)s"
|
||||
msgstr ""
|
||||
"Komentarz oflagowany przez %(user)s:\n"
|
||||
"\n"
|
||||
"%(text)s"
|
||||
|
||||
#: contrib/comments/models.py:265
|
||||
msgid "flag date"
|
||||
msgstr ""
|
||||
msgstr "data flagi"
|
||||
|
||||
#: contrib/comments/models.py:268
|
||||
msgid "user flag"
|
||||
msgstr ""
|
||||
msgstr "flaga użytkownika"
|
||||
|
||||
#: contrib/comments/models.py:269
|
||||
msgid "user flags"
|
||||
msgstr ""
|
||||
msgstr "flagi użytkownika"
|
||||
|
||||
#: contrib/comments/models.py:273
|
||||
#, python-format
|
||||
msgid "Flag by %r"
|
||||
msgstr ""
|
||||
msgstr "Flaga %r"
|
||||
|
||||
#: contrib/comments/models.py:278
|
||||
msgid "deletion date"
|
||||
msgstr ""
|
||||
msgstr "data skasowania"
|
||||
|
||||
#: contrib/comments/models.py:280
|
||||
msgid "moderator deletion"
|
||||
msgstr ""
|
||||
msgstr "usunięcie moderatora"
|
||||
|
||||
#: contrib/comments/models.py:281
|
||||
msgid "moderator deletions"
|
||||
msgstr ""
|
||||
msgstr "usunięcia moderatorów"
|
||||
|
||||
#: contrib/comments/models.py:285
|
||||
#, python-format
|
||||
msgid "Moderator deletion by %r"
|
||||
msgstr ""
|
||||
msgstr "Usunięcie moderatora przez %r"
|
||||
|
||||
#: contrib/comments/views/karma.py:19
|
||||
msgid "Anonymous users cannot vote"
|
||||
msgstr ""
|
||||
msgstr "Anonimowi użytkownicy nie mogą głosować"
|
||||
|
||||
#: contrib/comments/views/karma.py:23
|
||||
msgid "Invalid comment ID"
|
||||
msgstr ""
|
||||
msgstr "Błędny ID komentarza"
|
||||
|
||||
#: contrib/comments/views/karma.py:25
|
||||
msgid "No voting for yourself"
|
||||
msgstr ""
|
||||
msgstr "Nie można głosować na siebie"
|
||||
|
||||
#: contrib/comments/views/comments.py:28
|
||||
msgid ""
|
||||
"This rating is required because you've entered at least one other rating."
|
||||
msgstr ""
|
||||
"Ta ocena jest wymagana gdyż podałeś przynajmniej jedną inną ocenę."
|
||||
|
||||
|
||||
#: contrib/comments/views/comments.py:112
|
||||
#, python-format
|
||||
@ -236,12 +247,12 @@ msgstr ""
|
||||
#: contrib/comments/views/comments.py:189
|
||||
#: contrib/comments/views/comments.py:280
|
||||
msgid "Only POSTs are allowed"
|
||||
msgstr ""
|
||||
msgstr "Dozwolone tylko POSTy"
|
||||
|
||||
#: contrib/comments/views/comments.py:193
|
||||
#: contrib/comments/views/comments.py:284
|
||||
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:286
|
||||
@ -264,17 +275,16 @@ msgstr ""
|
||||
#: contrib/comments/templates/comments/form.html:8
|
||||
#: contrib/admin/templates/admin/login.html:17
|
||||
msgid "Username:"
|
||||
msgstr "Nazwa użytkownika"
|
||||
msgstr "Nazwa użytkownika:"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:6
|
||||
#: contrib/admin/templates/admin/login.html:20
|
||||
msgid "Password:"
|
||||
msgstr "Hasło"
|
||||
msgstr "Hasło:"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:6
|
||||
#, fuzzy
|
||||
msgid "Forgotten your password?"
|
||||
msgstr "Zmień hasło"
|
||||
msgstr "Zapomniałeś hasło?"
|
||||
|
||||
#: contrib/comments/templates/comments/form.html:8
|
||||
#: contrib/admin/templates/admin/object_history.html:3
|
||||
@ -385,7 +395,7 @@ msgstr "id obiektu"
|
||||
|
||||
#: contrib/admin/models.py:20
|
||||
msgid "object repr"
|
||||
msgstr ""
|
||||
msgstr "reprezentacj obiektu"
|
||||
|
||||
#: contrib/admin/models.py:21
|
||||
msgid "action flag"
|
||||
@ -426,12 +436,16 @@ msgid ""
|
||||
"Please log in again, because your session has expired. Don't worry: Your "
|
||||
"submission has been saved."
|
||||
msgstr ""
|
||||
"Zaloguj się ponownie. Twoja sesja wygasła lecz twoje zgłoszenie "
|
||||
"zostało zapisane."
|
||||
|
||||
#: contrib/admin/views/decorators.py:68
|
||||
msgid ""
|
||||
"Looks like your browser isn't configured to accept cookies. Please enable "
|
||||
"cookies, reload this page, and try again."
|
||||
msgstr ""
|
||||
"Twoja przeglądarka nie chce akceptować ciasteczek. Zmień "
|
||||
"jej ustawienia i spróbuj ponownie."
|
||||
|
||||
#: contrib/admin/views/decorators.py:82
|
||||
msgid "Usernames cannot contain the '@' character."
|
||||
@ -449,16 +463,16 @@ msgstr "Administracja stroną"
|
||||
#: contrib/admin/views/main.py:260
|
||||
#, python-format
|
||||
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
|
||||
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
|
||||
#, python-format
|
||||
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
|
||||
#, python-format
|
||||
@ -499,6 +513,8 @@ msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
|
||||
msgid ""
|
||||
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
||||
msgstr ""
|
||||
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
|
||||
|
||||
|
||||
#: contrib/admin/views/main.py:392
|
||||
#, python-format
|
||||
@ -508,21 +524,21 @@ msgstr "Zmień %s"
|
||||
#: contrib/admin/views/main.py:470
|
||||
#, python-format
|
||||
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
|
||||
#, python-format
|
||||
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
|
||||
#, python-format
|
||||
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
|
||||
msgid "Are you sure?"
|
||||
msgstr "Czy na pewno?"
|
||||
msgstr "Jesteś pewien?"
|
||||
|
||||
#: contrib/admin/views/main.py:533
|
||||
#, 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
|
||||
#, python-format
|
||||
msgid "String (up to %(maxlength)s)"
|
||||
msgstr ""
|
||||
msgstr "Łańcuch (do %(maxlength)s znaków)"
|
||||
|
||||
#: contrib/admin/views/doc.py:280
|
||||
msgid "Comma-separated integers"
|
||||
@ -604,11 +620,11 @@ msgstr "URL"
|
||||
|
||||
#: contrib/admin/views/doc.py:301
|
||||
msgid "U.S. state (two uppercase letters)"
|
||||
msgstr ""
|
||||
msgstr "Stan USA (dwie duże litery)"
|
||||
|
||||
#: contrib/admin/views/doc.py:302
|
||||
msgid "XML text"
|
||||
msgstr "Text XML"
|
||||
msgstr "Tekst XML"
|
||||
|
||||
#: contrib/admin/templates/admin/object_history.html:3
|
||||
#: 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 "
|
||||
"admin site."
|
||||
msgstr ""
|
||||
"Ten obiekt nie ma historii zmian. Najprawdopodobniej wpis te nie "
|
||||
"został dodany poprzez panel admina"
|
||||
|
||||
#: contrib/admin/templates/admin/base_site.html:4
|
||||
msgid "Django site admin"
|
||||
@ -701,13 +719,15 @@ msgstr "Bład serwera (500)"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:9
|
||||
msgid "Server Error <em>(500)</em>"
|
||||
msgstr ""
|
||||
msgstr "Błąd Serwera <em>(500)</em>"
|
||||
|
||||
#: contrib/admin/templates/admin/500.html:10
|
||||
msgid ""
|
||||
"There's been an error. It's been reported to the site administrators via e-"
|
||||
"mail and should be fixed shortly. Thanks for your patience."
|
||||
msgstr ""
|
||||
"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:8
|
||||
@ -716,12 +736,12 @@ msgstr "Strona nie znaleziona"
|
||||
|
||||
#: contrib/admin/templates/admin/404.html:10
|
||||
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
|
||||
#, python-format
|
||||
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/change_form.html:15
|
||||
@ -734,7 +754,7 @@ msgstr "Zmień"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:44
|
||||
msgid "You don't have permission to edit anything."
|
||||
msgstr ""
|
||||
msgstr "Nie masz uprawnień by edytować cokolwiek"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:52
|
||||
msgid "Recent Actions"
|
||||
@ -746,7 +766,7 @@ msgstr "Moje akcje"
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:57
|
||||
msgid "None available"
|
||||
msgstr "Nic nie dostępne"
|
||||
msgstr "Brak"
|
||||
|
||||
#: contrib/admin/templates/admin/change_list.html:11
|
||||
#, python-format
|
||||
@ -756,7 +776,7 @@ msgstr "Dodaj %(name)s"
|
||||
#: contrib/admin/templates/admin/login.html:22
|
||||
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
|
||||
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
|
||||
msgid "Welcome,"
|
||||
@ -816,11 +836,11 @@ msgstr "Porządek:"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:4
|
||||
msgid "Save as new"
|
||||
msgstr "Zapisz"
|
||||
msgstr "Zapisz jako nowe"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:5
|
||||
msgid "Save and add another"
|
||||
msgstr "Zapisz i dodaj"
|
||||
msgstr "Zapisz i dodaj nowe"
|
||||
|
||||
#: contrib/admin/templates/admin/submit_line.html:6
|
||||
msgid "Save and continue editing"
|
||||
@ -858,6 +878,8 @@ msgid ""
|
||||
"Forgotten your password? Enter your e-mail address below, and we'll reset "
|
||||
"your password and e-mail the new one to you."
|
||||
msgstr ""
|
||||
"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
|
||||
msgid "E-mail address:"
|
||||
@ -869,7 +891,7 @@ msgstr "Zresetuj moje hasło"
|
||||
|
||||
#: contrib/admin/templates/registration/logged_out.html:8
|
||||
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
|
||||
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:10
|
||||
msgid "Password reset successful"
|
||||
msgstr ""
|
||||
msgstr "Udane resetowanie hasła"
|
||||
|
||||
#: contrib/admin/templates/registration/password_reset_done.html:12
|
||||
msgid ""
|
||||
"We've e-mailed a new password to the e-mail address you submitted. You "
|
||||
"should be receiving it shortly."
|
||||
msgstr ""
|
||||
"Nowe hasło zostało wysłane na podany adres email. Powinieneś "
|
||||
"otrzymać je niebawem."
|
||||
|
||||
#: contrib/admin/templates/registration/password_change_form.html:12
|
||||
msgid ""
|
||||
"Please enter your old password, for security's sake, and then enter your new "
|
||||
"password twice so we can verify you typed it in correctly."
|
||||
msgstr ""
|
||||
msgstr "Podaj swoje stare hasło i dwa razy nowe."
|
||||
|
||||
#: contrib/admin/templates/registration/password_change_form.html:17
|
||||
msgid "Old password:"
|
||||
@ -910,12 +934,12 @@ msgstr "Zmień hasło"
|
||||
|
||||
#: contrib/admin/templates/registration/password_reset_email.html:2
|
||||
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
|
||||
#, python-format
|
||||
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
|
||||
#, python-format
|
||||
@ -924,11 +948,11 @@ msgstr "Twoje nowe hasło to: %(new_password)s"
|
||||
|
||||
#: contrib/admin/templates/registration/password_reset_email.html:7
|
||||
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
|
||||
msgid "Your username, in case you've forgotten:"
|
||||
msgstr ""
|
||||
msgstr "Twój login:"
|
||||
|
||||
#: contrib/admin/templates/registration/password_reset_email.html:13
|
||||
msgid "Thanks for using our site!"
|
||||
@ -960,7 +984,7 @@ msgstr ""
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
|
||||
msgid "Documentation for this page"
|
||||
msgstr ""
|
||||
msgstr "Dokumentacja dla tej strony"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
|
||||
msgid ""
|
||||
@ -970,37 +994,39 @@ msgstr ""
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
||||
msgid "Show object ID"
|
||||
msgstr ""
|
||||
msgstr "Pokaż ID obiektu"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
|
||||
msgid ""
|
||||
"Shows the content-type and unique ID for pages that represent a single "
|
||||
"object."
|
||||
msgstr ""
|
||||
"Pokazuje typ i unikalne ID dla stron, które reprezentują "
|
||||
"pojedynczy obiekt."
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
|
||||
msgid "Edit this object (current window)"
|
||||
msgstr ""
|
||||
msgstr "Edytuj ten obiekt (bierzące okno)"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
||||
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
|
||||
msgid "Edit this object (new window)"
|
||||
msgstr ""
|
||||
msgstr "Edytuj ten obiekt (nowe onko)"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
|
||||
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
|
||||
msgid "Date:"
|
||||
msgstr "data"
|
||||
msgstr "Data:"
|
||||
|
||||
#: contrib/admin/templates/widget/date_time.html:4
|
||||
msgid "Time:"
|
||||
msgstr "Czas"
|
||||
msgstr "Czas:"
|
||||
|
||||
#: contrib/admin/templates/widget/file.html:2
|
||||
msgid "Currently:"
|
||||
@ -1012,36 +1038,40 @@ msgstr "Zmień:"
|
||||
|
||||
#: contrib/redirects/models.py:7
|
||||
msgid "redirect from"
|
||||
msgstr ""
|
||||
msgstr "przekieruj z"
|
||||
|
||||
#: contrib/redirects/models.py:8
|
||||
msgid ""
|
||||
"This should be an absolute path, excluding the domain name. Example: '/"
|
||||
"events/search/'."
|
||||
msgstr ""
|
||||
"Podaj pełną ścieżkę bez nazwy domeny. Przykład: '/"
|
||||
"events/search/'."
|
||||
|
||||
#: contrib/redirects/models.py:9
|
||||
msgid "redirect to"
|
||||
msgstr ""
|
||||
msgstr "przekierowanie do"
|
||||
|
||||
#: contrib/redirects/models.py:10
|
||||
msgid ""
|
||||
"This can be either an absolute path (as above) or a full URL starting with "
|
||||
"'http://'."
|
||||
msgstr ""
|
||||
msgstr "Ścieżka jak wyżej lub pełny URL z http://"
|
||||
|
||||
#: contrib/redirects/models.py:12
|
||||
msgid "redirect"
|
||||
msgstr ""
|
||||
msgstr "przekieruj"
|
||||
|
||||
#: contrib/redirects/models.py:13
|
||||
msgid "redirects"
|
||||
msgstr ""
|
||||
msgstr "przekierowania"
|
||||
|
||||
#: contrib/flatpages/models.py:8
|
||||
msgid ""
|
||||
"Example: '/about/contact/'. Make sure to have leading and trailing slashes."
|
||||
msgstr ""
|
||||
"Przykład: '/about/contact/'. Upewnij się że wpisałeś otwierający i zamykający slash."
|
||||
|
||||
|
||||
#: contrib/flatpages/models.py:9
|
||||
msgid "title"
|
||||
@ -1053,11 +1083,11 @@ msgstr "zawartość"
|
||||
|
||||
#: contrib/flatpages/models.py:11
|
||||
msgid "enable comments"
|
||||
msgstr ""
|
||||
msgstr "włącz komentarze"
|
||||
|
||||
#: contrib/flatpages/models.py:12
|
||||
msgid "template name"
|
||||
msgstr ""
|
||||
msgstr "nazwa szablonu"
|
||||
|
||||
#: contrib/flatpages/models.py:13
|
||||
msgid ""
|
||||
@ -1067,11 +1097,11 @@ msgstr ""
|
||||
|
||||
#: contrib/flatpages/models.py:14
|
||||
msgid "registration required"
|
||||
msgstr ""
|
||||
msgstr "wymagana rejestracja"
|
||||
|
||||
#: contrib/flatpages/models.py:14
|
||||
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
|
||||
msgid "flat page"
|
||||
@ -1091,31 +1121,31 @@ msgstr ""
|
||||
|
||||
#: contrib/auth/models.py:17
|
||||
msgid "permission"
|
||||
msgstr ""
|
||||
msgstr "uprawnienie"
|
||||
|
||||
#: contrib/auth/models.py:18 contrib/auth/models.py:27
|
||||
msgid "permissions"
|
||||
msgstr ""
|
||||
msgstr "uprawnienia"
|
||||
|
||||
#: contrib/auth/models.py:29
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
msgstr "grupa"
|
||||
|
||||
#: contrib/auth/models.py:30 contrib/auth/models.py:65
|
||||
msgid "groups"
|
||||
msgstr ""
|
||||
msgstr "grupy"
|
||||
|
||||
#: contrib/auth/models.py:55
|
||||
msgid "username"
|
||||
msgstr ""
|
||||
msgstr "użytkownik"
|
||||
|
||||
#: contrib/auth/models.py:56
|
||||
msgid "first name"
|
||||
msgstr ""
|
||||
msgstr "Imię"
|
||||
|
||||
#: contrib/auth/models.py:57
|
||||
msgid "last name"
|
||||
msgstr ""
|
||||
msgstr "Nazwisko"
|
||||
|
||||
#: contrib/auth/models.py:58
|
||||
msgid "e-mail address"
|
||||
@ -1127,15 +1157,15 @@ msgstr "hasło"
|
||||
|
||||
#: contrib/auth/models.py:59
|
||||
msgid "Use '[algo]$[salt]$[hexdigest]'"
|
||||
msgstr ""
|
||||
msgstr "Użyj '[algo]$[salt]$[hexdigest]'"
|
||||
|
||||
#: contrib/auth/models.py:60
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
msgstr "stan w zespole"
|
||||
|
||||
#: contrib/auth/models.py:60
|
||||
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
|
||||
msgid "active"
|
||||
@ -1143,7 +1173,7 @@ msgstr "aktywny"
|
||||
|
||||
#: contrib/auth/models.py:62
|
||||
msgid "superuser status"
|
||||
msgstr ""
|
||||
msgstr "Główny Administrator"
|
||||
|
||||
#: contrib/auth/models.py:63
|
||||
msgid "last login"
|
||||
@ -1158,10 +1188,12 @@ msgid ""
|
||||
"In addition to the permissions manually assigned, this user will also get "
|
||||
"all permissions granted to each group he/she is in."
|
||||
msgstr ""
|
||||
"Oprócz uprawnień przypisanych bezpośrednio użytkownikowi otrzyma on "
|
||||
"uprawnienia grup, do których należy."
|
||||
|
||||
#: contrib/auth/models.py:67
|
||||
msgid "user permissions"
|
||||
msgstr ""
|
||||
msgstr "uprawnienia użytkownika"
|
||||
|
||||
#: contrib/auth/models.py:70
|
||||
#, fuzzy
|
||||
@ -1175,62 +1207,64 @@ msgstr "Uzytkownicy"
|
||||
|
||||
#: contrib/auth/models.py:76
|
||||
msgid "Personal info"
|
||||
msgstr ""
|
||||
msgstr "Dane osobowe"
|
||||
|
||||
#: contrib/auth/models.py:77
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
msgstr "Uprawnienia"
|
||||
|
||||
#: contrib/auth/models.py:78
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
msgstr "Ważne daty"
|
||||
|
||||
#: contrib/auth/models.py:79
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
msgstr "Grupy"
|
||||
|
||||
#: contrib/auth/models.py:219
|
||||
#, fuzzy
|
||||
msgid "message"
|
||||
msgstr "Wiadomość"
|
||||
msgstr "wiadomość"
|
||||
|
||||
#: contrib/auth/forms.py:30
|
||||
msgid ""
|
||||
"Your Web browser doesn't appear to have cookies enabled. Cookies are "
|
||||
"required for logging in."
|
||||
msgstr ""
|
||||
"Twoja przeglądarka nie chce akceptować ciasteczek. Są one "
|
||||
"wymagane do zalogowania się."
|
||||
|
||||
#: contrib/contenttypes/models.py:25
|
||||
msgid "python model class name"
|
||||
msgstr ""
|
||||
msgstr "nazwa pythonowa modelu klasy"
|
||||
|
||||
#: contrib/contenttypes/models.py:28
|
||||
msgid "content type"
|
||||
msgstr ""
|
||||
msgstr "typ zawartości"
|
||||
|
||||
#: contrib/contenttypes/models.py:29
|
||||
msgid "content types"
|
||||
msgstr ""
|
||||
msgstr "typy zawartości"
|
||||
|
||||
#: contrib/sessions/models.py:35
|
||||
msgid "session key"
|
||||
msgstr ""
|
||||
msgstr "klucz sesji"
|
||||
|
||||
#: contrib/sessions/models.py:36
|
||||
msgid "session data"
|
||||
msgstr ""
|
||||
msgstr "data sesji"
|
||||
|
||||
#: contrib/sessions/models.py:37
|
||||
msgid "expire date"
|
||||
msgstr ""
|
||||
msgstr "data wygaśnięcia sesji"
|
||||
|
||||
#: contrib/sessions/models.py:41
|
||||
msgid "session"
|
||||
msgstr ""
|
||||
msgstr "sesja"
|
||||
|
||||
#: contrib/sessions/models.py:42
|
||||
msgid "sessions"
|
||||
msgstr ""
|
||||
msgstr "sesje"
|
||||
|
||||
#: contrib/sites/models.py:10
|
||||
msgid "domain name"
|
||||
@ -1250,15 +1284,15 @@ msgstr "strony"
|
||||
|
||||
#: utils/translation.py:360
|
||||
msgid "DATE_FORMAT"
|
||||
msgstr "FORMAT_DATY"
|
||||
msgstr "Y-m-d"
|
||||
|
||||
#: utils/translation.py:361
|
||||
msgid "DATETIME_FORMAT"
|
||||
msgstr ""
|
||||
msgstr "Y-m-d H:i:s"
|
||||
|
||||
#: utils/translation.py:362
|
||||
msgid "TIME_FORMAT"
|
||||
msgstr ""
|
||||
msgstr "H:i:s"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Monday"
|
||||
@ -1339,52 +1373,51 @@ msgstr "Grudzień"
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "jan"
|
||||
msgstr "i"
|
||||
msgstr "sty"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "feb"
|
||||
msgstr ""
|
||||
msgstr "luty"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "mar"
|
||||
msgstr ""
|
||||
msgstr "marz"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "apr"
|
||||
msgstr ""
|
||||
msgstr "kwie"
|
||||
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "may"
|
||||
msgstr "dzień"
|
||||
msgstr "maj"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "jun"
|
||||
msgstr ""
|
||||
msgstr "czerw"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "jul"
|
||||
msgstr ""
|
||||
msgstr "lip"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "aug"
|
||||
msgstr ""
|
||||
msgstr "sier"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "sep"
|
||||
msgstr ""
|
||||
msgstr "wrze"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "oct"
|
||||
msgstr ""
|
||||
msgstr "paź"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "nov"
|
||||
msgstr ""
|
||||
msgstr "list"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "dec"
|
||||
msgstr ""
|
||||
msgstr "gru"
|
||||
|
||||
#: utils/dates.py:27
|
||||
msgid "Jan."
|
||||
@ -1396,7 +1429,7 @@ msgstr "Lut."
|
||||
|
||||
#: utils/dates.py:28
|
||||
msgid "Aug."
|
||||
msgstr "Sier.."
|
||||
msgstr "Sier."
|
||||
|
||||
#: utils/dates.py:28
|
||||
msgid "Sept."
|
||||
@ -1415,31 +1448,28 @@ msgid "Dec."
|
||||
msgstr "Gru."
|
||||
|
||||
#: utils/timesince.py:12
|
||||
#, fuzzy
|
||||
msgid "year"
|
||||
msgid_plural "years"
|
||||
msgstr[0] "rok"
|
||||
msgstr[1] "rok"
|
||||
msgstr[1] "lat"
|
||||
|
||||
#: utils/timesince.py:13
|
||||
#, fuzzy
|
||||
msgid "month"
|
||||
msgid_plural "months"
|
||||
msgstr[0] "miesiąc"
|
||||
msgstr[1] "miesiąc"
|
||||
msgstr[1] "miesięcy"
|
||||
|
||||
#: utils/timesince.py:14
|
||||
msgid "week"
|
||||
msgid_plural "weeks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "tydzień"
|
||||
msgstr[1] "tygodni"
|
||||
|
||||
#: utils/timesince.py:15
|
||||
#, fuzzy
|
||||
msgid "day"
|
||||
msgid_plural "days"
|
||||
msgstr[0] "dzień"
|
||||
msgstr[1] "dzień"
|
||||
msgstr[1] "dni"
|
||||
|
||||
#: utils/timesince.py:16
|
||||
#, fuzzy
|
||||
@ -1449,11 +1479,10 @@ msgstr[0] "godzina"
|
||||
msgstr[1] "godzina"
|
||||
|
||||
#: utils/timesince.py:17
|
||||
#, fuzzy
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "minuta"
|
||||
msgstr[1] "minuta"
|
||||
msgstr[1] "minut"
|
||||
|
||||
#: conf/global_settings.py:37
|
||||
msgid "Bengali"
|
||||
@ -1477,7 +1506,7 @@ msgstr "Niemiecki"
|
||||
|
||||
#: conf/global_settings.py:42
|
||||
msgid "Greek"
|
||||
msgstr ""
|
||||
msgstr "Grecki"
|
||||
|
||||
#: conf/global_settings.py:43
|
||||
msgid "English"
|
||||
@ -1501,7 +1530,7 @@ msgstr ""
|
||||
|
||||
#: conf/global_settings.py:48
|
||||
msgid "Hebrew"
|
||||
msgstr ""
|
||||
msgstr "Hebrajski"
|
||||
|
||||
#: conf/global_settings.py:49
|
||||
msgid "Icelandic"
|
||||
@ -1517,7 +1546,7 @@ msgstr "Japoński"
|
||||
|
||||
#: conf/global_settings.py:52
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
msgstr "Holenderski"
|
||||
|
||||
#: conf/global_settings.py:53
|
||||
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"
|
||||
|
||||
#: core/validators.py:64
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"This value must contain only letters, numbers, underscores, dashes or "
|
||||
"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
|
||||
msgid "Uppercase letters are not allowed here."
|
||||
@ -1606,7 +1634,7 @@ msgstr "Tu mogą być tylko cyfry"
|
||||
|
||||
#: core/validators.py:111
|
||||
msgid "This value can't be comprised solely of digits."
|
||||
msgstr ""
|
||||
msgstr "To pole nie może zawierać jedynie cyfr."
|
||||
|
||||
#: core/validators.py:116
|
||||
msgid "Enter a whole number."
|
||||
@ -1777,6 +1805,7 @@ msgid ""
|
||||
"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'."
|
||||
msgstr ""
|
||||
|
||||
|
||||
#: core/validators.py:462
|
||||
#, python-format
|
||||
msgid ""
|
||||
|
Binary file not shown.
@ -125,12 +125,10 @@ msgid "approved by staff"
|
||||
msgstr "одобрено администрацией"
|
||||
|
||||
#: contrib/comments/models.py:176
|
||||
#, fuzzy
|
||||
msgid "free comment"
|
||||
msgstr "Свободный комментарий"
|
||||
|
||||
#: contrib/comments/models.py:177
|
||||
#, fuzzy
|
||||
msgid "free comments"
|
||||
msgstr "Свободные комментарии"
|
||||
|
||||
@ -143,13 +141,12 @@ msgid "score date"
|
||||
msgstr "счёт времени"
|
||||
|
||||
#: contrib/comments/models.py:237
|
||||
#, fuzzy
|
||||
msgid "karma score"
|
||||
msgstr "счёт"
|
||||
msgstr "Карма счёт"
|
||||
|
||||
#: contrib/comments/models.py:238
|
||||
msgid "karma scores"
|
||||
msgstr ""
|
||||
msgstr "Карма счета"
|
||||
|
||||
#: contrib/comments/models.py:242
|
||||
#, python-format
|
||||
@ -172,12 +169,10 @@ msgid "flag date"
|
||||
msgstr "отметка даты"
|
||||
|
||||
#: contrib/comments/models.py:268
|
||||
#, fuzzy
|
||||
msgid "user flag"
|
||||
msgstr "Признак пользователя"
|
||||
|
||||
#: contrib/comments/models.py:269
|
||||
#, fuzzy
|
||||
msgid "user flags"
|
||||
msgstr "Признаки пользователя"
|
||||
|
||||
@ -191,14 +186,12 @@ msgid "deletion date"
|
||||
msgstr "дата удаления"
|
||||
|
||||
#: contrib/comments/models.py:280
|
||||
#, fuzzy
|
||||
msgid "moderator deletion"
|
||||
msgstr "Удалено модератором"
|
||||
msgstr "Удаленно модератором"
|
||||
|
||||
#: contrib/comments/models.py:281
|
||||
#, fuzzy
|
||||
msgid "moderator deletions"
|
||||
msgstr "Удалено модератором"
|
||||
msgstr "Удаления модератором"
|
||||
|
||||
#: contrib/comments/models.py:285
|
||||
#, python-format
|
||||
@ -742,7 +735,7 @@ msgstr "К сожалению, запрашиваемая вами страни
|
||||
#: contrib/admin/templates/admin/index.html:17
|
||||
#, python-format
|
||||
msgid "Models available in the %(name)s application."
|
||||
msgstr ""
|
||||
msgstr "Модели доступны в %(name)s приложении."
|
||||
|
||||
#: contrib/admin/templates/admin/index.html:28
|
||||
#: contrib/admin/templates/admin/change_form.html:15
|
||||
@ -818,11 +811,11 @@ msgstr ""
|
||||
|
||||
#: contrib/admin/templates/admin/search_form.html:8
|
||||
msgid "Go"
|
||||
msgstr ""
|
||||
msgstr "Вперёд"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:21
|
||||
msgid "View on site"
|
||||
msgstr ""
|
||||
msgstr "Смотреть сайт"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:30
|
||||
msgid "Please correct the error below."
|
||||
@ -832,7 +825,7 @@ msgstr[1] "Пожалуйста исправьте ошибки ниже."
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:48
|
||||
msgid "Ordering"
|
||||
msgstr ""
|
||||
msgstr "Очерёдность"
|
||||
|
||||
#: contrib/admin/templates/admin/change_form.html:51
|
||||
msgid "Order:"
|
||||
@ -967,11 +960,11 @@ msgstr "Спасибо за посещение нашего сайта!"
|
||||
#: contrib/admin/templates/registration/password_reset_email.html:15
|
||||
#, python-format
|
||||
msgid "The %(site_name)s team"
|
||||
msgstr "Команда сайта di %(site_name)s"
|
||||
msgstr "Команда сайта %(site_name)s"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:3
|
||||
msgid "Bookmarklets"
|
||||
msgstr ""
|
||||
msgstr "Закладки"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:5
|
||||
msgid "Documentation bookmarklets"
|
||||
@ -1018,7 +1011,7 @@ msgstr "Редактировать данный обьект (в текущем
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
||||
msgid "Jumps to the admin page for pages that represent a single object."
|
||||
msgstr ""
|
||||
msgstr "Перейти на страницу администратор для страниц представляющих один объект."
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
|
||||
msgid "Edit this object (new window)"
|
||||
@ -1129,22 +1122,18 @@ msgid "codename"
|
||||
msgstr "код"
|
||||
|
||||
#: contrib/auth/models.py:17
|
||||
#, fuzzy
|
||||
msgid "permission"
|
||||
msgstr "Права"
|
||||
|
||||
#: contrib/auth/models.py:18 contrib/auth/models.py:27
|
||||
#, fuzzy
|
||||
msgid "permissions"
|
||||
msgstr "Права"
|
||||
|
||||
#: contrib/auth/models.py:29
|
||||
#, fuzzy
|
||||
msgid "group"
|
||||
msgstr "Группа"
|
||||
|
||||
#: contrib/auth/models.py:30 contrib/auth/models.py:65
|
||||
#, fuzzy
|
||||
msgid "groups"
|
||||
msgstr "Группы"
|
||||
|
||||
@ -1205,17 +1194,14 @@ msgstr ""
|
||||
"все права группы, к которой он принадлежит."
|
||||
|
||||
#: contrib/auth/models.py:67
|
||||
#, fuzzy
|
||||
msgid "user permissions"
|
||||
msgstr "Права"
|
||||
msgstr "Права пользователя"
|
||||
|
||||
#: contrib/auth/models.py:70
|
||||
#, fuzzy
|
||||
msgid "user"
|
||||
msgstr "Пользователь"
|
||||
|
||||
#: contrib/auth/models.py:71
|
||||
#, fuzzy
|
||||
msgid "users"
|
||||
msgstr "Пользователи"
|
||||
|
||||
@ -1236,7 +1222,6 @@ msgid "Groups"
|
||||
msgstr "Группы"
|
||||
|
||||
#: contrib/auth/models.py:219
|
||||
#, fuzzy
|
||||
msgid "message"
|
||||
msgstr "Сообщение"
|
||||
|
||||
@ -1247,9 +1232,8 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: contrib/contenttypes/models.py:25
|
||||
#, fuzzy
|
||||
msgid "python model class name"
|
||||
msgstr "имя python модуля"
|
||||
msgstr "имя класса python модуля"
|
||||
|
||||
#: contrib/contenttypes/models.py:28
|
||||
msgid "content type"
|
||||
@ -1384,54 +1368,52 @@ msgid "December"
|
||||
msgstr "Декабрь"
|
||||
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "jan"
|
||||
msgstr "и"
|
||||
msgstr "янв"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "feb"
|
||||
msgstr ""
|
||||
msgstr "фев"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "mar"
|
||||
msgstr ""
|
||||
msgstr "мар"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "apr"
|
||||
msgstr ""
|
||||
msgstr "апр"
|
||||
|
||||
#: utils/dates.py:19
|
||||
#, fuzzy
|
||||
msgid "may"
|
||||
msgstr "Май"
|
||||
msgstr "май"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "jun"
|
||||
msgstr ""
|
||||
msgstr "июнь"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "jul"
|
||||
msgstr ""
|
||||
msgstr "июль"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "aug"
|
||||
msgstr ""
|
||||
msgstr "авг"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "sep"
|
||||
msgstr ""
|
||||
msgstr "сен"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "oct"
|
||||
msgstr ""
|
||||
msgstr "окт"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "nov"
|
||||
msgstr ""
|
||||
msgstr "нояб"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "dec"
|
||||
msgstr ""
|
||||
msgstr "дек"
|
||||
|
||||
#: utils/dates.py:27
|
||||
msgid "Jan."
|
||||
@ -1476,8 +1458,8 @@ msgstr[1] "месяцев"
|
||||
#: utils/timesince.py:14
|
||||
msgid "week"
|
||||
msgid_plural "weeks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "неделя"
|
||||
msgstr[1] "недель"
|
||||
|
||||
#: utils/timesince.py:15
|
||||
msgid "day"
|
||||
@ -1610,11 +1592,11 @@ msgid "This value must contain only letters, numbers and underscores."
|
||||
msgstr "Значение может содержать только буквы, цифры и подчеркивания."
|
||||
|
||||
#: core/validators.py:64
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"This value must contain only letters, numbers, underscores, dashes or "
|
||||
"slashes."
|
||||
msgstr "Значение может содержать только буквы, цифры и подчеркивания."
|
||||
msgstr "Значение может содержать только буквы, цифры, подчеркивания, дифисы или "
|
||||
"тере."
|
||||
|
||||
#: core/validators.py:72
|
||||
msgid "Uppercase letters are not allowed here."
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ import datetime
|
||||
|
||||
class FilterSpec(object):
|
||||
filter_specs = []
|
||||
def __init__(self, f, request, params):
|
||||
def __init__(self, f, request, params, model):
|
||||
self.field = f
|
||||
self.params = params
|
||||
|
||||
@ -19,10 +19,10 @@ class FilterSpec(object):
|
||||
cls.filter_specs.append((test, factory))
|
||||
register = classmethod(register)
|
||||
|
||||
def create(cls, f, request, params):
|
||||
def create(cls, f, request, params, model):
|
||||
for test, factory in cls.filter_specs:
|
||||
if test(f):
|
||||
return factory(f, request, params)
|
||||
return factory(f, request, params, model)
|
||||
create = classmethod(create)
|
||||
|
||||
def has_output(self):
|
||||
@ -48,8 +48,8 @@ class FilterSpec(object):
|
||||
return "".join(t)
|
||||
|
||||
class RelatedFilterSpec(FilterSpec):
|
||||
def __init__(self, f, request, params):
|
||||
super(RelatedFilterSpec, self).__init__(f, request, params)
|
||||
def __init__(self, f, request, params, model):
|
||||
super(RelatedFilterSpec, self).__init__(f, request, params, model)
|
||||
if isinstance(f, models.ManyToManyField):
|
||||
self.lookup_title = f.rel.to._meta.verbose_name
|
||||
else:
|
||||
@ -77,8 +77,8 @@ class RelatedFilterSpec(FilterSpec):
|
||||
FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
|
||||
|
||||
class ChoicesFilterSpec(FilterSpec):
|
||||
def __init__(self, f, request, params):
|
||||
super(ChoicesFilterSpec, self).__init__(f, request, params)
|
||||
def __init__(self, f, request, params, model):
|
||||
super(ChoicesFilterSpec, self).__init__(f, request, params, model)
|
||||
self.lookup_kwarg = '%s__exact' % f.name
|
||||
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
|
||||
|
||||
@ -94,8 +94,8 @@ class ChoicesFilterSpec(FilterSpec):
|
||||
FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
|
||||
|
||||
class DateFieldFilterSpec(FilterSpec):
|
||||
def __init__(self, f, request, params):
|
||||
super(DateFieldFilterSpec, self).__init__(f, request, params)
|
||||
def __init__(self, f, request, params, model):
|
||||
super(DateFieldFilterSpec, self).__init__(f, request, params, model)
|
||||
|
||||
self.field_generic = '%s__' % self.field.name
|
||||
|
||||
@ -129,8 +129,8 @@ class DateFieldFilterSpec(FilterSpec):
|
||||
FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
|
||||
|
||||
class BooleanFieldFilterSpec(FilterSpec):
|
||||
def __init__(self, f, request, params):
|
||||
super(BooleanFieldFilterSpec, self).__init__(f, request, params)
|
||||
def __init__(self, f, request, params, model):
|
||||
super(BooleanFieldFilterSpec, self).__init__(f, request, params, model)
|
||||
self.lookup_kwarg = '%s__exact' % f.name
|
||||
self.lookup_kwarg2 = '%s__isnull' % f.name
|
||||
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
|
||||
@ -150,3 +150,26 @@ class BooleanFieldFilterSpec(FilterSpec):
|
||||
'display': _('Unknown')}
|
||||
|
||||
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)
|
||||
|
46
django/contrib/admin/media/css/rtl.css
Normal file
46
django/contrib/admin/media/css/rtl.css
Normal 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;}
|
@ -31,7 +31,7 @@ var CollapsedFieldsets = {
|
||||
collapse_link.id = 'fieldsetcollapser' + i;
|
||||
collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;');
|
||||
collapse_link.href = '#';
|
||||
collapse_link.innerHTML = 'Show';
|
||||
collapse_link.innerHTML = gettext('Show');
|
||||
var h2 = fs.getElementsByTagName('h2')[0];
|
||||
h2.appendChild(document.createTextNode(' ('));
|
||||
h2.appendChild(collapse_link);
|
||||
@ -60,7 +60,7 @@ var CollapsedFieldsets = {
|
||||
// Toggle the "Show" link to a "Hide" link
|
||||
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
|
||||
collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;');
|
||||
collapse_link.innerHTML = 'Hide';
|
||||
collapse_link.innerHTML = gettext('Hide');
|
||||
},
|
||||
hide: function(fieldset_index) {
|
||||
var fs = document.getElementsByTagName('fieldset')[fieldset_index];
|
||||
@ -69,7 +69,7 @@ var CollapsedFieldsets = {
|
||||
// Toggle the "Hide" link to a "Show" link
|
||||
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
|
||||
collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;');
|
||||
collapse_link.innerHTML = 'Show';
|
||||
collapse_link.innerHTML = gettext('Show');
|
||||
},
|
||||
|
||||
uncollapse_all: function() {
|
||||
|
@ -69,7 +69,16 @@ var DateTimeShortcuts = {
|
||||
var clock_box = document.createElement('div');
|
||||
clock_box.style.display = 'none';
|
||||
clock_box.style.position = 'absolute';
|
||||
if (getStyle(document.body,'direction')!='rtl') {
|
||||
clock_box.style.left = findPosX(clock_link) + 17 + 'px';
|
||||
}
|
||||
else {
|
||||
// since style's width is in em, it'd be tough to calculate
|
||||
// px value of it. let's use an estimated px for now
|
||||
// TODO: IE returns wrong value for findPosX when in rtl mode
|
||||
// (it returns as it was left aligned), needs to be fixed.
|
||||
clock_box.style.left = findPosX(clock_link) - 110 + 'px';
|
||||
}
|
||||
clock_box.style.top = findPosY(clock_link) - 30 + 'px';
|
||||
clock_box.className = 'clockbox module';
|
||||
clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
|
||||
@ -140,7 +149,17 @@ var DateTimeShortcuts = {
|
||||
var cal_box = document.createElement('div');
|
||||
cal_box.style.display = 'none';
|
||||
cal_box.style.position = 'absolute';
|
||||
// is it left-to-right or right-to-left layout ?
|
||||
if (getStyle(document.body,'direction')!='rtl') {
|
||||
cal_box.style.left = findPosX(cal_link) + 17 + 'px';
|
||||
}
|
||||
else {
|
||||
// since style's width is in em, it'd be tough to calculate
|
||||
// px value of it. let's use an estimated px for now
|
||||
// TODO: IE returns wrong value for findPosX when in rtl mode
|
||||
// (it returns as it was left aligned), needs to be fixed.
|
||||
cal_box.style.left = findPosX(cal_link) - 180 + 'px';
|
||||
}
|
||||
cal_box.style.top = findPosY(cal_link) - 75 + 'px';
|
||||
cal_box.className = 'calendarbox module';
|
||||
cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
|
||||
|
@ -136,3 +136,20 @@ String.prototype.pad_left = function(pad_length, pad_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;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<!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>
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<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 extrahead %}{% endblock %}
|
||||
</head>
|
||||
@ -20,7 +21,7 @@
|
||||
{% block branding %}{% endblock %}
|
||||
</div>
|
||||
{% 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 %}
|
||||
{% block nav-global %}{% endblock %}
|
||||
</div>
|
||||
|
@ -1,6 +1,7 @@
|
||||
{% load admin_list %}
|
||||
{% load i18n %}
|
||||
{% if cl.has_filters %}<div id="changelist-filter">
|
||||
<h2>Filter</h2>
|
||||
<h2>{% trans 'Filter' %}</h2>
|
||||
{% for spec in cl.filter_specs %}
|
||||
{% filter cl spec %}
|
||||
{% endfor %}</div>{% endif %}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% load admin_list %}
|
||||
{% load i18n %}
|
||||
<p class="paginator">
|
||||
{% if pagination_required %}
|
||||
{% for i in page_range %}
|
||||
@ -6,5 +7,5 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
|
||||
{% if show_all_url %} <a href="{{ show_all_url }}" class="showall">Show all</a>{% endif %}
|
||||
{% if show_all_url %} <a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
|
||||
</p>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" />
|
||||
<input type="submit" value="{% trans 'Go' %}" />
|
||||
{% 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 %}
|
||||
{% for pair in cl.params.items %}
|
||||
{% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% load i18n %}
|
||||
{% 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 %}
|
||||
|
||||
|
@ -131,7 +131,7 @@ def items_for_result(cl, result):
|
||||
|
||||
if isinstance(f.rel, models.ManyToOneRel):
|
||||
if field_val is not None:
|
||||
result_repr = getattr(result, f.name)
|
||||
result_repr = escape(getattr(result, f.name))
|
||||
else:
|
||||
result_repr = EMPTY_CHANGELIST_VALUE
|
||||
# Dates and times are special: They're formatted in a certain way.
|
||||
|
@ -18,6 +18,19 @@ def class_name_to_underscored(name):
|
||||
return '_'.join([s.lower() for s in word_re.findall(name)[:-1]])
|
||||
|
||||
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)
|
||||
include_admin_script = register.simple_tag(include_admin_script)
|
||||
|
||||
|
@ -574,7 +574,7 @@ class ChangeList(object):
|
||||
filter_fields = [self.lookup_opts.get_field(field_name) \
|
||||
for field_name in self.lookup_opts.admin.list_filter]
|
||||
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():
|
||||
filter_specs.append(spec)
|
||||
return filter_specs, bool(filter_specs)
|
||||
|
@ -23,8 +23,6 @@ def create_permissions(app, created_models):
|
||||
if not app_models:
|
||||
return
|
||||
for klass in app_models:
|
||||
if not klass._meta.admin:
|
||||
continue
|
||||
ctype = ContentType.objects.get_for_model(klass)
|
||||
for codename, name in _get_all_permissions(klass._meta):
|
||||
try:
|
||||
|
@ -8,7 +8,7 @@ class LazyUser(object):
|
||||
self._user = get_user(request)
|
||||
return self._user
|
||||
|
||||
class AuthenticationMiddleware:
|
||||
class AuthenticationMiddleware(object):
|
||||
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'."
|
||||
request.__class__.user = LazyUser()
|
||||
|
@ -8,7 +8,7 @@ from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
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."
|
||||
manipulator = AuthenticationForm(request)
|
||||
redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
|
||||
@ -25,19 +25,19 @@ def login(request):
|
||||
else:
|
||||
errors = {}
|
||||
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),
|
||||
REDIRECT_FIELD_NAME: redirect_to,
|
||||
'site_name': Site.objects.get_current().name,
|
||||
}, 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."
|
||||
from django.contrib.auth import logout
|
||||
try:
|
||||
logout(request)
|
||||
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:
|
||||
# Redirect to this page until the session has been cleared.
|
||||
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"
|
||||
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 = {}, {}
|
||||
form = PasswordResetForm()
|
||||
if request.POST:
|
||||
@ -62,13 +62,13 @@ def password_reset(request, is_admin_site=False):
|
||||
else:
|
||||
form.save()
|
||||
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))
|
||||
|
||||
def password_reset_done(request):
|
||||
return render_to_response('registration/password_reset_done.html', context_instance=RequestContext(request))
|
||||
def password_reset_done(request, template_name='registration/password_reset_done.html'):
|
||||
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 = {}, {}
|
||||
form = PasswordChangeForm(request.user)
|
||||
if request.POST:
|
||||
@ -77,9 +77,9 @@ def password_change(request):
|
||||
if not errors:
|
||||
form.save(new_data)
|
||||
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))
|
||||
password_change = login_required(password_change)
|
||||
|
||||
def password_change_done(request):
|
||||
return render_to_response('registration/password_change_done.html', context_instance=RequestContext(request))
|
||||
def password_change_done(request, template_name='registration/password_change_done.html'):
|
||||
return render_to_response(template_name, context_instance=RequestContext(request))
|
||||
|
24
django/contrib/contenttypes/management.py
Normal file
24
django/contrib/contenttypes/management.py
Normal 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)
|
@ -2,7 +2,7 @@ from django.contrib.flatpages.views import flatpage
|
||||
from django.http import Http404
|
||||
from django.conf import settings
|
||||
|
||||
class FlatpageFallbackMiddleware:
|
||||
class FlatpageFallbackMiddleware(object):
|
||||
def process_response(self, request, response):
|
||||
if response.status_code != 404:
|
||||
return response # No need to check for a flatpage for non-404 responses.
|
||||
|
@ -2,7 +2,7 @@ from django.contrib.redirects.models import Redirect
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
|
||||
class RedirectFallbackMiddleware:
|
||||
class RedirectFallbackMiddleware(object):
|
||||
def process_response(self, request, response):
|
||||
if response.status_code != 404:
|
||||
return response # No need to check for a redirect for non-404 responses.
|
||||
|
@ -8,15 +8,17 @@ class Redirect(models.Model):
|
||||
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,
|
||||
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('redirect')
|
||||
verbose_name_plural = _('redirects')
|
||||
db_table = 'django_redirect'
|
||||
unique_together=(('site', 'old_path'),)
|
||||
ordering = ('old_path',)
|
||||
|
||||
class Admin:
|
||||
list_filter = ('site',)
|
||||
search_fields = ('old_path', 'new_path')
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
return "%s ---> %s" % (self.old_path, self.new_path)
|
||||
|
@ -64,7 +64,7 @@ class SessionWrapper(object):
|
||||
|
||||
_session = property(_get_session)
|
||||
|
||||
class SessionMiddleware:
|
||||
class SessionMiddleware(object):
|
||||
def process_request(self, request):
|
||||
request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
|
||||
|
||||
|
@ -12,7 +12,7 @@ def add_domain(domain, url):
|
||||
class FeedDoesNotExist(ObjectDoesNotExist):
|
||||
pass
|
||||
|
||||
class Feed:
|
||||
class Feed(object):
|
||||
item_pubdate = None
|
||||
item_enclosure_url = None
|
||||
feed_type = feedgenerator.DefaultFeed
|
||||
@ -73,6 +73,7 @@ class Feed:
|
||||
author_name = self.__get_dynamic_attr('author_name', obj),
|
||||
author_link = self.__get_dynamic_attr('author_link', obj),
|
||||
author_email = self.__get_dynamic_attr('author_email', obj),
|
||||
categories = self.__get_dynamic_attr('categories', obj),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -110,5 +111,6 @@ class Feed:
|
||||
author_name = author_name,
|
||||
author_email = author_email,
|
||||
author_link = author_link,
|
||||
categories = self.__get_dynamic_attr('item_categories', item),
|
||||
)
|
||||
return feed
|
||||
|
2
django/core/cache/backends/base.py
vendored
2
django/core/cache/backends/base.py
vendored
@ -5,7 +5,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
class InvalidCacheBackendError(ImproperlyConfigured):
|
||||
pass
|
||||
|
||||
class BaseCache:
|
||||
class BaseCache(object):
|
||||
def __init__(self, params):
|
||||
timeout = params.get('timeout', 300)
|
||||
try:
|
||||
|
@ -36,6 +36,10 @@ def i18n(request):
|
||||
context_extras['LANGUAGE_CODE'] = request.LANGUAGE_CODE
|
||||
else:
|
||||
context_extras['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
|
||||
|
||||
from django.utils import translation
|
||||
context_extras['LANGUAGE_BIDI'] = translation.get_language_bidi()
|
||||
|
||||
return context_extras
|
||||
|
||||
def request(request):
|
||||
@ -44,7 +48,7 @@ def request(request):
|
||||
# PermWrapper and PermLookupDict proxy the permissions system into objects that
|
||||
# the template system can understand.
|
||||
|
||||
class PermLookupDict:
|
||||
class PermLookupDict(object):
|
||||
def __init__(self, user, module_name):
|
||||
self.user, self.module_name = user, module_name
|
||||
def __repr__(self):
|
||||
@ -54,7 +58,7 @@ class PermLookupDict:
|
||||
def __nonzero__(self):
|
||||
return self.user.has_module_perms(self.module_name)
|
||||
|
||||
class PermWrapper:
|
||||
class PermWrapper(object):
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
def __getitem__(self, module_name):
|
||||
|
@ -3,7 +3,7 @@ from django.dispatch import dispatcher
|
||||
from django import http
|
||||
import sys
|
||||
|
||||
class BaseHandler:
|
||||
class BaseHandler(object):
|
||||
def __init__(self):
|
||||
self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
|
||||
|
||||
|
@ -211,11 +211,14 @@ def _get_sql_for_pending_references(klass, pending_references):
|
||||
|
||||
def _get_many_to_many_sql_for_model(klass):
|
||||
from django.db import backend, get_creation_module
|
||||
from django.db.models import GenericRel
|
||||
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
|
||||
opts = klass._meta
|
||||
final_output = []
|
||||
for f in opts.many_to_many:
|
||||
if not isinstance(f.rel, GenericRel):
|
||||
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
|
||||
table_output.append(' %s %s %s,' % \
|
||||
@ -815,10 +818,8 @@ def get_validation_errors(outfile, app=None):
|
||||
|
||||
# Do field-specific validation.
|
||||
for f in opts.fields:
|
||||
# Check for deprecated args
|
||||
dep_args = getattr(f, 'deprecated_args', None)
|
||||
if dep_args:
|
||||
e.add(opts, "'%s' Initialized with deprecated args:%s" % (f.name, ",".join(dep_args)))
|
||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||
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 isinstance(f, models.CharField) and f.maxlength in (None, 0):
|
||||
e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
|
||||
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):
|
||||
e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
|
||||
if f.choices:
|
||||
if not type(f.choices) in (tuple, list):
|
||||
e.add(opts, '"%s": "choices" should be either a tuple or list.' % f.name)
|
||||
if not hasattr(f.choices, '__iter__'):
|
||||
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
|
||||
else:
|
||||
for c in f.choices:
|
||||
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:]
|
||||
if opts.order_with_respect_to and field_name == '_order':
|
||||
continue
|
||||
if '.' in field_name: continue # Skip ordering in the format 'table.field'.
|
||||
try:
|
||||
opts.get_field(field_name, many_to_many=False)
|
||||
except models.FieldDoesNotExist:
|
||||
|
@ -4,7 +4,7 @@ from math import ceil
|
||||
class InvalidPage(Exception):
|
||||
pass
|
||||
|
||||
class ObjectPaginator:
|
||||
class ObjectPaginator(object):
|
||||
"""
|
||||
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
|
||||
|
@ -21,7 +21,7 @@ software_version = server_version + ' ' + sys_version
|
||||
class WSGIServerException(Exception):
|
||||
pass
|
||||
|
||||
class FileWrapper:
|
||||
class FileWrapper(object):
|
||||
"""Wrapper to convert file-like objects to iterables"""
|
||||
|
||||
def __init__(self, filelike, blksize=8192):
|
||||
@ -63,7 +63,7 @@ def _formatparam(param, value=None, quote=1):
|
||||
else:
|
||||
return param
|
||||
|
||||
class Headers:
|
||||
class Headers(object):
|
||||
"""Manage a collection of HTTP response headers"""
|
||||
def __init__(self,headers):
|
||||
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 _hoppish(header_name.lower())
|
||||
|
||||
class ServerHandler:
|
||||
class ServerHandler(object):
|
||||
"""Manage the invocation of a WSGI application"""
|
||||
|
||||
# Configuration parameters; can override per-subclass or per-instance
|
||||
@ -591,7 +591,7 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
|
||||
return
|
||||
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
|
||||
defined by the ADMIN_MEDIA_PREFIX setting, and serves those images.
|
||||
|
@ -83,7 +83,7 @@ class MatchChecker(object):
|
||||
raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
|
||||
return str(value) # TODO: Unicode?
|
||||
|
||||
class RegexURLPattern:
|
||||
class RegexURLPattern(object):
|
||||
def __init__(self, regex, callback, default_args=None):
|
||||
# regex is a string representing a regular expression.
|
||||
# callback is something like 'foo.views.news.stories.story_detail',
|
||||
|
@ -237,7 +237,7 @@ def hasNoProfanities(field_data, all_data):
|
||||
"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')
|
||||
|
||||
class AlwaysMatchesOtherField:
|
||||
class AlwaysMatchesOtherField(object):
|
||||
def __init__(self, other_field_name, error_message=None):
|
||||
self.other = other_field_name
|
||||
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]:
|
||||
raise ValidationError, self.error_message
|
||||
|
||||
class ValidateIfOtherFieldEquals:
|
||||
class ValidateIfOtherFieldEquals(object):
|
||||
def __init__(self, other_field, other_value, validator_list):
|
||||
self.other_field, self.other_value = other_field, other_value
|
||||
self.validator_list = validator_list
|
||||
@ -258,7 +258,7 @@ class ValidateIfOtherFieldEquals:
|
||||
for v in self.validator_list:
|
||||
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.")):
|
||||
self.other, self.error_message = other_field_name, error_message
|
||||
self.always_test = True
|
||||
@ -267,7 +267,7 @@ class RequiredIfOtherFieldNotGiven:
|
||||
if not all_data.get(self.other, False) and not field_data:
|
||||
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.")):
|
||||
self.other, self.error_message = other_field_names, error_message
|
||||
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.")):
|
||||
RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)
|
||||
|
||||
class RequiredIfOtherFieldEquals:
|
||||
class RequiredIfOtherFieldEquals(object):
|
||||
def __init__(self, other_field, other_value, error_message=None):
|
||||
self.other_field = other_field
|
||||
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:
|
||||
raise ValidationError(self.error_message)
|
||||
|
||||
class RequiredIfOtherFieldDoesNotEqual:
|
||||
class RequiredIfOtherFieldDoesNotEqual(object):
|
||||
def __init__(self, other_field, other_value, error_message=None):
|
||||
self.other_field = other_field
|
||||
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:
|
||||
raise ValidationError(self.error_message)
|
||||
|
||||
class IsLessThanOtherField:
|
||||
class IsLessThanOtherField(object):
|
||||
def __init__(self, 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]:
|
||||
raise ValidationError, self.error_message
|
||||
|
||||
class UniqueAmongstFieldsWithPrefix:
|
||||
class UniqueAmongstFieldsWithPrefix(object):
|
||||
def __init__(self, field_name, prefix, error_message):
|
||||
self.field_name, self.prefix = field_name, prefix
|
||||
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:
|
||||
raise ValidationError, self.error_message
|
||||
|
||||
class IsAPowerOf:
|
||||
class IsAPowerOf(object):
|
||||
"""
|
||||
>>> v = IsAPowerOf(2)
|
||||
>>> v(4, None)
|
||||
@ -342,7 +342,7 @@ class IsAPowerOf:
|
||||
if val != int(val):
|
||||
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):
|
||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||
|
||||
@ -355,11 +355,14 @@ class IsValidFloat:
|
||||
if len(data) > (self.max_digits + 1):
|
||||
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
|
||||
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:
|
||||
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
|
||||
|
||||
class HasAllowableSize:
|
||||
class HasAllowableSize(object):
|
||||
"""
|
||||
Checks that the file-upload field data is a certain size. min_size and
|
||||
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:
|
||||
raise ValidationError, self.max_error_message
|
||||
|
||||
class MatchesRegularExpression:
|
||||
class MatchesRegularExpression(object):
|
||||
"""
|
||||
Checks that the field matches the given regular-expression. The regex
|
||||
should be in string format, not already compiled.
|
||||
@ -392,7 +395,7 @@ class MatchesRegularExpression:
|
||||
if not self.regexp.search(field_data):
|
||||
raise ValidationError(self.error_message)
|
||||
|
||||
class AnyValidator:
|
||||
class AnyValidator(object):
|
||||
"""
|
||||
This validator tries all given validators. If any one of them succeeds,
|
||||
validation passes. If none of them succeeds, the given message is thrown
|
||||
@ -416,7 +419,7 @@ class AnyValidator:
|
||||
pass
|
||||
raise ValidationError(self.error_message)
|
||||
|
||||
class URLMimeTypeCheck:
|
||||
class URLMimeTypeCheck(object):
|
||||
"Checks that the provided URL points to a document with a listed mime type"
|
||||
class CouldNotRetrieve(ValidationError):
|
||||
pass
|
||||
@ -441,7 +444,7 @@ class URLMimeTypeCheck:
|
||||
raise URLMimeTypeCheck.InvalidContentType, gettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
|
||||
'url': field_data, 'contenttype': content_type}
|
||||
|
||||
class RelaxNGCompact:
|
||||
class RelaxNGCompact(object):
|
||||
"Validate against a Relax NG compact schema"
|
||||
def __init__(self, schema_path, additional_root_element=None):
|
||||
self.schema_path = schema_path
|
||||
|
@ -131,6 +131,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return "DROP CONSTRAINT"
|
||||
|
||||
def get_pk_default_value():
|
||||
return "DEFAULT"
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '= %s',
|
||||
'iexact': 'LIKE %s',
|
||||
|
@ -158,6 +158,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return "DROP FOREIGN KEY"
|
||||
|
||||
def get_pk_default_value():
|
||||
return "DEFAULT"
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '= %s',
|
||||
'iexact': 'LIKE %s',
|
||||
|
@ -114,6 +114,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return "DROP FOREIGN KEY"
|
||||
|
||||
def get_pk_default_value():
|
||||
return "DEFAULT"
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '= %s',
|
||||
'iexact': 'LIKE %s',
|
||||
|
@ -108,6 +108,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return "DROP CONSTRAINT"
|
||||
|
||||
def get_pk_default_value():
|
||||
return "DEFAULT"
|
||||
|
||||
# Register these custom typecasts, because Django expects dates/times to be
|
||||
# in Python's native (standard-library) datetime/time format, whereas psycopg
|
||||
# use mx.DateTime by default.
|
||||
|
@ -114,6 +114,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return "DROP CONSTRAINT"
|
||||
|
||||
def get_pk_default_value():
|
||||
return "DEFAULT"
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '= %s',
|
||||
'iexact': 'ILIKE %s',
|
||||
|
@ -130,6 +130,9 @@ def get_fulltext_search_sql(field_name):
|
||||
def get_drop_foreignkey_sql():
|
||||
return ""
|
||||
|
||||
def get_pk_default_value():
|
||||
return "NULL"
|
||||
|
||||
def _sqlite_date_trunc(lookup_type, dt):
|
||||
try:
|
||||
dt = util.typecast_timestamp(dt)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import datetime
|
||||
from time import time
|
||||
|
||||
class CursorDebugWrapper:
|
||||
class CursorDebugWrapper(object):
|
||||
def __init__(self, cursor, db):
|
||||
self.cursor = cursor
|
||||
self.db = db
|
||||
|
@ -8,6 +8,7 @@ from django.db.models.manager import Manager
|
||||
from django.db.models.base import Model, AdminOptions
|
||||
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.generic import GenericRelation, GenericRel, GenericForeignKey
|
||||
from django.db.models import signals
|
||||
from django.utils.functional import curry
|
||||
from django.utils.text import capfirst
|
||||
@ -15,7 +16,7 @@ from django.utils.text import capfirst
|
||||
# Admin stages.
|
||||
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
|
||||
instead of when the model is loaded. For example::
|
||||
|
@ -107,6 +107,12 @@ class Model(object):
|
||||
else:
|
||||
val = kwargs.pop(f.attname, f.get_default())
|
||||
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:
|
||||
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
|
||||
for i, arg in enumerate(args):
|
||||
@ -165,7 +171,7 @@ class Model(object):
|
||||
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
||||
(backend.quote_name(self._meta.db_table),
|
||||
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
|
||||
backend.quote_name(self._meta.pk.attname)),
|
||||
backend.quote_name(self._meta.pk.column)),
|
||||
db_values + [pk_val])
|
||||
else:
|
||||
record_exists = False
|
||||
@ -183,9 +189,16 @@ class Model(object):
|
||||
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)))
|
||||
db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
|
||||
if db_values:
|
||||
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
|
||||
(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:
|
||||
setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
|
||||
transaction.commit_unless_managed()
|
||||
|
@ -535,7 +535,7 @@ class FileField(Field):
|
||||
if not self.blank:
|
||||
if rel:
|
||||
# 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):
|
||||
self.other_field_names = other_field_names
|
||||
self.other_file_field_name = other_file_field_name
|
||||
|
259
django/db/models/fields/generic.py
Normal file
259
django/db/models/fields/generic.py
Normal 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"
|
@ -667,7 +667,7 @@ class ManyToManyField(RelatedField, Field):
|
||||
def set_attributes_from_rel(self):
|
||||
pass
|
||||
|
||||
class ManyToOneRel:
|
||||
class ManyToOneRel(object):
|
||||
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,
|
||||
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.multiple = False
|
||||
|
||||
class ManyToManyRel:
|
||||
class ManyToManyRel(object):
|
||||
def __init__(self, to, num_in_admin=0, related_name=None,
|
||||
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
|
||||
self.to = to
|
||||
|
@ -3,6 +3,7 @@ from django.db import backend, connection
|
||||
from django.db.models.query import QuerySet
|
||||
from django.dispatch import dispatcher
|
||||
from django.db.models import signals
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.utils.datastructures import SortedDict
|
||||
|
||||
# Size of each "chunk" for get_iterator calls.
|
||||
@ -13,8 +14,11 @@ def ensure_default_manager(sender):
|
||||
cls = sender
|
||||
if not hasattr(cls, '_default_manager'):
|
||||
# Create the default manager, if needed.
|
||||
if hasattr(cls, 'objects'):
|
||||
raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name
|
||||
try:
|
||||
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())
|
||||
|
||||
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
|
||||
@ -65,6 +69,9 @@ class Manager(object):
|
||||
def get(self, *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):
|
||||
return self.get_query_set().filter(*args, **kwargs)
|
||||
|
||||
|
@ -15,7 +15,7 @@ DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
|
||||
'unique_together', 'permissions', 'get_latest_by',
|
||||
'order_with_respect_to', 'app_label')
|
||||
|
||||
class Options:
|
||||
class Options(object):
|
||||
def __init__(self, meta):
|
||||
self.fields, self.many_to_many = [], []
|
||||
self.module_name, self.verbose_name = None, None
|
||||
@ -195,7 +195,7 @@ class Options:
|
||||
self._field_types[field_type] = False
|
||||
return self._field_types[field_type]
|
||||
|
||||
class AdminOptions:
|
||||
class AdminOptions(object):
|
||||
def __init__(self, fields=None, js=None, list_display=None, list_filter=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):
|
||||
|
@ -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)
|
||||
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):
|
||||
"""
|
||||
Returns the latest object, according to the model's 'get_latest_by'
|
||||
@ -529,7 +546,7 @@ class DateQuerySet(QuerySet):
|
||||
c._order = self._order
|
||||
return c
|
||||
|
||||
class QOperator:
|
||||
class QOperator(object):
|
||||
"Base class for QAnd and QOr"
|
||||
def __init__(self, *args):
|
||||
self.args = args
|
||||
|
@ -114,7 +114,7 @@ def is_managed():
|
||||
def managed(flag=True):
|
||||
"""
|
||||
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
|
||||
commited.
|
||||
"""
|
||||
|
@ -101,7 +101,7 @@ class Manipulator(object):
|
||||
for field in self.fields:
|
||||
field.convert_post_data(new_data)
|
||||
|
||||
class FormWrapper:
|
||||
class FormWrapper(object):
|
||||
"""
|
||||
A wrapper linking a Manipulator to the template system.
|
||||
This allows dictionary-style lookups of formfields. It also handles feeding
|
||||
@ -150,7 +150,7 @@ class FormWrapper:
|
||||
|
||||
fields = property(_get_fields)
|
||||
|
||||
class FormFieldWrapper:
|
||||
class FormFieldWrapper(object):
|
||||
"A bridge between the template system and an individual form field. Used by FormWrapper."
|
||||
def __init__(self, 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):
|
||||
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."
|
||||
def __init__(self, parent_manipulator, rel_obj, data, errors):
|
||||
self.parent_manipulator = parent_manipulator
|
||||
@ -269,7 +269,7 @@ class InlineObjectCollection:
|
||||
self._collections = collections
|
||||
|
||||
|
||||
class FormField:
|
||||
class FormField(object):
|
||||
"""Abstract class representing a form field.
|
||||
|
||||
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.
|
||||
"""
|
||||
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 choices is None: choices = []
|
||||
self.ul_class = ul_class
|
||||
SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list)
|
||||
|
||||
def prepare(self, new_data):
|
||||
@ -628,7 +629,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
|
||||
new_data.setlist(self.field_name, data_list)
|
||||
|
||||
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
|
||||
for value, choice in self.choices:
|
||||
checked_html = ''
|
||||
@ -897,10 +898,11 @@ class FilePathField(SelectField):
|
||||
"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):
|
||||
import os
|
||||
from django.db.models import BLANK_CHOICE_DASH
|
||||
if match is not None:
|
||||
import re
|
||||
match_re = re.compile(match)
|
||||
choices = []
|
||||
choices = not is_required and BLANK_CHOICE_DASH[:] or []
|
||||
if recursive:
|
||||
for root, dirs, files in os.walk(path):
|
||||
for f in files:
|
||||
|
@ -265,6 +265,12 @@ class HttpResponseForbidden(HttpResponse):
|
||||
HttpResponse.__init__(self, *args, **kwargs)
|
||||
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):
|
||||
def __init__(self, *args, **kwargs):
|
||||
HttpResponse.__init__(self, *args, **kwargs)
|
||||
|
@ -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.http import HttpResponseNotModified
|
||||
|
||||
class CacheMiddleware:
|
||||
class CacheMiddleware(object):
|
||||
"""
|
||||
Cache middleware. If this is enabled, each Django-powered page will be
|
||||
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs.
|
||||
|
@ -3,7 +3,7 @@ from django import http
|
||||
from django.core.mail import mail_managers
|
||||
import md5, os
|
||||
|
||||
class CommonMiddleware:
|
||||
class CommonMiddleware(object):
|
||||
"""
|
||||
"Common" middleware for taking care of some basic operations:
|
||||
|
||||
@ -39,6 +39,8 @@ class CommonMiddleware:
|
||||
# trailing slash or a file extension.
|
||||
if settings.APPEND_SLASH and (old_url[1][-1] != '/') and ('.' not in old_url[1].split('/')[-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:
|
||||
# Redirect
|
||||
if new_url[0]:
|
||||
|
@ -1,7 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django import http
|
||||
|
||||
class XViewMiddleware:
|
||||
class XViewMiddleware(object):
|
||||
"""
|
||||
Adds an X-View header to internal HEAD requests -- used by the documentation system.
|
||||
"""
|
||||
|
@ -4,7 +4,7 @@ from django.utils.cache import patch_vary_headers
|
||||
|
||||
re_accepts_gzip = re.compile(r'\bgzip\b')
|
||||
|
||||
class GZipMiddleware:
|
||||
class GZipMiddleware(object):
|
||||
"""
|
||||
This middleware compresses content if the browser allows gzip compression.
|
||||
It sets the Vary header accordingly, so that caches will base their storage
|
||||
|
@ -1,6 +1,6 @@
|
||||
import datetime
|
||||
|
||||
class ConditionalGetMiddleware:
|
||||
class ConditionalGetMiddleware(object):
|
||||
"""
|
||||
Handles conditional GET operations. If the response has a ETag or
|
||||
Last-Modified header, and the request has If-None-Match or
|
||||
|
@ -3,7 +3,7 @@
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from django.utils import translation
|
||||
|
||||
class LocaleMiddleware:
|
||||
class LocaleMiddleware(object):
|
||||
"""
|
||||
This is a very simple middleware that parses a request
|
||||
and decides what translation object to install in the current
|
||||
|
@ -1,7 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
|
||||
class TransactionMiddleware:
|
||||
class TransactionMiddleware(object):
|
||||
"""
|
||||
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
|
||||
|
@ -56,9 +56,10 @@ times with multiple contexts)
|
||||
"""
|
||||
import re
|
||||
from inspect import getargspec
|
||||
from django.utils.functional import curry
|
||||
from django.conf import settings
|
||||
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')
|
||||
|
||||
@ -74,6 +75,8 @@ BLOCK_TAG_START = '{%'
|
||||
BLOCK_TAG_END = '%}'
|
||||
VARIABLE_TAG_START = '{{'
|
||||
VARIABLE_TAG_END = '}}'
|
||||
SINGLE_BRACE_START = '{'
|
||||
SINGLE_BRACE_END = '}'
|
||||
|
||||
ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
|
||||
|
||||
@ -133,7 +136,7 @@ class StringOrigin(Origin):
|
||||
def reload(self):
|
||||
return self.source
|
||||
|
||||
class Template:
|
||||
class Template(object):
|
||||
def __init__(self, template_string, origin=None):
|
||||
"Compilation stage"
|
||||
if settings.TEMPLATE_DEBUG and origin == None:
|
||||
@ -157,22 +160,18 @@ def compile_string(template_string, origin):
|
||||
parser = parser_factory(lexer.tokenize())
|
||||
return parser.parse()
|
||||
|
||||
class Token:
|
||||
class Token(object):
|
||||
def __init__(self, token_type, contents):
|
||||
"The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK"
|
||||
self.token_type, self.contents = token_type, contents
|
||||
|
||||
def __str__(self):
|
||||
return '<%s token: "%s...">' % (
|
||||
{TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
|
||||
self.contents[:20].replace('\n', '')
|
||||
)
|
||||
return '<%s token: "%s...">' % \
|
||||
({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
|
||||
self.contents[:20].replace('\n', ''))
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s token: "%s">' % (
|
||||
{TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
|
||||
self.contents[:].replace('\n', '')
|
||||
)
|
||||
def split_contents(self):
|
||||
return smart_split(self.contents)
|
||||
|
||||
class Lexer(object):
|
||||
def __init__(self, template_string, origin):
|
||||
@ -367,7 +366,6 @@ class DebugParser(Parser):
|
||||
if not hasattr(e, 'source'):
|
||||
e.source = token.source
|
||||
|
||||
|
||||
def lexer_factory(*args, **kwargs):
|
||||
if settings.TEMPLATE_DEBUG:
|
||||
return DebugLexer(*args, **kwargs)
|
||||
@ -380,8 +378,7 @@ def parser_factory(*args, **kwargs):
|
||||
else:
|
||||
return Parser(*args, **kwargs)
|
||||
|
||||
|
||||
class TokenParser:
|
||||
class TokenParser(object):
|
||||
"""
|
||||
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.
|
||||
@ -564,7 +561,7 @@ class FilterExpression(object):
|
||||
def args_check(name, func, provided):
|
||||
provided = list(provided)
|
||||
plen = len(provided)
|
||||
(args, varargs, varkw, defaults) = getargspec(func)
|
||||
args, varargs, varkw, defaults = getargspec(func)
|
||||
# First argument is filter input.
|
||||
args.pop(0)
|
||||
if defaults:
|
||||
@ -614,7 +611,7 @@ def resolve_variable(path, context):
|
||||
|
||||
(The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
|
||||
"""
|
||||
if path[0] in '0123456789':
|
||||
if path[0].isdigit():
|
||||
number_type = '.' in path and float or int
|
||||
try:
|
||||
current = number_type(path)
|
||||
@ -659,7 +656,7 @@ def resolve_variable(path, context):
|
||||
del bits[0]
|
||||
return current
|
||||
|
||||
class Node:
|
||||
class Node(object):
|
||||
def render(self, context):
|
||||
"Return the node rendered as a string"
|
||||
pass
|
||||
@ -820,7 +817,7 @@ class Library(object):
|
||||
return func
|
||||
|
||||
def simple_tag(self,func):
|
||||
(params, xx, xxx, defaults) = getargspec(func)
|
||||
params, xx, xxx, defaults = getargspec(func)
|
||||
|
||||
class SimpleNode(Node):
|
||||
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 dec(func):
|
||||
(params, xx, xxx, defaults) = getargspec(func)
|
||||
params, xx, xxx, defaults = getargspec(func)
|
||||
if takes_context:
|
||||
if params[0] == 'context':
|
||||
params = params[1:]
|
||||
|
@ -7,7 +7,7 @@ class ContextPopException(Exception):
|
||||
"pop() has been called more times than push()"
|
||||
pass
|
||||
|
||||
class Context:
|
||||
class Context(object):
|
||||
"A stack container for variable context"
|
||||
def __init__(self, dict_=None):
|
||||
dict_ = dict_ or {}
|
||||
|
@ -330,6 +330,8 @@ def get_digit(value, arg):
|
||||
def date(value, arg=None):
|
||||
"Formats a date according to the given format"
|
||||
from django.utils.dateformat import format
|
||||
if not value:
|
||||
return ''
|
||||
if arg is None:
|
||||
arg = settings.DATE_FORMAT
|
||||
return format(value, arg)
|
||||
@ -337,6 +339,8 @@ def date(value, arg=None):
|
||||
def time(value, arg=None):
|
||||
"Formats a time according to the given format"
|
||||
from django.utils.dateformat import time_format
|
||||
if not value:
|
||||
return ''
|
||||
if arg is None:
|
||||
arg = settings.TIME_FORMAT
|
||||
return time_format(value, arg)
|
||||
@ -344,6 +348,8 @@ def time(value, arg=None):
|
||||
def timesince(value):
|
||||
'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
|
||||
from django.utils.timesince import timesince
|
||||
if not value:
|
||||
return ''
|
||||
return timesince(value)
|
||||
|
||||
###################
|
||||
|
@ -1,7 +1,7 @@
|
||||
"Default tags used by the template system, available to all templates."
|
||||
|
||||
from django.template import Node, NodeList, Template, Context, resolve_variable
|
||||
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END
|
||||
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.conf import settings
|
||||
import sys
|
||||
@ -149,9 +149,10 @@ class IfEqualNode(Node):
|
||||
return self.nodelist_false.render(context)
|
||||
|
||||
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.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
||||
self.link_type = link_type
|
||||
|
||||
def __repr__(self):
|
||||
return "<If node>"
|
||||
@ -171,6 +172,7 @@ class IfNode(Node):
|
||||
return nodes
|
||||
|
||||
def render(self, context):
|
||||
if self.link_type == IfNode.LinkTypes.or_:
|
||||
for ifnot, bool_expr in self.bool_exprs:
|
||||
try:
|
||||
value = bool_expr.resolve(context)
|
||||
@ -179,6 +181,19 @@ class IfNode(Node):
|
||||
if (value and not ifnot) or (ifnot and not value):
|
||||
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):
|
||||
def __init__(self, target, expression, var_name):
|
||||
@ -260,7 +275,10 @@ class TemplateTagNode(Node):
|
||||
mapping = {'openblock': BLOCK_TAG_START,
|
||||
'closeblock': BLOCK_TAG_END,
|
||||
'openvariable': VARIABLE_TAG_START,
|
||||
'closevariable': VARIABLE_TAG_END}
|
||||
'closevariable': VARIABLE_TAG_END,
|
||||
'openbrace': SINGLE_BRACE_START,
|
||||
'closebrace': SINGLE_BRACE_END,
|
||||
}
|
||||
|
||||
def __init__(self, tagtype):
|
||||
self.tagtype = tagtype
|
||||
@ -487,7 +505,7 @@ def do_ifequal(parser, token, negate):
|
||||
...
|
||||
{% endifnotequal %}
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
bits = list(token.split_contents())
|
||||
if len(bits) != 3:
|
||||
raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
|
||||
end_tag = 'end' + bits[0]
|
||||
@ -561,11 +579,22 @@ def do_if(parser, token):
|
||||
if not bits:
|
||||
raise TemplateSyntaxError, "'if' statement requires at least one argument"
|
||||
# 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 = []
|
||||
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:
|
||||
if ' ' in boolpair:
|
||||
try:
|
||||
not_, boolvar = boolpair.split()
|
||||
except ValueError:
|
||||
raise TemplateSyntaxError, "'if' statement improperly formatted"
|
||||
if not_ != 'not':
|
||||
raise TemplateSyntaxError, "Expected 'not' in if statement"
|
||||
boolvars.append((True, parser.compile_filter(boolvar)))
|
||||
@ -578,7 +607,7 @@ def do_if(parser, token):
|
||||
parser.delete_first_token()
|
||||
else:
|
||||
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)
|
||||
|
||||
#@register.tag
|
||||
@ -783,6 +812,8 @@ def templatetag(parser, token):
|
||||
``closeblock`` ``%}``
|
||||
``openvariable`` ``{{``
|
||||
``closevariable`` ``}}``
|
||||
``openbrace`` ``{``
|
||||
``closebrace`` ``}``
|
||||
================== =======
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
|
@ -1,4 +1,4 @@
|
||||
class MergeDict:
|
||||
class MergeDict(object):
|
||||
"""
|
||||
A simple class for creating new "virtual" dictionaries that actualy look
|
||||
up values in more than one dictionary, passed in the constructor.
|
||||
|
@ -19,7 +19,7 @@ import re, time
|
||||
re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
|
||||
re_escaped = re.compile(r'\\(.)')
|
||||
|
||||
class Formatter:
|
||||
class Formatter(object):
|
||||
def format(self, formatstr):
|
||||
pieces = []
|
||||
for i, piece in enumerate(re_formatchars.split(formatstr)):
|
||||
|
@ -36,7 +36,7 @@ def get_tag_uri(url, date):
|
||||
tag = re.sub('#', '/', tag)
|
||||
return 'tag:' + tag
|
||||
|
||||
class SyndicationFeed:
|
||||
class SyndicationFeed(object):
|
||||
"Base class for all syndication feeds. Subclasses should provide write()"
|
||||
def __init__(self, title, link, description, language=None, author_email=None,
|
||||
author_name=None, author_link=None, subtitle=None, categories=None,
|
||||
@ -108,7 +108,7 @@ class SyndicationFeed:
|
||||
else:
|
||||
return datetime.datetime.now()
|
||||
|
||||
class Enclosure:
|
||||
class Enclosure(object):
|
||||
"Represents an RSS enclosure"
|
||||
def __init__(self, url, length, mime_type):
|
||||
"All args are expected to be Python Unicode objects"
|
||||
@ -126,6 +126,8 @@ class RssFeed(SyndicationFeed):
|
||||
handler.addQuickElement(u"description", self.feed['description'])
|
||||
if self.feed['language'] is not None:
|
||||
handler.addQuickElement(u"language", self.feed['language'])
|
||||
for cat in self.feed['categories']:
|
||||
handler.addQuickElement(u"category", cat)
|
||||
self.write_items(handler)
|
||||
self.endChannelElement(handler)
|
||||
handler.endElement(u"rss")
|
||||
|
@ -109,3 +109,21 @@ def javascript_quote(s):
|
||||
s = s.replace("'", "\\'")
|
||||
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
|
||||
|
@ -111,6 +111,12 @@ def technical_500_response(request, exc_type, exc_value, tb):
|
||||
})
|
||||
tb = tb.tb_next
|
||||
|
||||
if not frames:
|
||||
frames = [{
|
||||
'filename': '<unknown>',
|
||||
'function': '?',
|
||||
'lineno': '?',
|
||||
}]
|
||||
t = Template(TECHNICAL_500_TEMPLATE)
|
||||
c = Context({
|
||||
'exception_type': exc_type.__name__,
|
||||
|
@ -106,6 +106,8 @@ def update_object(request, model, object_id=None, slug=None,
|
||||
|
||||
if request.POST:
|
||||
new_data = request.POST.copy()
|
||||
if model._meta.has_field_type(FileField):
|
||||
new_data.update(request.FILES)
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
manipulator.do_html2python(new_data)
|
||||
if not errors:
|
||||
|
@ -49,8 +49,8 @@ humanize
|
||||
========
|
||||
|
||||
A set of Django template filters useful for adding a "human touch" to data.
|
||||
To activate these filters, add ``'django.contrib.english'`` to your
|
||||
``INSTALLED_APPS`` setting. Once you've done that, use ``{% load english %}``
|
||||
To activate these filters, add ``'django.contrib.humanize'`` to your
|
||||
``INSTALLED_APPS`` setting. Once you've done that, use ``{% load humanize %}``
|
||||
in a template, and you'll have access to these filters:
|
||||
|
||||
apnumber
|
||||
|
@ -355,8 +355,8 @@ Here's what ``django.contrib.auth.views.login`` does::
|
||||
form.
|
||||
|
||||
It's your responsibility to provide the login form in a template called
|
||||
``registration/login.html``. This template gets passed three template context
|
||||
variables:
|
||||
``registration/login.html`` by default. This template gets passed three
|
||||
template context variables:
|
||||
|
||||
* ``form``: A ``FormWrapper`` object representing the login form. See the
|
||||
`forms documentation`_ for more on ``FormWrapper`` objects.
|
||||
@ -365,6 +365,13 @@ variables:
|
||||
* ``site_name``: The name of the current ``Site``, according to the
|
||||
``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
|
||||
point. It assumes you have a ``base.html`` template that defines a ``content``
|
||||
block::
|
||||
|
@ -559,7 +559,7 @@ following models::
|
||||
# ...
|
||||
hometown = models.ForeignKey(City)
|
||||
|
||||
class Book(meta.Model):
|
||||
class Book(models.Model):
|
||||
# ...
|
||||
author = models.ForeignKey(Person)
|
||||
|
||||
@ -705,6 +705,64 @@ The ``DoesNotExist`` exception inherits from
|
||||
except ObjectDoesNotExist:
|
||||
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()``
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
41
docs/faq.txt
41
docs/faq.txt
@ -200,6 +200,23 @@ In the meantime, though, check out this `unofficial Django screencast`_.
|
||||
|
||||
.. _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?
|
||||
---------------------------------
|
||||
|
||||
@ -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
|
||||
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.
|
||||
|
||||
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?
|
||||
---------------------------------------
|
||||
|
||||
* 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
|
||||
`Running mod_python on Apache on Windows2000`_.
|
||||
* Also, try this (not Windows-specific) `guide to getting mod_python
|
||||
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
|
||||
.. _`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 you don't mind clearing data, just pipe the output of the appropriate
|
||||
``django-admin.py sqlreset`` command into your database's command-line utility.
|
||||
For example::
|
||||
If you don't mind clearing data, your project's ``manage.py`` utility has an
|
||||
option to reset the SQL for a particular application::
|
||||
|
||||
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
|
||||
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.
|
||||
This drops any tables associated with ``appname`` and recreates them.
|
||||
|
||||
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,
|
||||
|
@ -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
|
||||
this document, we'll be working with the following model, a "place" object::
|
||||
|
||||
from django.db import models
|
||||
|
||||
PLACE_TYPES = (
|
||||
(1, 'Bar'),
|
||||
(2, 'Restaurant'),
|
||||
@ -22,13 +24,13 @@ this document, we'll be working with the following model, a "place" object::
|
||||
(4, 'Secret Hideout'),
|
||||
)
|
||||
|
||||
class Place(meta.Model):
|
||||
name = meta.CharField(maxlength=100)
|
||||
address = meta.CharField(maxlength=100, blank=True)
|
||||
city = meta.CharField(maxlength=50, blank=True)
|
||||
state = meta.USStateField()
|
||||
zip_code = meta.CharField(maxlength=5, blank=True)
|
||||
place_type = meta.IntegerField(choices=PLACE_TYPES)
|
||||
class Place(models.Model):
|
||||
name = models.CharField(maxlength=100)
|
||||
address = models.CharField(maxlength=100, blank=True)
|
||||
city = models.CharField(maxlength=50, blank=True)
|
||||
state = models.USStateField()
|
||||
zip_code = models.CharField(maxlength=5, blank=True)
|
||||
place_type = models.IntegerField(choices=PLACE_TYPES)
|
||||
|
||||
class Admin:
|
||||
pass
|
||||
|
@ -133,8 +133,8 @@ For example, to translate a model's ``help_text``, do the following::
|
||||
|
||||
from django.utils.translation import gettext_lazy
|
||||
|
||||
class MyThing(meta.Model):
|
||||
name = meta.CharField(help_text=gettext_lazy('This is the help text'))
|
||||
class MyThing(models.Model):
|
||||
name = models.CharField(help_text=gettext_lazy('This is the help text'))
|
||||
|
||||
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
|
||||
@ -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 _
|
||||
|
||||
class MyThing(meta.Model):
|
||||
name = meta.CharField(help_text=_('This is the help text'))
|
||||
class MyThing(models.Model):
|
||||
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
|
||||
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 _
|
||||
|
||||
class MyThing(meta.Model):
|
||||
name = meta.CharField(_('name'), help_text=_('This is the help text'))
|
||||
class MyThing(models.Model):
|
||||
name = models.CharField(_('name'), help_text=_('This is the help text'))
|
||||
class Meta:
|
||||
verbose_name = _('my thing')
|
||||
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`` is the current user's preferred language, as a string.
|
||||
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
|
||||
two tags::
|
||||
three tags::
|
||||
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% get_available_languages as LANGUAGES %}
|
||||
{% get_current_language_bidi as LANGUAGE_BIDI %}
|
||||
|
||||
These tags also require a ``{% load i18n %}``.
|
||||
|
||||
|
@ -445,7 +445,8 @@ empty value. If a field has ``blank=False``, the field will be required.
|
||||
``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
|
||||
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):
|
||||
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``
|
||||
~~~~~~~~
|
||||
|
||||
|
@ -400,6 +400,10 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
|
||||
``HttpResponseForbidden``
|
||||
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``
|
||||
Acts just like ``HttpResponse`` but uses a 410 status code.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
# 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
|
||||
# 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 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
|
||||
=======================
|
||||
|
||||
|
@ -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
|
||||
will be displayed if the test fails.
|
||||
|
||||
``if`` tags may use ``or`` or ``not`` to test a number of variables or to negate
|
||||
a given variable::
|
||||
``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or
|
||||
to negate a given variable::
|
||||
|
||||
{% if athlete_list and coach_list %}
|
||||
Both athletes and coaches are available.
|
||||
{% endif %}
|
||||
|
||||
{% if not athlete_list %}
|
||||
There are no athletes.
|
||||
@ -468,16 +472,24 @@ a given variable::
|
||||
{% if not athlete_list or coach_list %}
|
||||
There are no athletes or there are some coaches (OK, so
|
||||
writing English translations of boolean logic sounds
|
||||
stupid; it's not my fault).
|
||||
stupid; it's not our fault).
|
||||
{% endif %}
|
||||
|
||||
For simplicity, ``if`` tags do not allow ``and`` clauses; use nested ``if``
|
||||
tags instead::
|
||||
{% if athlete_list and not coach_list %}
|
||||
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 coach_list %}
|
||||
Number of athletes: {{ athlete_list|length }}.
|
||||
Number of coaches: {{ coach_list|length }}.
|
||||
{% if coach_list or cheerleader_list %}
|
||||
We have athletes, and either coaches or cheerleaders!
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@ -754,6 +766,8 @@ The argument tells which template bit to output:
|
||||
``closeblock`` ``%}``
|
||||
``openvariable`` ``{{``
|
||||
``closevariable`` ``}}``
|
||||
``openbrace`` ``{``
|
||||
``closebrace`` ``}``
|
||||
================== =======
|
||||
|
||||
widthratio
|
||||
|
@ -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.
|
||||
|
||||
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::
|
||||
|
||||
polls/
|
||||
models/
|
||||
models.py
|
||||
templatetags/
|
||||
views.py
|
||||
|
||||
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
|
||||
|
@ -8,7 +8,8 @@ this behavior by explicitly adding ``primary_key=True`` to a field.
|
||||
from django.db import models
|
||||
|
||||
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)
|
||||
last_name = models.CharField(maxlength=20)
|
||||
class Meta:
|
||||
|
0
tests/modeltests/empty/__init__.py
Normal file
0
tests/modeltests/empty/__init__.py
Normal file
24
tests/modeltests/empty/models.py
Normal file
24
tests/modeltests/empty/models.py
Normal 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
|
||||
|
||||
"""
|
0
tests/modeltests/generic_relations/__init__.py
Normal file
0
tests/modeltests/generic_relations/__init__.py
Normal file
108
tests/modeltests/generic_relations/models.py
Normal file
108
tests/modeltests/generic_relations/models.py
Normal 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>]
|
||||
"""
|
0
tests/modeltests/get_or_create/__init__.py
Normal file
0
tests/modeltests/get_or_create/__init__.py
Normal file
52
tests/modeltests/get_or_create/models.py
Normal file
52
tests/modeltests/get_or_create/models.py
Normal 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
|
||||
"""
|
@ -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: "filefield": FileFields require an "upload_to" attribute.
|
||||
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: "index": "db_index" should be either None, True or False.
|
||||
|
@ -12,8 +12,14 @@ class Person(models.Model):
|
||||
|
||||
def _get_full_name(self):
|
||||
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_2 = property(_get_full_name, _set_full_name)
|
||||
|
||||
API_TESTS = """
|
||||
>>> a = Person(first_name='John', last_name='Lennon')
|
||||
>>> a.save()
|
||||
@ -25,4 +31,10 @@ API_TESTS = """
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
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'
|
||||
"""
|
||||
|
@ -169,8 +169,7 @@ TEMPLATE_TESTS = {
|
||||
'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"),
|
||||
|
||||
### CYCLE TAG #############################################################
|
||||
#'cycleXX': ('', {}, ''),
|
||||
'cycle01': ('{% cycle a, %}', {}, 'a'),
|
||||
'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError),
|
||||
'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'),
|
||||
'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'),
|
||||
@ -193,13 +192,11 @@ TEMPLATE_TESTS = {
|
||||
'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
|
||||
|
||||
### FILTER TAG ############################################################
|
||||
#'filterXX': ('', {}, ''),
|
||||
'filter01': ('{% filter upper %}{% endfilter %}', {}, ''),
|
||||
'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'),
|
||||
'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'),
|
||||
|
||||
### FIRSTOF TAG ###########################################################
|
||||
#'firstofXX': ('', {}, ''),
|
||||
'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''),
|
||||
'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'),
|
||||
'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-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 #########################################################
|
||||
#'ifchangedXX': ('', {}, ''),
|
||||
'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'),
|
||||
'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"),
|
||||
'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 ########################################################
|
||||
'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
|
||||
'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
|
||||
@ -388,7 +468,6 @@ TEMPLATE_TESTS = {
|
||||
"""),
|
||||
|
||||
### REGROUP TAG ###########################################################
|
||||
#'regroupXX': ('', {}, ''),
|
||||
'regroup01': ('{% regroup data by bar as grouped %}' + \
|
||||
'{% for group in grouped %}' + \
|
||||
'{{ group.grouper }}:' + \
|
||||
@ -414,16 +493,18 @@ TEMPLATE_TESTS = {
|
||||
{}, ''),
|
||||
|
||||
### TEMPLATETAG TAG #######################################################
|
||||
#'templatetagXX': ('', {}, ''),
|
||||
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
||||
'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),
|
||||
'templatetag03': ('{% templatetag openvariable %}', {}, '{{'),
|
||||
'templatetag04': ('{% templatetag closevariable %}', {}, '}}'),
|
||||
'templatetag05': ('{% templatetag %}', {}, 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 ########################################################
|
||||
#'widthratioXX': ('', {}, ''),
|
||||
'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
|
||||
'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''),
|
||||
'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user