1
0
mirror of https://github.com/django/django.git synced 2025-07-07 11:19:12 +00:00

queryset-refactor: Merged from trunk up to [6724].

git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6726 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-11-28 21:51:17 +00:00
parent 5d85a5147b
commit a97abcffc2
34 changed files with 892 additions and 327 deletions

View File

@ -11,11 +11,10 @@ except NameError:
def compile_messages(locale=None): def compile_messages(locale=None):
basedirs = [os.path.join('conf', 'locale'), 'locale'] basedirs = (os.path.join('conf', 'locale'), 'locale')
if os.environ.get('DJANGO_SETTINGS_MODULE'): if os.environ.get('DJANGO_SETTINGS_MODULE'):
from django.conf import settings from django.conf import settings
if hasattr(settings, 'LOCALE_PATHS'): basedirs += settings.LOCALE_PATHS
basedirs += settings.LOCALE_PATHS
# Gather existing directories. # Gather existing directories.
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs))) basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))

View File

@ -90,6 +90,8 @@ LANGUAGES_BIDI = ("he", "ar", "fa")
# to load the internationalization machinery. # to load the internationalization machinery.
USE_I18N = True USE_I18N = True
LOCALE_PATHS = ()
# Not-necessarily-technical managers of the site. They get broken link # Not-necessarily-technical managers of the site. They get broken link
# notifications and other various e-mails. # notifications and other various e-mails.
MANAGERS = ADMINS MANAGERS = ADMINS

View File

@ -5,7 +5,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: django\n" "Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-11-13 21:55+0100\n" "POT-Creation-Date: 2007-11-15 15:28+0100\n"
"PO-Revision-Date: 2007-05-08 20:29+0200\n" "PO-Revision-Date: 2007-05-08 20:29+0200\n"
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n" "Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
"Language-Team: Polish <pl@li.org>\n" "Language-Team: Polish <pl@li.org>\n"
@ -196,7 +196,7 @@ msgstr "Uproszczony chiński"
msgid "Traditional Chinese" msgid "Traditional Chinese"
msgstr "Chiński tradycyjny" msgstr "Chiński tradycyjny"
#: contrib/admin/filterspecs.py:42 #: contrib/admin/filterspecs.py:44
#, python-format #, python-format
msgid "" msgid ""
"<h3>By %s:</h3>\n" "<h3>By %s:</h3>\n"
@ -205,71 +205,71 @@ msgstr ""
"<h3>Przez %s:</h3>\n" "<h3>Przez %s:</h3>\n"
"</ul>\n" "</ul>\n"
#: contrib/admin/filterspecs.py:72 contrib/admin/filterspecs.py:90 #: contrib/admin/filterspecs.py:74 contrib/admin/filterspecs.py:92
#: contrib/admin/filterspecs.py:145 contrib/admin/filterspecs.py:171 #: contrib/admin/filterspecs.py:147 contrib/admin/filterspecs.py:173
msgid "All" msgid "All"
msgstr "Wszystko" msgstr "Wszystko"
#: contrib/admin/filterspecs.py:111 #: contrib/admin/filterspecs.py:113
msgid "Any date" msgid "Any date"
msgstr "Dowolna data" msgstr "Dowolna data"
#: contrib/admin/filterspecs.py:112 #: contrib/admin/filterspecs.py:114
msgid "Today" msgid "Today"
msgstr "Dzisiaj" msgstr "Dzisiaj"
#: contrib/admin/filterspecs.py:115 #: contrib/admin/filterspecs.py:117
msgid "Past 7 days" msgid "Past 7 days"
msgstr "Ostatnie 7 dni" msgstr "Ostatnie 7 dni"
#: contrib/admin/filterspecs.py:117 #: contrib/admin/filterspecs.py:119
msgid "This month" msgid "This month"
msgstr "Ten miesiąc" msgstr "Ten miesiąc"
#: contrib/admin/filterspecs.py:119 #: contrib/admin/filterspecs.py:121
msgid "This year" msgid "This year"
msgstr "Ten rok" msgstr "Ten rok"
#: contrib/admin/filterspecs.py:145 newforms/widgets.py:221 #: contrib/admin/filterspecs.py:147 newforms/widgets.py:229
#: oldforms/__init__.py:591 #: oldforms/__init__.py:592
msgid "Yes" msgid "Yes"
msgstr "Tak" msgstr "Tak"
#: contrib/admin/filterspecs.py:145 newforms/widgets.py:221 #: contrib/admin/filterspecs.py:147 newforms/widgets.py:229
#: oldforms/__init__.py:591 #: oldforms/__init__.py:592
msgid "No" msgid "No"
msgstr "Nie" msgstr "Nie"
#: contrib/admin/filterspecs.py:152 newforms/widgets.py:221 #: contrib/admin/filterspecs.py:154 newforms/widgets.py:229
#: oldforms/__init__.py:591 #: oldforms/__init__.py:592
msgid "Unknown" msgid "Unknown"
msgstr "Nieznany" msgstr "Nieznany"
#: contrib/admin/models.py:17 #: contrib/admin/models.py:18
msgid "action time" msgid "action time"
msgstr "czas akcji" msgstr "czas akcji"
#: contrib/admin/models.py:20 #: contrib/admin/models.py:21
msgid "object id" msgid "object id"
msgstr "id obiektu" msgstr "id obiektu"
#: contrib/admin/models.py:21 #: contrib/admin/models.py:22
msgid "object repr" msgid "object repr"
msgstr "reprezentacj obiektu" msgstr "reprezentacj obiektu"
#: contrib/admin/models.py:22 #: contrib/admin/models.py:23
msgid "action flag" msgid "action flag"
msgstr "flaga akcji" msgstr "flaga akcji"
#: contrib/admin/models.py:23 #: contrib/admin/models.py:24
msgid "change message" msgid "change message"
msgstr "zmień wiadomość" msgstr "zmień wiadomość"
#: contrib/admin/models.py:26 #: contrib/admin/models.py:27
msgid "log entry" msgid "log entry"
msgstr "log" msgstr "log"
#: contrib/admin/models.py:27 #: contrib/admin/models.py:28
msgid "log entries" msgid "log entries"
msgstr "logi" msgstr "logi"
@ -472,7 +472,7 @@ msgid "Password:"
msgstr "Hasło:" msgstr "Hasło:"
#: contrib/admin/templates/admin/login.html:25 #: contrib/admin/templates/admin/login.html:25
#: contrib/admin/views/decorators.py:24 #: contrib/admin/views/decorators.py:25
msgid "Log in" msgid "Log in"
msgstr "Zaloguj się" msgstr "Zaloguj się"
@ -764,17 +764,17 @@ msgstr "Teraz:"
msgid "Change:" msgid "Change:"
msgstr "Zmień:" msgstr "Zmień:"
#: contrib/admin/templatetags/admin_list.py:254 #: contrib/admin/templatetags/admin_list.py:255
msgid "All dates" msgid "All dates"
msgstr "Wszystkie daty" msgstr "Wszystkie daty"
#: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:264 #: contrib/admin/views/auth.py:20 contrib/admin/views/main.py:267
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was added successfully." msgid "The %(name)s \"%(obj)s\" was added successfully."
msgstr "%(name)s \"%(obj)s\" dodany pomyślnie." msgstr "%(name)s \"%(obj)s\" dodany pomyślnie."
#: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:268 #: contrib/admin/views/auth.py:25 contrib/admin/views/main.py:271
#: contrib/admin/views/main.py:354 #: contrib/admin/views/main.py:357
msgid "You may edit it again below." msgid "You may edit it again below."
msgstr "Możesz ponownie edytować wpis poniżej." msgstr "Możesz ponownie edytować wpis poniżej."
@ -791,7 +791,7 @@ msgstr "Hasło zostało zmienione pomyślnie."
msgid "Change password: %s" msgid "Change password: %s"
msgstr "Zmień hasło: %s" msgstr "Zmień hasło: %s"
#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:60 #: contrib/admin/views/decorators.py:11 contrib/auth/forms.py:60
msgid "" msgid ""
"Please enter a correct username and password. Note that both fields are case-" "Please enter a correct username and password. Note that both fields are case-"
"sensitive." "sensitive."
@ -799,7 +799,7 @@ msgstr ""
"Proszę wpisać poprawną nazwę użytkownika i hasło. Uwaga: wielkość liter ma " "Proszę wpisać poprawną nazwę użytkownika i hasło. Uwaga: wielkość liter ma "
"znaczenie." "znaczenie."
#: contrib/admin/views/decorators.py:62 #: contrib/admin/views/decorators.py:63
msgid "" msgid ""
"Please log in again, because your session has expired. Don't worry: Your " "Please log in again, because your session has expired. Don't worry: Your "
"submission has been saved." "submission has been saved."
@ -807,7 +807,7 @@ msgstr ""
"Zaloguj się ponownie. Twoja sesja wygasła lecz twoje zgłoszenie zostało " "Zaloguj się ponownie. Twoja sesja wygasła lecz twoje zgłoszenie zostało "
"zapisane." "zapisane."
#: contrib/admin/views/decorators.py:69 #: contrib/admin/views/decorators.py:70
msgid "" msgid ""
"Looks like your browser isn't configured to accept cookies. Please enable " "Looks like your browser isn't configured to accept cookies. Please enable "
"cookies, reload this page, and try again." "cookies, reload this page, and try again."
@ -815,246 +815,246 @@ msgstr ""
"Twoja przeglądarka nie chce akceptować ciasteczek. Zmień jej ustawienia i " "Twoja przeglądarka nie chce akceptować ciasteczek. Zmień jej ustawienia i "
"spróbuj ponownie." "spróbuj ponownie."
#: contrib/admin/views/decorators.py:83 #: contrib/admin/views/decorators.py:84
msgid "Usernames cannot contain the '@' character." msgid "Usernames cannot contain the '@' character."
msgstr "Nazwy użytkowników nie mogą zawierać znaków '@'." msgstr "Nazwy użytkowników nie mogą zawierać znaków '@'."
#: contrib/admin/views/decorators.py:85 #: contrib/admin/views/decorators.py:86
#, python-format #, python-format
msgid "Your e-mail address is not your username. Try '%s' instead." msgid "Your e-mail address is not your username. Try '%s' instead."
msgstr "Twój adres e-mail to nie jest twój login. Spróbuj '%s'." msgstr "Twój adres e-mail to nie jest twój login. Spróbuj '%s'."
#: contrib/admin/views/doc.py:47 contrib/admin/views/doc.py:49 #: contrib/admin/views/doc.py:48 contrib/admin/views/doc.py:50
#: contrib/admin/views/doc.py:51 #: contrib/admin/views/doc.py:52
msgid "tag:" msgid "tag:"
msgstr "tag:" msgstr "tag:"
#: contrib/admin/views/doc.py:78 contrib/admin/views/doc.py:80 #: contrib/admin/views/doc.py:79 contrib/admin/views/doc.py:81
#: contrib/admin/views/doc.py:82 #: contrib/admin/views/doc.py:83
msgid "filter:" msgid "filter:"
msgstr "filtr:" msgstr "filtr:"
#: contrib/admin/views/doc.py:136 contrib/admin/views/doc.py:138 #: contrib/admin/views/doc.py:137 contrib/admin/views/doc.py:139
#: contrib/admin/views/doc.py:140 #: contrib/admin/views/doc.py:141
msgid "view:" msgid "view:"
msgstr "widok:" msgstr "widok:"
#: contrib/admin/views/doc.py:165 #: contrib/admin/views/doc.py:166
#, python-format #, python-format
msgid "App %r not found" msgid "App %r not found"
msgstr "Aplikacja %r nie została znaleziona" msgstr "Aplikacja %r nie została znaleziona"
#: contrib/admin/views/doc.py:172 #: contrib/admin/views/doc.py:173
#, python-format #, python-format
msgid "Model %(name)r not found in app %(label)r" msgid "Model %(name)r not found in app %(label)r"
msgstr "Model %(name)r nie został znaleziony w aplikacji %(label)r" msgstr "Model %(name)r nie został znaleziony w aplikacji %(label)r"
#: contrib/admin/views/doc.py:184 #: contrib/admin/views/doc.py:185
#, python-format #, python-format
msgid "the related `%(label)s.%(type)s` object" msgid "the related `%(label)s.%(type)s` object"
msgstr "powiązany obiekt `%(label)s.%(type)s`" msgstr "powiązany obiekt `%(label)s.%(type)s`"
#: contrib/admin/views/doc.py:184 contrib/admin/views/doc.py:206 #: contrib/admin/views/doc.py:185 contrib/admin/views/doc.py:207
#: contrib/admin/views/doc.py:220 contrib/admin/views/doc.py:225 #: contrib/admin/views/doc.py:221 contrib/admin/views/doc.py:226
msgid "model:" msgid "model:"
msgstr "model:" msgstr "model:"
#: contrib/admin/views/doc.py:215 #: contrib/admin/views/doc.py:216
#, python-format #, python-format
msgid "related `%(label)s.%(name)s` objects" msgid "related `%(label)s.%(name)s` objects"
msgstr "powiązane obiekty `%(label)s.%(name)s`" msgstr "powiązane obiekty `%(label)s.%(name)s`"
#: contrib/admin/views/doc.py:220 #: contrib/admin/views/doc.py:221
#, python-format #, python-format
msgid "all %s" msgid "all %s"
msgstr "wszystkie %s" msgstr "wszystkie %s"
#: contrib/admin/views/doc.py:225 #: contrib/admin/views/doc.py:226
#, python-format #, python-format
msgid "number of %s" msgid "number of %s"
msgstr "liczba %s" msgstr "liczba %s"
#: contrib/admin/views/doc.py:230 #: contrib/admin/views/doc.py:231
#, python-format #, python-format
msgid "Fields on %s objects" msgid "Fields on %s objects"
msgstr "Pola obiektów %s" msgstr "Pola obiektów %s"
#: contrib/admin/views/doc.py:292 contrib/admin/views/doc.py:303 #: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:304
#: contrib/admin/views/doc.py:305 contrib/admin/views/doc.py:311 #: contrib/admin/views/doc.py:306 contrib/admin/views/doc.py:312
#: contrib/admin/views/doc.py:312 contrib/admin/views/doc.py:314 #: contrib/admin/views/doc.py:313 contrib/admin/views/doc.py:315
msgid "Integer" msgid "Integer"
msgstr "Liczba całkowita" msgstr "Liczba całkowita"
#: contrib/admin/views/doc.py:293 #: contrib/admin/views/doc.py:294
msgid "Boolean (Either True or False)" msgid "Boolean (Either True or False)"
msgstr "Wartość logiczna (True, False - prawda lub fałsz)" msgstr "Wartość logiczna (True, False - prawda lub fałsz)"
#: contrib/admin/views/doc.py:294 contrib/admin/views/doc.py:313 #: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:314
#, python-format #, python-format
msgid "String (up to %(max_length)s)" msgid "String (up to %(max_length)s)"
msgstr "Łańcuch (do %(max_length)s znaków)" msgstr "Łańcuch (do %(max_length)s znaków)"
#: contrib/admin/views/doc.py:295 #: contrib/admin/views/doc.py:296
msgid "Comma-separated integers" msgid "Comma-separated integers"
msgstr "Liczby całkowite rozdzielone przecinkami" msgstr "Liczby całkowite rozdzielone przecinkami"
#: contrib/admin/views/doc.py:296 #: contrib/admin/views/doc.py:297
msgid "Date (without time)" msgid "Date (without time)"
msgstr "Data (bez godziny)" msgstr "Data (bez godziny)"
#: contrib/admin/views/doc.py:297 #: contrib/admin/views/doc.py:298
msgid "Date (with time)" msgid "Date (with time)"
msgstr "Data (z godziną)" msgstr "Data (z godziną)"
#: contrib/admin/views/doc.py:298 #: contrib/admin/views/doc.py:299
msgid "Decimal number" msgid "Decimal number"
msgstr "Numer dziesiętny" msgstr "Numer dziesiętny"
#: contrib/admin/views/doc.py:299 #: contrib/admin/views/doc.py:300
msgid "E-mail address" msgid "E-mail address"
msgstr "Adres e-mail" msgstr "Adres e-mail"
#: contrib/admin/views/doc.py:300 contrib/admin/views/doc.py:301 #: contrib/admin/views/doc.py:301 contrib/admin/views/doc.py:302
#: contrib/admin/views/doc.py:304 #: contrib/admin/views/doc.py:305
msgid "File path" msgid "File path"
msgstr "Ścieżka do pliku" msgstr "Ścieżka do pliku"
#: contrib/admin/views/doc.py:302 #: contrib/admin/views/doc.py:303
msgid "Floating point number" msgid "Floating point number"
msgstr "Liczba zmiennoprzecinkowa" msgstr "Liczba zmiennoprzecinkowa"
#: contrib/admin/views/doc.py:306 contrib/comments/models.py:85 #: contrib/admin/views/doc.py:307 contrib/comments/models.py:85
msgid "IP address" msgid "IP address"
msgstr "Adres IP" msgstr "Adres IP"
#: contrib/admin/views/doc.py:308 #: contrib/admin/views/doc.py:309
msgid "Boolean (Either True, False or None)" msgid "Boolean (Either True, False or None)"
msgstr "Wartość logiczna (True, False, None - prawda, fałsz lub nic)" msgstr "Wartość logiczna (True, False, None - prawda, fałsz lub nic)"
#: contrib/admin/views/doc.py:309 #: contrib/admin/views/doc.py:310
msgid "Relation to parent model" msgid "Relation to parent model"
msgstr "Relacja do modelu rodzica" msgstr "Relacja do modelu rodzica"
#: contrib/admin/views/doc.py:310 #: contrib/admin/views/doc.py:311
msgid "Phone number" msgid "Phone number"
msgstr "Numer telefonu" msgstr "Numer telefonu"
#: contrib/admin/views/doc.py:315 #: contrib/admin/views/doc.py:316
msgid "Text" msgid "Text"
msgstr "Tekst" msgstr "Tekst"
#: contrib/admin/views/doc.py:316 #: contrib/admin/views/doc.py:317
msgid "Time" msgid "Time"
msgstr "Czas" msgstr "Czas"
#: contrib/admin/views/doc.py:317 contrib/flatpages/models.py:7 #: contrib/admin/views/doc.py:318 contrib/flatpages/models.py:7
msgid "URL" msgid "URL"
msgstr "URL" msgstr "URL"
#: contrib/admin/views/doc.py:318 #: contrib/admin/views/doc.py:319
msgid "U.S. state (two uppercase letters)" msgid "U.S. state (two uppercase letters)"
msgstr "Stan USA (dwie duże litery)" msgstr "Stan USA (dwie duże litery)"
#: contrib/admin/views/doc.py:319 #: contrib/admin/views/doc.py:320
msgid "XML text" msgid "XML text"
msgstr "Tekst XML" msgstr "Tekst XML"
#: contrib/admin/views/doc.py:345 #: contrib/admin/views/doc.py:346
#, python-format #, python-format
msgid "%s does not appear to be a urlpattern object" msgid "%s does not appear to be a urlpattern object"
msgstr "%s nie jest obiektem urlpattern" msgstr "%s nie jest obiektem urlpattern"
#: contrib/admin/views/main.py:230 #: contrib/admin/views/main.py:233
msgid "Site administration" msgid "Site administration"
msgstr "Administracja stroną" msgstr "Administracja stroną"
#: contrib/admin/views/main.py:278 contrib/admin/views/main.py:363 #: contrib/admin/views/main.py:281 contrib/admin/views/main.py:366
#, python-format #, python-format
msgid "You may add another %s below." msgid "You may add another %s below."
msgstr "Możesz dodać nowy wpis %s poniżej." msgstr "Możesz dodać nowy wpis %s poniżej."
#: contrib/admin/views/main.py:296 #: contrib/admin/views/main.py:299
#, python-format #, python-format
msgid "Add %s" msgid "Add %s"
msgstr "Dodaj %s" msgstr "Dodaj %s"
#: contrib/admin/views/main.py:342 #: contrib/admin/views/main.py:345
#, python-format #, python-format
msgid "Added %s." msgid "Added %s."
msgstr "Dodano %s" msgstr "Dodano %s"
#: contrib/admin/views/main.py:342 contrib/admin/views/main.py:344 #: contrib/admin/views/main.py:345 contrib/admin/views/main.py:347
#: contrib/admin/views/main.py:346 core/validators.py:283 #: contrib/admin/views/main.py:349 core/validators.py:283
#: db/models/manipulators.py:309 #: db/models/manipulators.py:309
msgid "and" msgid "and"
msgstr "i" msgstr "i"
#: contrib/admin/views/main.py:344 #: contrib/admin/views/main.py:347
#, python-format #, python-format
msgid "Changed %s." msgid "Changed %s."
msgstr "Zmieniono %s" msgstr "Zmieniono %s"
#: contrib/admin/views/main.py:346 #: contrib/admin/views/main.py:349
#, python-format #, python-format
msgid "Deleted %s." msgid "Deleted %s."
msgstr "Skasowano %s" msgstr "Skasowano %s"
#: contrib/admin/views/main.py:349 #: contrib/admin/views/main.py:352
msgid "No fields changed." msgid "No fields changed."
msgstr "Żadne pole nie zmienione." msgstr "Żadne pole nie zmienione."
#: contrib/admin/views/main.py:352 #: contrib/admin/views/main.py:355
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was changed successfully." msgid "The %(name)s \"%(obj)s\" was changed successfully."
msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione." msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
#: contrib/admin/views/main.py:360 #: contrib/admin/views/main.py:363
#, python-format #, python-format
msgid "" msgid ""
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
msgstr "" msgstr ""
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej." "%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
#: contrib/admin/views/main.py:398 #: contrib/admin/views/main.py:401
#, python-format #, python-format
msgid "Change %s" msgid "Change %s"
msgstr "Zmień %s" msgstr "Zmień %s"
#: contrib/admin/views/main.py:483 #: contrib/admin/views/main.py:488
#, python-format #, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "Jedno lub więcej %(fieldname)s w %(name)s: %(obj)s" msgstr "Jedno lub więcej %(fieldname)s w %(name)s: %(obj)s"
#: contrib/admin/views/main.py:488 #: contrib/admin/views/main.py:493
#, python-format #, python-format
msgid "One or more %(fieldname)s in %(name)s:" msgid "One or more %(fieldname)s in %(name)s:"
msgstr "Jedno lub więcej %(fieldname)s w %(name)s:" msgstr "Jedno lub więcej %(fieldname)s w %(name)s:"
#: contrib/admin/views/main.py:520 #: contrib/admin/views/main.py:525
#, python-format #, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie." msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
#: contrib/admin/views/main.py:523 #: contrib/admin/views/main.py:528
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Jesteś pewien?" msgstr "Jesteś pewien?"
#: contrib/admin/views/main.py:545 #: contrib/admin/views/main.py:550
#, python-format #, python-format
msgid "Change history: %s" msgid "Change history: %s"
msgstr "Historia zmian: %s" msgstr "Historia zmian: %s"
#: contrib/admin/views/main.py:579 #: contrib/admin/views/main.py:584
#, python-format #, python-format
msgid "Select %s" msgid "Select %s"
msgstr "Zaznacz %s" msgstr "Zaznacz %s"
#: contrib/admin/views/main.py:579 #: contrib/admin/views/main.py:584
#, python-format #, python-format
msgid "Select %s to change" msgid "Select %s to change"
msgstr "Zaznacz %s aby zmienić" msgstr "Zaznacz %s aby zmienić"
#: contrib/admin/views/main.py:780 #: contrib/admin/views/main.py:785
msgid "Database error" msgid "Database error"
msgstr "Błąd bazy danych" msgstr "Błąd bazy danych"
@ -1618,7 +1618,7 @@ msgstr "-gi"
msgid "rd" msgid "rd"
msgstr "-ci" msgstr "-ci"
#: contrib/humanize/templatetags/humanize.py:50 #: contrib/humanize/templatetags/humanize.py:52
#, python-format #, python-format
msgid "%(value).1f million" msgid "%(value).1f million"
msgid_plural "%(value).1f million" msgid_plural "%(value).1f million"
@ -1626,7 +1626,7 @@ msgstr[0] "%(value).1f milion"
msgstr[1] "%(value).1f miliony" msgstr[1] "%(value).1f miliony"
msgstr[2] "%(value).1f milionów" msgstr[2] "%(value).1f milionów"
#: contrib/humanize/templatetags/humanize.py:53 #: contrib/humanize/templatetags/humanize.py:55
#, python-format #, python-format
msgid "%(value).1f billion" msgid "%(value).1f billion"
msgid_plural "%(value).1f billion" msgid_plural "%(value).1f billion"
@ -1634,7 +1634,7 @@ msgstr[0] "%(value).1f miliard"
msgstr[1] "%(value).1f miliardy" msgstr[1] "%(value).1f miliardy"
msgstr[2] "%(value).1f miliardów" msgstr[2] "%(value).1f miliardów"
#: contrib/humanize/templatetags/humanize.py:56 #: contrib/humanize/templatetags/humanize.py:58
#, python-format #, python-format
msgid "%(value).1f trillion" msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion" msgid_plural "%(value).1f trillion"
@ -1642,51 +1642,51 @@ msgstr[0] "%(value).1f bilion"
msgstr[1] "%(value).1f biliony" msgstr[1] "%(value).1f biliony"
msgstr[2] "%(value).1f bilionów" msgstr[2] "%(value).1f bilionów"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "one" msgid "one"
msgstr "jeden" msgstr "jeden"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "two" msgid "two"
msgstr "dwa" msgstr "dwa"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "three" msgid "three"
msgstr "trzy" msgstr "trzy"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "four" msgid "four"
msgstr "cztery" msgstr "cztery"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "five" msgid "five"
msgstr "pięć" msgstr "pięć"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "six" msgid "six"
msgstr "sześć" msgstr "sześć"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "seven" msgid "seven"
msgstr "siedem" msgstr "siedem"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "eight" msgid "eight"
msgstr "osiem" msgstr "osiem"
#: contrib/humanize/templatetags/humanize.py:71 #: contrib/humanize/templatetags/humanize.py:74
msgid "nine" msgid "nine"
msgstr "dziewięć" msgstr "dziewięć"
#: contrib/humanize/templatetags/humanize.py:90 #: contrib/humanize/templatetags/humanize.py:94
msgid "today" msgid "today"
msgstr "dzisiaj" msgstr "dzisiaj"
#: contrib/humanize/templatetags/humanize.py:92 #: contrib/humanize/templatetags/humanize.py:96
msgid "tomorrow" msgid "tomorrow"
msgstr "jutro" msgstr "jutro"
#: contrib/humanize/templatetags/humanize.py:94 #: contrib/humanize/templatetags/humanize.py:98
msgid "yesterday" msgid "yesterday"
msgstr "wczoraj" msgstr "wczoraj"
@ -1705,8 +1705,7 @@ msgstr "To pole musi zawierać 7 lub 8 cyfr."
#: contrib/localflavor/ar/forms.py:75 #: contrib/localflavor/ar/forms.py:75
msgid "Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format." msgid "Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format."
msgstr "" msgstr "Podaj poprawny numer CUIT w formacie XX-XXXXXXXX-X lub XXXXXXXXXXXX."
"Podaj poprawny numer CUIT w formacie XX-XXXXXXXX-X lub XXXXXXXXXXXX."
#: contrib/localflavor/ar/forms.py:88 #: contrib/localflavor/ar/forms.py:88
msgid "Invalid CUIT." msgid "Invalid CUIT."
@ -1725,11 +1724,12 @@ msgid "Phone numbers must be in XX-XXXX-XXXX format."
msgstr "Numery telefoniczne muszą być w formacie XX-XXXX-XXXX." msgstr "Numery telefoniczne muszą być w formacie XX-XXXX-XXXX."
#: contrib/localflavor/br/forms.py:68 #: contrib/localflavor/br/forms.py:68
#, fuzzy
msgid "" msgid ""
"Select a valid brazilian state. That state is not one of the available " "Select a valid brazilian state. That state is not one of the available "
"states." "states."
msgstr "Wybierz poprawną wartość. Podana nie jest jednym z dostępnych wyborów." msgstr ""
"Wybierz poprawny brazylijski stan. Ten stan nie jest jednym z dostępnych "
"stanów."
#: contrib/localflavor/br/forms.py:105 #: contrib/localflavor/br/forms.py:105
msgid "This field requires at most 11 digits or 14 characters." msgid "This field requires at most 11 digits or 14 characters."
@ -1748,14 +1748,13 @@ msgid "Invalid CNPJ number."
msgstr "Błędny numer CNPJ." msgstr "Błędny numer CNPJ."
#: contrib/localflavor/ca/forms.py:19 #: contrib/localflavor/ca/forms.py:19
#, fuzzy
msgid "Enter a postal code in the format XXX XXX." msgid "Enter a postal code in the format XXX XXX."
msgstr "Wpisz kod pocztowy w formacie XXXXX." msgstr "Wpisz kod pocztowy w formacie XXX XXX."
#: contrib/localflavor/ca/forms.py:81 #: contrib/localflavor/ca/forms.py:81
#, fuzzy
msgid "Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format." msgid "Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format."
msgstr "Wpisz poprawny numer U.S. Social Security w formacie XXX-XX-XXXX." msgstr ""
"Wpisz poprawny numer kanadyjskiego ubezpieczenia w formacie XXX-XXX-XXXX."
#: contrib/localflavor/ch/ch_states.py:5 #: contrib/localflavor/ch/ch_states.py:5
msgid "Aargau" msgid "Aargau"
@ -1870,7 +1869,7 @@ msgid ""
"Enter a valid Swiss identity or passport card number in X1234567<0 or " "Enter a valid Swiss identity or passport card number in X1234567<0 or "
"1234567890 format." "1234567890 format."
msgstr "" msgstr ""
"Podaj poprawny numer szwajarskiego dowodu osobistego lub paszportu w " "Podaj poprawny numer szwajcarskiego dowodu osobistego lub paszportu w "
"formacie X1234567<0 lub 1234567890." "formacie X1234567<0 lub 1234567890."
#: contrib/localflavor/cl/forms.py:32 #: contrib/localflavor/cl/forms.py:32
@ -2237,16 +2236,15 @@ msgid "Valencian Community"
msgstr "" msgstr ""
#: contrib/localflavor/es/forms.py:22 #: contrib/localflavor/es/forms.py:22
#, fuzzy
msgid "Enter a valid postal code in the range and format 01XXX - 52XXX." msgid "Enter a valid postal code in the range and format 01XXX - 52XXX."
msgstr "Wpisz kod pocztowy w formacie XXXXXXX lub XXX-XXXX." msgstr "Wpisz kod pocztowy w zakresie i formacie 01XXX - 52XX."
#: contrib/localflavor/es/forms.py:39 #: contrib/localflavor/es/forms.py:39
#, fuzzy
msgid "" msgid ""
"Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or " "Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or "
"9XXXXXXXX." "9XXXXXXXX."
msgstr "Wpisz kod pocztowy w formacie XXXXXXX lub XXX-XXXX." msgstr ""
"Wpisz numer telefoniczny w formacie 6XXXXXXXX, 8XXXXXXXX lub 9XXXXXXXX."
#: contrib/localflavor/es/forms.py:73 contrib/localflavor/es/forms.py:108 #: contrib/localflavor/es/forms.py:73 contrib/localflavor/es/forms.py:108
#: db/models/fields/related.py:55 #: db/models/fields/related.py:55
@ -2256,36 +2254,33 @@ msgstr "Proszę wpisać poprawne %s."
#: contrib/localflavor/es/forms.py:91 #: contrib/localflavor/es/forms.py:91
msgid "Invalid checksum for NIF." msgid "Invalid checksum for NIF."
msgstr "" msgstr "Niepoprawna suma kontrolna NIF."
#: contrib/localflavor/es/forms.py:97 #: contrib/localflavor/es/forms.py:97
msgid "Invalid checksum for NIE." msgid "Invalid checksum for NIE."
msgstr "" msgstr "Niepoprawna suma kontrolna NIE."
#: contrib/localflavor/es/forms.py:106 #: contrib/localflavor/es/forms.py:106
msgid "Invalid checksum for CIF." msgid "Invalid checksum for CIF."
msgstr "" msgstr "Niepoprawna suma kontrolna CIF."
#: contrib/localflavor/es/forms.py:136 #: contrib/localflavor/es/forms.py:136
#, fuzzy
msgid "" msgid ""
"Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX." "Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX."
msgstr "" msgstr ""
"Podaj poprawny niemiecki numer dowodu osobistego w formacie XXXXXXXXXXX-" "Podaj poprawny numer konta bankowego w formacie XXXX-XXXX-XX-XXXXXXXXXX."
"XXXXXXX-XXXXXXX-X."
#: contrib/localflavor/es/forms.py:150 #: contrib/localflavor/es/forms.py:150
msgid "Invalid checksum for bank account number." msgid "Invalid checksum for bank account number."
msgstr "" msgstr "Niepoprawna suma kontrolna numeru konta bankowego."
#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45 #: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
msgid "Enter a valid Finnish social security number." msgid "Enter a valid Finnish social security number."
msgstr "Wpis poprawny numer fińskiego ubezpieczenia socjalnego." msgstr "Wpis poprawny numer fińskiego ubezpieczenia socjalnego."
#: contrib/localflavor/in_/forms.py:16 #: contrib/localflavor/in_/forms.py:16
#, fuzzy
msgid "Enter a zip code in the format XXXXXXX." msgid "Enter a zip code in the format XXXXXXX."
msgstr "Wpisz kod pocztowy w formacie XXXXX-XXX." msgstr "Wpisz kod pocztowy w formacie XXXXXXX."
#: contrib/localflavor/is_/forms.py:17 #: contrib/localflavor/is_/forms.py:17
msgid "" msgid ""
@ -2502,19 +2497,16 @@ msgid "Okinawa"
msgstr "" msgstr ""
#: contrib/localflavor/nl/forms.py:25 #: contrib/localflavor/nl/forms.py:25
#, fuzzy
msgid "Enter a valid postal code" msgid "Enter a valid postal code"
msgstr "Wpisz poprawny kod pocztowy." msgstr "Wpisz poprawny kod pocztowy."
#: contrib/localflavor/nl/forms.py:53 #: contrib/localflavor/nl/forms.py:53
#, fuzzy
msgid "Enter a valid phone number" msgid "Enter a valid phone number"
msgstr "Wpisz poprawny numer VAT." msgstr "Wpisz poprawny numer telefonu."
#: contrib/localflavor/nl/forms.py:76 #: contrib/localflavor/nl/forms.py:76
#, fuzzy
msgid "Enter a valid SoFi number" msgid "Enter a valid SoFi number"
msgstr "Wpisz poprawny numer VAT." msgstr "Wpisz poprawny numer SoFi."
#: contrib/localflavor/nl/nl_provinces.py:4 #: contrib/localflavor/nl/nl_provinces.py:4
#, fuzzy #, fuzzy
@ -2574,13 +2566,12 @@ msgid "Enter a valid Norwegian social security number."
msgstr "Wpis poprawny numer norweskiego ubezpieczenia socjalnego." msgstr "Wpis poprawny numer norweskiego ubezpieczenia socjalnego."
#: contrib/localflavor/pe/forms.py:36 #: contrib/localflavor/pe/forms.py:36
#, fuzzy
msgid "This field requires 8 digits." msgid "This field requires 8 digits."
msgstr "To pole musi zawierać co najmniej 14 cyfr." msgstr "To pole musi zawierać 8 cyfr."
#: contrib/localflavor/pe/forms.py:59 #: contrib/localflavor/pe/forms.py:59
msgid "This field requires 11 digits." msgid "This field requires 11 digits."
msgstr "To pole musi zawierać co najmniej 11 cyfr." msgstr "To pole musi zawierać 11 cyfr."
#: contrib/localflavor/pl/forms.py:41 #: contrib/localflavor/pl/forms.py:41
msgid "National Identification Number consists of 11 digits." msgid "National Identification Number consists of 11 digits."
@ -2676,9 +2667,8 @@ msgid "West Pomerania"
msgstr "Zachodniopomorskie" msgstr "Zachodniopomorskie"
#: contrib/localflavor/sk/forms.py:32 #: contrib/localflavor/sk/forms.py:32
#, fuzzy
msgid "Enter a postal code in the format XXXXX or XXX XX." msgid "Enter a postal code in the format XXXXX or XXX XX."
msgstr "Wpisz kod pocztowy w formacie XXXXXXX lub XXX-XXXX." msgstr "Wpisz kod pocztowy w formacie XXXXX or XXX XX."
#: contrib/localflavor/sk/sk_districts.py:8 #: contrib/localflavor/sk/sk_districts.py:8
msgid "Banska Bystrica" msgid "Banska Bystrica"
@ -3198,7 +3188,7 @@ msgid "Enter a valid e-mail address."
msgstr "Wprowadź poprawny adres e-mail." msgstr "Wprowadź poprawny adres e-mail."
#: core/validators.py:182 core/validators.py:474 newforms/fields.py:438 #: core/validators.py:182 core/validators.py:474 newforms/fields.py:438
#: oldforms/__init__.py:686 #: oldforms/__init__.py:687
msgid "No file was submitted. Check the encoding type on the form." msgid "No file was submitted. Check the encoding type on the form."
msgstr "Nie wysłano żadnego pliku. Sprawdź typ kodowania formularza." msgstr "Nie wysłano żadnego pliku. Sprawdź typ kodowania formularza."
@ -3460,7 +3450,7 @@ msgstr "Już istnieje %(optname)s z %(fieldname)s."
#: db/models/fields/__init__.py:161 db/models/fields/__init__.py:318 #: db/models/fields/__init__.py:161 db/models/fields/__init__.py:318
#: db/models/fields/__init__.py:735 db/models/fields/__init__.py:746 #: db/models/fields/__init__.py:735 db/models/fields/__init__.py:746
#: newforms/fields.py:45 newforms/models.py:220 oldforms/__init__.py:373 #: newforms/fields.py:45 newforms/models.py:220 oldforms/__init__.py:374
msgid "This field is required." msgid "This field is required."
msgstr "To pole jest wymagane." msgstr "To pole jest wymagane."
@ -3523,15 +3513,15 @@ msgstr "Wpisz poprawną wartość."
#, python-format #, python-format
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)." msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
msgstr "" msgstr ""
"Upewnij się, że ta wartość ma co najwyżej %(max)d znaków " "Upewnij się, że ta wartość ma co najwyżej %(max)d znaków (ma długość %"
"(ma długość %(length)d)." "(length)d)."
#: newforms/fields.py:130 #: newforms/fields.py:130
#, python-format #, python-format
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)." msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
msgstr "" msgstr ""
"Upewnij się, że ta wartość ma co najmniej %(min)d znaków " "Upewnij się, że ta wartość ma co najmniej %(min)d znaków (ma długość %"
"(ma długość %(length)d)." "(length)d)."
#: newforms/fields.py:158 newforms/fields.py:187 newforms/fields.py:216 #: newforms/fields.py:158 newforms/fields.py:187 newforms/fields.py:216
#, python-format #, python-format
@ -3578,7 +3568,7 @@ msgstr "Wpisz poprawną datę/godzinę."
msgid "No file was submitted." msgid "No file was submitted."
msgstr "Żaden plik nie został przesłany." msgstr "Żaden plik nie został przesłany."
#: newforms/fields.py:440 oldforms/__init__.py:688 #: newforms/fields.py:440 oldforms/__init__.py:689
msgid "The submitted file is empty." msgid "The submitted file is empty."
msgstr "Wysłany plik jest pusty." msgstr "Wysłany plik jest pusty."
@ -3613,7 +3603,7 @@ msgstr "Wprowadź poprawny adres IPv4."
msgid "Select a valid choice. %s is not one of the available choices." msgid "Select a valid choice. %s is not one of the available choices."
msgstr "Wybierz poprawną wartość. %s nie jest jednym z dostępnych wyborów." msgstr "Wybierz poprawną wartość. %s nie jest jednym z dostępnych wyborów."
#: oldforms/__init__.py:408 #: oldforms/__init__.py:409
#, python-format #, python-format
msgid "Ensure your text is less than %s character." msgid "Ensure your text is less than %s character."
msgid_plural "Ensure your text is less than %s characters." msgid_plural "Ensure your text is less than %s characters."
@ -3621,32 +3611,32 @@ msgstr[0] "Upewnij się, że tekst ma mniej niż %s znak."
msgstr[1] "Upewnij się, że tekst ma mniej niż %s znaki." msgstr[1] "Upewnij się, że tekst ma mniej niż %s znaki."
msgstr[2] "Upewnij się, że tekst ma mniej niż %s znaków." msgstr[2] "Upewnij się, że tekst ma mniej niż %s znaków."
#: oldforms/__init__.py:413 #: oldforms/__init__.py:414
msgid "Line breaks are not allowed here." msgid "Line breaks are not allowed here."
msgstr "Znaki nowej linii są tutaj niedopuszczalne." msgstr "Znaki nowej linii są tutaj niedopuszczalne."
#: oldforms/__init__.py:511 oldforms/__init__.py:585 oldforms/__init__.py:624 #: oldforms/__init__.py:512 oldforms/__init__.py:586 oldforms/__init__.py:625
#, python-format #, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Wybierz poprawną opcję; '%(data)s' nie jest wśród %(choices)s." msgstr "Wybierz poprawną opcję; '%(data)s' nie jest wśród %(choices)s."
#: oldforms/__init__.py:744 #: oldforms/__init__.py:745
msgid "Enter a whole number between -32,768 and 32,767." msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Proszę wpisać liczbę całkowitą z zakresu od -32 768 do 32 767" msgstr "Proszę wpisać liczbę całkowitą z zakresu od -32 768 do 32 767"
#: oldforms/__init__.py:754 #: oldforms/__init__.py:755
msgid "Enter a positive number." msgid "Enter a positive number."
msgstr "Proszę wpisać liczbę dodatnią." msgstr "Proszę wpisać liczbę dodatnią."
#: oldforms/__init__.py:764 #: oldforms/__init__.py:765
msgid "Enter a whole number between 0 and 32,767." msgid "Enter a whole number between 0 and 32,767."
msgstr "Proszę wpisać liczbę całkowitą z zakresu od 0 do 32 767" msgstr "Proszę wpisać liczbę całkowitą z zakresu od 0 do 32 767"
#: template/defaultfilters.py:555 #: template/defaultfilters.py:655
msgid "yes,no,maybe" msgid "yes,no,maybe"
msgstr "tak,nie,może" msgstr "tak,nie,może"
#: template/defaultfilters.py:585 #: template/defaultfilters.py:686
#, python-format #, python-format
msgid "%(size)d byte" msgid "%(size)d byte"
msgid_plural "%(size)d bytes" msgid_plural "%(size)d bytes"
@ -3654,17 +3644,17 @@ msgstr[0] "%(size)d bajt"
msgstr[1] "%(size)d bajty" msgstr[1] "%(size)d bajty"
msgstr[2] "%(size)d bajtów" msgstr[2] "%(size)d bajtów"
#: template/defaultfilters.py:587 #: template/defaultfilters.py:688
#, python-format #, python-format
msgid "%.1f KB" msgid "%.1f KB"
msgstr "%.1f KB" msgstr "%.1f KB"
#: template/defaultfilters.py:589 #: template/defaultfilters.py:690
#, python-format #, python-format
msgid "%.1f MB" msgid "%.1f MB"
msgstr "%.1f MB" msgstr "%.1f MB"
#: template/defaultfilters.py:590 #: template/defaultfilters.py:691
#, python-format #, python-format
msgid "%.1f GB" msgid "%.1f GB"
msgstr "%.1f GB" msgstr "%.1f GB"

View File

@ -4,7 +4,7 @@
*/ */
/* Block IE 5 */ /* Block IE 5 */
@import "null?\"\{"; @import "null.css?\"\{";
/* Import other styles */ /* Import other styles */
@import url('global.css'); @import url('global.css');

View File

@ -1,6 +1,16 @@
// Handles related-objects functionality: lookup link for raw_id_admin=True // Handles related-objects functionality: lookup link for raw_id_admin=True
// and Add Another links. // and Add Another links.
function html_unescape(text) {
// Unescape a string that was escaped using django.utils.html.escape.
text = text.replace(/&lt;/g, '<');
text = text.replace(/&gt;/g, '>');
text = text.replace(/&quot;/g, '"');
text = text.replace(/&#39;/g, "'");
text = text.replace(/&amp;/g, '&');
return text;
}
function showRelatedObjectLookupPopup(triggeringLink) { function showRelatedObjectLookupPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^lookup_/, ''); var name = triggeringLink.id.replace(/^lookup_/, '');
// IE doesn't like periods in the window name, so convert temporarily. // IE doesn't like periods in the window name, so convert temporarily.
@ -42,6 +52,10 @@ function showAddAnotherPopup(triggeringLink) {
} }
function dismissAddAnotherPopup(win, newId, newRepr) { function dismissAddAnotherPopup(win, newId, newRepr) {
// newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = win.name.replace(/___/g, '.'); var name = win.name.replace(/___/g, '.');
var elem = document.getElementById(name); var elem = document.getElementById(name);
if (elem) { if (elem) {

View File

@ -148,6 +148,8 @@ def items_for_result(cl, result):
# function has an "allow_tags" attribute set to True. # function has an "allow_tags" attribute set to True.
if not allow_tags: if not allow_tags:
result_repr = escape(result_repr) result_repr = escape(result_repr)
else:
result_repr = mark_safe(result_repr)
else: else:
field_val = getattr(result, f.attname) field_val = getattr(result, f.attname)
@ -185,7 +187,7 @@ def items_for_result(cl, result):
else: else:
result_repr = escape(field_val) result_repr = escape(field_val)
if force_unicode(result_repr) == '': if force_unicode(result_repr) == '':
result_repr = '&nbsp;' result_repr = mark_safe('&nbsp;')
# If list_display_links not defined, add the link tag to the first field # If list_display_links not defined, add the link tag to the first field
if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links: if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
table_tag = {True:'th', False:'td'}[first] table_tag = {True:'th', False:'td'}[first]

View File

@ -118,7 +118,7 @@ class FieldWrapper(object):
return not isinstance(self.field, models.AutoField) return not isinstance(self.field, models.AutoField)
def header_class_attribute(self): def header_class_attribute(self):
return self.field.blank and ' class="optional"' or '' return self.field.blank and mark_safe(' class="optional"') or ''
def use_raw_id_admin(self): def use_raw_id_admin(self):
return isinstance(self.field.rel, (models.ManyToOneRel, models.ManyToManyRel)) \ return isinstance(self.field.rel, (models.ManyToOneRel, models.ManyToManyRel)) \

View File

@ -273,10 +273,9 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
post_url_continue += "?_popup=1" post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value) return HttpResponseRedirect(post_url_continue % pk_value)
if "_popup" in request.POST: if "_popup" in request.POST:
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable. return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
pk_value = '"%s"' % pk_value.replace('"', '\\"') # escape() calls force_unicode.
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \ (escape(pk_value), escape(new_object)))
(pk_value, force_unicode(new_object).replace('"', '\\"')))
elif "_addanother" in request.POST: elif "_addanother" in request.POST:
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect(request.path) return HttpResponseRedirect(request.path)

View File

@ -16,8 +16,12 @@ class CacheClass(SimpleCacheClass):
def add(self, key, value, timeout=None): def add(self, key, value, timeout=None):
self._lock.writer_enters() self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try: try:
SimpleCacheClass.add(self, key, value, timeout) try:
super(CacheClass, self).add(key, pickle.dumps(value), timeout)
except pickle.PickleError:
pass
finally: finally:
self._lock.writer_leaves() self._lock.writer_leaves()
@ -49,6 +53,7 @@ class CacheClass(SimpleCacheClass):
def set(self, key, value, timeout=None): def set(self, key, value, timeout=None):
self._lock.writer_enters() self._lock.writer_enters()
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
try: try:
try: try:
super(CacheClass, self).set(key, pickle.dumps(value), timeout) super(CacheClass, self).set(key, pickle.dumps(value), timeout)

View File

@ -52,7 +52,7 @@ def load_command_class(app_name, name):
return getattr(__import__('%s.management.commands.%s' % (app_name, name), return getattr(__import__('%s.management.commands.%s' % (app_name, name),
{}, {}, ['Command']), 'Command')() {}, {}, ['Command']), 'Command')()
def get_commands(load_user_commands=True, project_directory=None): def get_commands():
""" """
Returns a dictionary of commands against the application in which Returns a dictionary of commands against the application in which
those commands can be found. This works by looking for a those commands can be found. This works by looking for a
@ -60,10 +60,10 @@ def get_commands(load_user_commands=True, project_directory=None):
application -- if a commands package exists, all commands in that application -- if a commands package exists, all commands in that
package are registered. package are registered.
Core commands are always included; user-defined commands will also Core commands are always included. If a settings module has been
be included if ``load_user_commands`` is True. If a project directory specified, user-defined commands will also be included, the
is provided, the startproject command will be disabled, and the startproject command will be disabled, and the startapp command
startapp command will be modified to use that directory. will be modified to use the directory in which that module appears.
The dictionary is in the format {command_name: app_name}. Key-value The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to pairs from this dictionary can then be used in calls to
@ -80,16 +80,27 @@ def get_commands(load_user_commands=True, project_directory=None):
if _commands is None: if _commands is None:
_commands = dict([(name, 'django.core') _commands = dict([(name, 'django.core')
for name in find_commands(__path__[0])]) for name in find_commands(__path__[0])])
if load_user_commands: # Get commands from all installed apps.
# Get commands from all installed apps. try:
from django.conf import settings from django.conf import settings
for app_name in settings.INSTALLED_APPS: apps = settings.INSTALLED_APPS
try: except (AttributeError, EnvironmentError):
path = find_management_module(app_name) apps = []
_commands.update(dict([(name, app_name)
for name in find_commands(path)])) for app_name in apps:
except ImportError: try:
pass # No management module - ignore this app path = find_management_module(app_name)
_commands.update(dict([(name, app_name)
for name in find_commands(path)]))
except ImportError:
pass # No management module - ignore this app
# Try to determine the project directory
try:
from django.conf import settings
project_directory = setup_environ(__import__(settings.SETTINGS_MODULE))
except (AttributeError, EnvironmentError, ImportError):
project_directory = None
if project_directory: if project_directory:
# Remove the "startproject" command from self.commands, because # Remove the "startproject" command from self.commands, because
@ -146,8 +157,6 @@ class ManagementUtility(object):
def __init__(self, argv=None): def __init__(self, argv=None):
self.argv = argv or sys.argv[:] self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0]) self.prog_name = os.path.basename(self.argv[0])
self.project_directory = None
self.user_commands = False
def main_help_text(self): def main_help_text(self):
""" """
@ -159,8 +168,7 @@ class ManagementUtility(object):
usage.append("Type '%s help <subcommand>' for help on a specific" usage.append("Type '%s help <subcommand>' for help on a specific"
" subcommand." % self.prog_name) " subcommand." % self.prog_name)
usage.append('Available subcommands:') usage.append('Available subcommands:')
commands = get_commands(self.user_commands, commands = get_commands().keys()
self.project_directory).keys()
commands.sort() commands.sort()
for cmd in commands: for cmd in commands:
usage.append(' %s' % cmd) usage.append(' %s' % cmd)
@ -173,8 +181,7 @@ class ManagementUtility(object):
django-admin.py or manage.py) if it can't be found. django-admin.py or manage.py) if it can't be found.
""" """
try: try:
app_name = get_commands(self.user_commands, app_name = get_commands()[subcommand]
self.project_directory)[subcommand]
if isinstance(app_name, BaseCommand): if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly. # If the command is already loaded, use it directly.
klass = app_name klass = app_name
@ -235,8 +242,6 @@ class ProjectManagementUtility(ManagementUtility):
""" """
def __init__(self, argv, project_directory): def __init__(self, argv, project_directory):
super(ProjectManagementUtility, self).__init__(argv) super(ProjectManagementUtility, self).__init__(argv)
self.project_directory = project_directory
self.user_commands = True
def setup_environ(settings_mod): def setup_environ(settings_mod):
""" """

View File

@ -91,7 +91,7 @@ class ObjectPaginator(object):
a template for loop. a template for loop.
""" """
if self._page_range is None: if self._page_range is None:
self._page_range = range(1, self._pages + 1) self._page_range = range(1, self.pages + 1)
return self._page_range return self._page_range
hits = property(_get_hits) hits = property(_get_hits)

View File

@ -1,4 +1,5 @@
import re import re
from django.utils.text import compress_string from django.utils.text import compress_string
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
@ -11,18 +12,21 @@ class GZipMiddleware(object):
on the Accept-Encoding header. on the Accept-Encoding header.
""" """
def process_response(self, request, response): def process_response(self, request, response):
# It's not worth compressing non-OK or really short responses.
if response.status_code != 200 or len(response.content) < 200: if response.status_code != 200 or len(response.content) < 200:
# Not worth compressing really short responses or 304 status
# responses, etc.
return response return response
patch_vary_headers(response, ('Accept-Encoding',)) patch_vary_headers(response, ('Accept-Encoding',))
# Avoid gzipping if we've already got a content-encoding or if the # Avoid gzipping if we've already got a content-encoding.
# content-type is Javascript and the user's browser is IE. if response.has_header('Content-Encoding'):
is_js = ("msie" in request.META.get('HTTP_USER_AGENT', '').lower() and return response
"javascript" in response.get('Content-Type', '').lower())
if response.has_header('Content-Encoding') or is_js: # Older versions of IE have issues with gzipped javascript.
# See http://code.djangoproject.com/ticket/2449
is_ie = "msie" in request.META.get('HTTP_USER_AGENT', '').lower()
is_js = "javascript" in response.get('Content-Type', '').lower()
if is_ie and is_js:
return response return response
ae = request.META.get('HTTP_ACCEPT_ENCODING', '') ae = request.META.get('HTTP_ACCEPT_ENCODING', '')

View File

@ -6,6 +6,7 @@ import datetime
from django.newforms.widgets import Widget, Select from django.newforms.widgets import Widget, Select
from django.utils.dates import MONTHS from django.utils.dates import MONTHS
from django.utils.safestring import mark_safe
__all__ = ('SelectDateWidget',) __all__ = ('SelectDateWidget',)
@ -51,7 +52,7 @@ class SelectDateWidget(Widget):
select_html = Select(choices=year_choices).render(self.year_field % name, year_val) select_html = Select(choices=year_choices).render(self.year_field % name, year_val)
output.append(select_html) output.append(select_html)
return u'\n'.join(output) return mark_safe(u'\n'.join(output))
def value_from_datadict(self, data, files, name): def value_from_datadict(self, data, files, name):
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name) y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)

View File

@ -3,13 +3,13 @@ Helper functions for creating Form classes from Django models
and database field objects. and database field objects.
""" """
from django.utils.translation import ugettext from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from util import ValidationError from util import ValidationError
from forms import BaseForm from forms import BaseForm
from fields import Field, ChoiceField from fields import Field, ChoiceField, EMPTY_VALUES
from widgets import Select, SelectMultiple, MultipleHiddenInput from widgets import Select, SelectMultiple, MultipleHiddenInput
__all__ = ( __all__ = (
@ -151,15 +151,20 @@ class ModelChoiceField(ChoiceField):
"""A ChoiceField whose choices are a model QuerySet.""" """A ChoiceField whose choices are a model QuerySet."""
# This class is a subclass of ChoiceField for purity, but it doesn't # This class is a subclass of ChoiceField for purity, but it doesn't
# actually use any of ChoiceField's implementation. # actually use any of ChoiceField's implementation.
default_error_messages = {
'invalid_choice': _(u'Select a valid choice. That choice is not one of'
u' the available choices.'),
}
def __init__(self, queryset, empty_label=u"---------", cache_choices=False, def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
required=True, widget=Select, label=None, initial=None, required=True, widget=Select, label=None, initial=None,
help_text=None): help_text=None, *args, **kwargs):
self.empty_label = empty_label self.empty_label = empty_label
self.cache_choices = cache_choices self.cache_choices = cache_choices
# Call Field instead of ChoiceField __init__() because we don't need # Call Field instead of ChoiceField __init__() because we don't need
# ChoiceField.__init__(). # ChoiceField.__init__().
Field.__init__(self, required, widget, label, initial, help_text) Field.__init__(self, required, widget, label, initial, help_text,
*args, **kwargs)
self.queryset = queryset self.queryset = queryset
def _get_queryset(self): def _get_queryset(self):
@ -195,41 +200,43 @@ class ModelChoiceField(ChoiceField):
def clean(self, value): def clean(self, value):
Field.clean(self, value) Field.clean(self, value)
if value in ('', None): if value in EMPTY_VALUES:
return None return None
try: try:
value = self.queryset.get(pk=value) value = self.queryset.get(pk=value)
except self.queryset.model.DoesNotExist: except self.queryset.model.DoesNotExist:
raise ValidationError(ugettext(u'Select a valid choice. That' raise ValidationError(self.error_messages['invalid_choice'])
u' choice is not one of the'
u' available choices.'))
return value return value
class ModelMultipleChoiceField(ModelChoiceField): class ModelMultipleChoiceField(ModelChoiceField):
"""A MultipleChoiceField whose choices are a model QuerySet.""" """A MultipleChoiceField whose choices are a model QuerySet."""
hidden_widget = MultipleHiddenInput hidden_widget = MultipleHiddenInput
default_error_messages = {
'list': _(u'Enter a list of values.'),
'invalid_choice': _(u'Select a valid choice. %s is not one of the'
u' available choices.'),
}
def __init__(self, queryset, cache_choices=False, required=True, def __init__(self, queryset, cache_choices=False, required=True,
widget=SelectMultiple, label=None, initial=None, widget=SelectMultiple, label=None, initial=None,
help_text=None): help_text=None, *args, **kwargs):
super(ModelMultipleChoiceField, self).__init__(queryset, None, super(ModelMultipleChoiceField, self).__init__(queryset, None,
cache_choices, required, widget, label, initial, help_text) cache_choices, required, widget, label, initial, help_text,
*args, **kwargs)
def clean(self, value): def clean(self, value):
if self.required and not value: if self.required and not value:
raise ValidationError(ugettext(u'This field is required.')) raise ValidationError(self.error_messages['required'])
elif not self.required and not value: elif not self.required and not value:
return [] return []
if not isinstance(value, (list, tuple)): if not isinstance(value, (list, tuple)):
raise ValidationError(ugettext(u'Enter a list of values.')) raise ValidationError(self.error_messages['list'])
final_values = [] final_values = []
for val in value: for val in value:
try: try:
obj = self.queryset.get(pk=val) obj = self.queryset.get(pk=val)
except self.queryset.model.DoesNotExist: except self.queryset.model.DoesNotExist:
raise ValidationError(ugettext(u'Select a valid choice. %s is' raise ValidationError(self.error_messages['invalid_choice'] % val)
u' not one of the available'
u' choices.') % val)
else: else:
final_values.append(obj) final_values.append(obj)
return final_values return final_values

View File

@ -11,7 +11,7 @@ import copy
from itertools import chain from itertools import chain
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.html import escape from django.utils.html import escape, conditional_escape
from django.utils.translation import ugettext from django.utils.translation import ugettext
from django.utils.encoding import StrAndUnicode, force_unicode from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -155,7 +155,7 @@ class Textarea(Widget):
value = force_unicode(value) value = force_unicode(value)
final_attrs = self.build_attrs(attrs, name=name) final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
escape(value))) conditional_escape(force_unicode(value))))
class DateTimeInput(Input): class DateTimeInput(Input):
input_type = 'text' input_type = 'text'
@ -217,7 +217,9 @@ class Select(Widget):
for option_value, option_label in chain(self.choices, choices): for option_value, option_label in chain(self.choices, choices):
option_value = force_unicode(option_value) option_value = force_unicode(option_value)
selected_html = (option_value == str_value) and u' selected="selected"' or '' selected_html = (option_value == str_value) and u' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label)))) output.append(u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label))))
output.append(u'</select>') output.append(u'</select>')
return mark_safe(u'\n'.join(output)) return mark_safe(u'\n'.join(output))
@ -254,7 +256,9 @@ class SelectMultiple(Widget):
for option_value, option_label in chain(self.choices, choices): for option_value, option_label in chain(self.choices, choices):
option_value = force_unicode(option_value) option_value = force_unicode(option_value)
selected_html = (option_value in str_values) and ' selected="selected"' or '' selected_html = (option_value in str_values) and ' selected="selected"' or ''
output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label)))) output.append(u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label))))
output.append(u'</select>') output.append(u'</select>')
return mark_safe(u'\n'.join(output)) return mark_safe(u'\n'.join(output))
@ -278,7 +282,7 @@ class RadioInput(StrAndUnicode):
def __unicode__(self): def __unicode__(self):
return mark_safe(u'<label>%s %s</label>' % (self.tag(), return mark_safe(u'<label>%s %s</label>' % (self.tag(),
self.choice_label)) conditional_escape(force_unicode(self.choice_label))))
def is_checked(self): def is_checked(self):
return self.value == self.choice_value return self.value == self.choice_value
@ -317,11 +321,13 @@ class RadioFieldRenderer(StrAndUnicode):
% force_unicode(w) for w in self])) % force_unicode(w) for w in self]))
class RadioSelect(Select): class RadioSelect(Select):
renderer = RadioFieldRenderer
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.renderer = kwargs.pop('renderer', None) # Override the default renderer if we were passed one.
if not self.renderer: renderer = kwargs.pop('renderer', None)
self.renderer = RadioFieldRenderer if renderer:
self.renderer = renderer
super(RadioSelect, self).__init__(*args, **kwargs) super(RadioSelect, self).__init__(*args, **kwargs)
def get_renderer(self, name, value, attrs=None, choices=()): def get_renderer(self, name, value, attrs=None, choices=()):
@ -361,7 +367,8 @@ class CheckboxSelectMultiple(SelectMultiple):
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value) option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value) rendered_cb = cb.render(name, option_value)
output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(force_unicode(option_label)))) output.append(u'<li><label>%s %s</label></li>' % (rendered_cb,
conditional_escape(force_unicode(option_label))))
output.append(u'</ul>') output.append(u'</ul>')
return mark_safe(u'\n'.join(output)) return mark_safe(u'\n'.join(output))

View File

@ -547,9 +547,9 @@ class FilterExpression(object):
if var == None: if var == None:
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant") var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
if i18n_constant: if i18n_constant:
var = '"%s"' % _(i18n_constant) var = '"%s"' % _(i18n_constant.replace(r'\"', '"'))
elif constant: elif constant:
var = '"%s"' % constant var = '"%s"' % constant.replace(r'\"', '"')
upto = match.end() upto = match.end()
if var == None: if var == None:
raise TemplateSyntaxError, "Could not find variable at start of %s" % token raise TemplateSyntaxError, "Could not find variable at start of %s" % token

View File

@ -25,6 +25,8 @@ def stringfilter(func):
if args: if args:
args = list(args) args = list(args)
args[0] = force_unicode(args[0]) args[0] = force_unicode(args[0])
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
return mark_safe(func(*args, **kwargs))
return func(*args, **kwargs) return func(*args, **kwargs)
# Include a reference to the real function (used to check original # Include a reference to the real function (used to check original
@ -106,6 +108,7 @@ floatformat.is_safe = True
def iriencode(value): def iriencode(value):
"""Escapes an IRI value for use in a URL.""" """Escapes an IRI value for use in a URL."""
return force_unicode(iri_to_uri(value)) return force_unicode(iri_to_uri(value))
iriencode.is_safe = True
iriencode = stringfilter(iriencode) iriencode = stringfilter(iriencode)
def linenumbers(value, autoescape=None): def linenumbers(value, autoescape=None):

View File

@ -51,9 +51,9 @@ class TestCase(unittest.TestCase):
def _pre_setup(self): def _pre_setup(self):
"""Performs any pre-test setup. This includes: """Performs any pre-test setup. This includes:
* If the Test Case class has a 'fixtures' member, clearing the * Flushing the database.
database and installing the named fixtures at the start of each * If the Test Case class has a 'fixtures' member, installing the
test. named fixtures.
* Clearing the mail test outbox. * Clearing the mail test outbox.
""" """
call_command('flush', verbosity=0, interactive=False) call_command('flush', verbosity=0, interactive=False)

View File

@ -20,6 +20,10 @@ An example: i18n middleware would need to distinguish caches by the
import md5 import md5
import re import re
import time import time
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
@ -70,8 +74,6 @@ def patch_cache_control(response, **kwargs):
cc = ', '.join([dictvalue(el) for el in cc.items()]) cc = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc response['Cache-Control'] = cc
vary_delim_re = re.compile(r',\s*')
def patch_response_headers(response, cache_timeout=None): def patch_response_headers(response, cache_timeout=None):
""" """
Adds some useful headers to the given HttpResponse object: Adds some useful headers to the given HttpResponse object:
@ -109,14 +111,15 @@ def patch_vary_headers(response, newheaders):
# Note that we need to keep the original order intact, because cache # Note that we need to keep the original order intact, because cache
# implementations may rely on the order of the Vary contents in, say, # implementations may rely on the order of the Vary contents in, say,
# computing an MD5 hash. # computing an MD5 hash.
vary = []
if response.has_header('Vary'): if response.has_header('Vary'):
vary = vary_delim_re.split(response['Vary']) vary_headers = cc_delim_re.split(response['Vary'])
oldheaders = dict([(el.lower(), 1) for el in vary]) else:
for newheader in newheaders: vary_headers = []
if not newheader.lower() in oldheaders: # Use .lower() here so we treat headers as case-insensitive.
vary.append(newheader) existing_headers = set([header.lower() for header in vary_headers])
response['Vary'] = ', '.join(vary) additional_headers = [newheader for newheader in newheaders
if newheader.lower() not in existing_headers]
response['Vary'] = ', '.join(vary_headers + additional_headers)
def _generate_cache_key(request, headerlist, key_prefix): def _generate_cache_key(request, headerlist, key_prefix):
"""Returns a cache key from the headers given in the header list.""" """Returns a cache key from the headers given in the header list."""
@ -169,7 +172,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
key_prefix, iri_to_uri(request.path)) key_prefix, iri_to_uri(request.path))
if response.has_header('Vary'): if response.has_header('Vary'):
headerlist = ['HTTP_'+header.upper().replace('-', '_') headerlist = ['HTTP_'+header.upper().replace('-', '_')
for header in vary_delim_re.split(response['Vary'])] for header in cc_delim_re.split(response['Vary'])]
cache.set(cache_key, headerlist, cache_timeout) cache.set(cache_key, headerlist, cache_timeout)
return _generate_cache_key(request, headerlist, key_prefix) return _generate_cache_key(request, headerlist, key_prefix)
else: else:

View File

@ -7,9 +7,9 @@ class MergeDict(object):
self.dicts = dicts self.dicts = dicts
def __getitem__(self, key): def __getitem__(self, key):
for dict in self.dicts: for dict_ in self.dicts:
try: try:
return dict[key] return dict_[key]
except KeyError: except KeyError:
pass pass
raise KeyError raise KeyError
@ -24,22 +24,22 @@ class MergeDict(object):
return default return default
def getlist(self, key): def getlist(self, key):
for dict in self.dicts: for dict_ in self.dicts:
try: try:
return dict.getlist(key) return dict_.getlist(key)
except KeyError: except KeyError:
pass pass
raise KeyError raise KeyError
def items(self): def items(self):
item_list = [] item_list = []
for dict in self.dicts: for dict_ in self.dicts:
item_list.extend(dict.items()) item_list.extend(dict_.items())
return item_list return item_list
def has_key(self, key): def has_key(self, key):
for dict in self.dicts: for dict_ in self.dicts:
if key in dict: if key in dict_:
return True return True
return False return False
@ -56,7 +56,7 @@ class SortedDict(dict):
def __init__(self, data=None): def __init__(self, data=None):
if data is None: if data is None:
data = {} data = {}
dict.__init__(self, data) super(SortedDict, self).__init__(data)
if isinstance(data, dict): if isinstance(data, dict):
self.keyOrder = data.keys() self.keyOrder = data.keys()
else: else:
@ -68,12 +68,12 @@ class SortedDict(dict):
for key, value in self.iteritems()]) for key, value in self.iteritems()])
def __setitem__(self, key, value): def __setitem__(self, key, value):
dict.__setitem__(self, key, value) super(SortedDict, self).__setitem__(key, value)
if key not in self.keyOrder: if key not in self.keyOrder:
self.keyOrder.append(key) self.keyOrder.append(key)
def __delitem__(self, key): def __delitem__(self, key):
dict.__delitem__(self, key) super(SortedDict, self).__delitem__(key)
self.keyOrder.remove(key) self.keyOrder.remove(key)
def __iter__(self): def __iter__(self):
@ -81,7 +81,7 @@ class SortedDict(dict):
yield k yield k
def pop(self, k, *args): def pop(self, k, *args):
result = dict.pop(self, k, *args) result = super(SortedDict, self).pop(k, *args)
try: try:
self.keyOrder.remove(k) self.keyOrder.remove(k)
except ValueError: except ValueError:
@ -90,7 +90,7 @@ class SortedDict(dict):
return result return result
def popitem(self): def popitem(self):
result = dict.popitem(self) result = super(SortedDict, self).popitem()
self.keyOrder.remove(result[0]) self.keyOrder.remove(result[0])
return result return result
@ -99,7 +99,7 @@ class SortedDict(dict):
def iteritems(self): def iteritems(self):
for key in self.keyOrder: for key in self.keyOrder:
yield key, dict.__getitem__(self, key) yield key, super(SortedDict, self).__getitem__(key)
def keys(self): def keys(self):
return self.keyOrder[:] return self.keyOrder[:]
@ -108,20 +108,20 @@ class SortedDict(dict):
return iter(self.keyOrder) return iter(self.keyOrder)
def values(self): def values(self):
return [dict.__getitem__(self, k) for k in self.keyOrder] return [super(SortedDict, self).__getitem__(k) for k in self.keyOrder]
def itervalues(self): def itervalues(self):
for key in self.keyOrder: for key in self.keyOrder:
yield dict.__getitem__(self, key) yield super(SortedDict, self).__getitem__(key)
def update(self, dict): def update(self, dict_):
for k, v in dict.items(): for k, v in dict_.items():
self.__setitem__(k, v) self.__setitem__(k, v)
def setdefault(self, key, default): def setdefault(self, key, default):
if key not in self.keyOrder: if key not in self.keyOrder:
self.keyOrder.append(key) self.keyOrder.append(key)
return dict.setdefault(self, key, default) return super(SortedDict, self).setdefault(key, default)
def value_for_index(self, index): def value_for_index(self, index):
"""Returns the value of the item at the given zero-based index.""" """Returns the value of the item at the given zero-based index."""
@ -135,7 +135,7 @@ class SortedDict(dict):
if n < index: if n < index:
index -= 1 index -= 1
self.keyOrder.insert(index, key) self.keyOrder.insert(index, key)
dict.__setitem__(self, key, value) super(SortedDict, self).__setitem__(key, value)
def copy(self): def copy(self):
"""Returns a copy of this object.""" """Returns a copy of this object."""
@ -173,10 +173,11 @@ class MultiValueDict(dict):
single name-value pairs. single name-value pairs.
""" """
def __init__(self, key_to_list_mapping=()): def __init__(self, key_to_list_mapping=()):
dict.__init__(self, key_to_list_mapping) super(MultiValueDict, self).__init__(key_to_list_mapping)
def __repr__(self): def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, dict.__repr__(self)) return "<%s: %s>" % (self.__class__.__name__,
super(MultiValueDict, self).__repr__())
def __getitem__(self, key): def __getitem__(self, key):
""" """
@ -184,7 +185,7 @@ class MultiValueDict(dict):
raises KeyError if not found. raises KeyError if not found.
""" """
try: try:
list_ = dict.__getitem__(self, key) list_ = super(MultiValueDict, self).__getitem__(key)
except KeyError: except KeyError:
raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self) raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)
try: try:
@ -193,10 +194,10 @@ class MultiValueDict(dict):
return [] return []
def __setitem__(self, key, value): def __setitem__(self, key, value):
dict.__setitem__(self, key, [value]) super(MultiValueDict, self).__setitem__(key, [value])
def __copy__(self): def __copy__(self):
return self.__class__(dict.items(self)) return self.__class__(super(MultiValueDict, self).items())
def __deepcopy__(self, memo=None): def __deepcopy__(self, memo=None):
import copy import copy
@ -210,7 +211,10 @@ class MultiValueDict(dict):
return result return result
def get(self, key, default=None): def get(self, key, default=None):
"""Returns the default value if the requested data doesn't exist.""" """
Returns the last data value for the passed key. If key doesn't exist
or value is an empty list, then default is returned.
"""
try: try:
val = self[key] val = self[key]
except KeyError: except KeyError:
@ -220,14 +224,17 @@ class MultiValueDict(dict):
return val return val
def getlist(self, key): def getlist(self, key):
"""Returns an empty list if the requested data doesn't exist.""" """
Returns the list of values for the passed key. If key doesn't exist,
then an empty list is returned.
"""
try: try:
return dict.__getitem__(self, key) return super(MultiValueDict, self).__getitem__(key)
except KeyError: except KeyError:
return [] return []
def setlist(self, key, list_): def setlist(self, key, list_):
dict.__setitem__(self, key, list_) super(MultiValueDict, self).__setitem__(key, list_)
def setdefault(self, key, default=None): def setdefault(self, key, default=None):
if key not in self: if key not in self:
@ -242,7 +249,7 @@ class MultiValueDict(dict):
def appendlist(self, key, value): def appendlist(self, key, value):
"""Appends an item to the internal list associated with key.""" """Appends an item to the internal list associated with key."""
self.setlistdefault(key, []) self.setlistdefault(key, [])
dict.__setitem__(self, key, self.getlist(key) + [value]) super(MultiValueDict, self).__setitem__(key, self.getlist(key) + [value])
def items(self): def items(self):
""" """
@ -253,7 +260,7 @@ class MultiValueDict(dict):
def lists(self): def lists(self):
"""Returns a list of (key, list) pairs.""" """Returns a list of (key, list) pairs."""
return dict.items(self) return super(MultiValueDict, self).items()
def values(self): def values(self):
"""Returns a list of the last value on every key list.""" """Returns a list of the last value on every key list."""
@ -315,7 +322,7 @@ class DotExpandedDict(dict):
try: try:
current[bits[-1]] = v current[bits[-1]] = v
except TypeError: # Special-case if current isn't a dict. except TypeError: # Special-case if current isn't a dict.
current = {bits[-1] : v} current = {bits[-1]: v}
class FileDict(dict): class FileDict(dict):
""" """

View File

@ -168,10 +168,9 @@ def translation(language):
res.merge(t) res.merge(t)
return res return res
if hasattr(settings, 'LOCALE_PATHS'): for localepath in settings.LOCALE_PATHS:
for localepath in settings.LOCALE_PATHS: if os.path.isdir(localepath):
if os.path.isdir(localepath): res = _merge(localepath)
res = _merge(localepath)
if projectpath and os.path.isdir(projectpath): if projectpath and os.path.isdir(projectpath):
res = _merge(projectpath) res = _merge(projectpath)

View File

@ -422,11 +422,11 @@ TECHNICAL_500_TEMPLATE = """
{% if frame.context_line %} {% if frame.context_line %}
<div class="context" id="c{{ frame.id }}"> <div class="context" id="c{{ frame.id }}">
{% if frame.pre_context %} {% if frame.pre_context %}
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol> <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
{% endif %} {% endif %}
<ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line }} <span>...</span></li></ol> <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line|escape }} <span>...</span></li></ol>
{% if frame.post_context %} {% if frame.post_context %}
<ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol> <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
@ -445,8 +445,8 @@ TECHNICAL_500_TEMPLATE = """
<tbody> <tbody>
{% for var in frame.vars|dictsort:"0" %} {% for var in frame.vars|dictsort:"0" %}
<tr> <tr>
<td>{{ var.0 }}</td> <td>{{ var.0|escape }}</td>
<td class="code"><div>{{ var.1|pprint }}</div></td> <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -466,7 +466,7 @@ Traceback (most recent call last):<br/>
{% for frame in frames %} {% for frame in frames %}
File "{{ frame.filename }}" in {{ frame.function }}<br/> File "{{ frame.filename }}" in {{ frame.function }}<br/>
{% if frame.context_line %} {% if frame.context_line %}
&nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line }}<br/> &nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line|escape }}<br/>
{% endif %} {% endif %}
{% endfor %}<br/> {% endfor %}<br/>
&nbsp;&nbsp;{{ exception_type }} at {{ request.path|escape }}<br/> &nbsp;&nbsp;{{ exception_type }} at {{ request.path|escape }}<br/>

View File

@ -658,7 +658,7 @@ message file. The choice is yours.
of the settings file to determine this, and a settings file doesn't exist of the settings file to determine this, and a settings file doesn't exist
if you're manually configuring your settings.) if you're manually configuring your settings.)
.. _settings documentation: ../settings/#using-settings-without-the-django-settings-module-environment-variable .. _settings documentation: ../settings/#using-settings-without-setting-django-settings-module
All message file repositories are structured the same way. They are: All message file repositories are structured the same way. They are:

View File

@ -583,7 +583,7 @@ LOCALE_PATHS
Default: ``()`` (Empty tuple) Default: ``()`` (Empty tuple)
A list of directories where Django looks for translation files. A tuple of directories where Django looks for translation files.
See the `internationalization docs section`_ explaining the variable and the See the `internationalization docs section`_ explaining the variable and the
default behavior. default behavior.

View File

@ -755,61 +755,106 @@ inside the template code:
``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry ``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry
about these; they exist for the implementation of the ``escape`` filter. about these; they exist for the implementation of the ``escape`` filter.
Inside your filter, you will need to think about three areas in order to be When you are writing a filter, your code will typically fall into one of two
auto-escaping compliant: situations:
1. If your filter returns a string that is ready for direct output (it should 1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``,
be considered a "safe" string), you should call ``'``, ``"`` or ``&``) into the result that were not already present. In
``django.utils.safestring.mark_safe()`` on the result prior to returning. this case, you can let Django take care of all the auto-escaping handling
This will turn the result into the appropriate ``SafeData`` type. This is for you. All you need to do is put the ``is_safe`` attribute on your
often the case when you are returning raw HTML, for example. filter function and set it to ``True``. This attribute tells Django that
is a "safe" string is passed into your filter, the result will still be
"safe" and if a non-safe string is passed in, Django will automatically
escape it, if necessary. The reason ``is_safe`` is necessary is because
there are plenty of normal string operations that will turn a ``SafeData``
object back into a normal ``str`` or ``unicode`` object and, rather than
try to catch them all, which would be very difficult, Django repairs the
damage after the filter has completed.
2. If your filter is given a "safe" string, is it guaranteed to return a For example, suppose you have a filter that adds the string ``xx`` to the
"safe" string? If so, set the ``is_safe`` attribute on the function to be end of any input. Since this introduces no dangerous HTML characters into
``True``. For example, a filter that replaced a word consisting only of the result (aside from any that were already present), you should mark
digits with the number spelt out in words is going to be your filter with ``is_safe``::
safe-string-preserving, since it cannot introduce any of the five dangerous
characters: <, >, ", ' or &. We can write::
@register.filter @register.filter
def convert_to_words(value): def add_xx(value):
# ... implementation here ... return '%sxx' % value
return result add_xx.is_safe = True
convert_to_words.is_safe = True When this filter is used in a template where auto-escaping is enabled,
Django will escape the output whenever the input is not already marked as
"safe".
Note that this filter does not return a universally safe result (it does By default, ``is_safe`` defaults to ``False`` and you can omit it from
not return ``mark_safe(result)``) because if it is handed a raw string such any filters where it isn't required.
as '<a>', this will need further escaping in an auto-escape environment.
The ``is_safe`` attribute only talks about the the result when a safe
string is passed into the filter.
3. Will your filter behave differently depending upon whether auto-escaping Be careful when deciding if your filter really does leave safe strings
is currently in effect or not? This is normally a concern when you are as safe. Sometimes if you are *removing* characters, you can
returning mixed content (HTML elements mixed with user-supplied content). inadvertently leave unbalanced HTML tags or entities in the result.
For example, the ``ordered_list`` filter that ships with Django needs to For example, removing a ``>`` from the input might turn ``<a>`` into
know whether to escape its content or not. It will always return a safe ``<a``, which would need to be escaped on output to avoid causing
string. Since it returns raw HTML, we cannot apply escaping to the problems. Similarly, removing a semicolon (``;``) can turn ``&amp;``
result -- it needs to be done in-situ. into ``&amp``, which is no longer a valid entity and thus needs
further escaping. Most cases won't be nearly this tricky, but keep an
eye out for any problems like that when reviewing your code.
For these cases, the filter function needs to be told what the current 2. Alternatively, your filter code can manually take care of any necessary
auto-escaping setting is. Set the ``needs_autoescape`` attribute on the escaping. This is usually necessary when you are introducing new HTML
filter to ``True`` and have your function take an extra argument called markup into the result. You want to mark the output as safe from further
``autoescape`` with a default value of ``None``. When the filter is called, escaping so that your HTML markup isn't escaped further, so you'll need to
the ``autoescape`` keyword argument will be ``True`` if auto-escaping is in handle the input yourself.
effect. For example, the ``unordered_list`` filter is written as::
def unordered_list(value, autoescape=None): To mark the output as a safe string, use
# ... lots of code here ... ``django.utils.safestring.mark_safe()``.
return mark_safe(...) Be careful, though. You need to do more than just mark the output as
safe. You need to ensure it really *is* safe and what you do will often
depend upon whether or not auto-escaping is in effect. The idea is to
write filters than can operate in templates where auto-escaping is either
on or off in order to make things easier for your template authors.
unordered_list.is_safe = True In order for you filter to know the current auto-escaping state, set the
unordered_list.needs_autoescape = True ``needs_autoescape`` attribute to ``True`` on your function (if you don't
specify this attribute, it defaults to ``False``). This attribute tells
Django that your filter function wants to be passed an extra keyword
argument, called ``autoescape`` that is ``True`` is auto-escaping is in
effect and ``False`` otherwise.
By default, both the ``is_safe`` and ``needs_autoescape`` attributes are An example might make this clearer. Let's write a filter that emphasizes
``False``. You do not need to specify them if ``False`` is an acceptable the first character of a string::
value.
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
def initial_letter_filter(text, autoescape=None):
first, other = text[0] ,text[1:]
if autoescape:
esc = conditional_escape
else:
esc = lambda x: x
result = '<strong>%s</strong>%s' % (esc(first), esc(other))
return mark_safe(result)
initial_letter_filter.needs_autoescape = True
The ``needs_autoescape`` attribute on the filter function and the
``autoescape`` keyword argument mean that our function will know whether
or not automatic escaping is in effect when the filter is called. We use
``autoescape`` to decide whether the input data needs to be passed through
``django.utils.html.conditional_escape`` or not (in the latter case, we
just use the identity function as the "escape" function). The
``conditional_escape()`` function is like ``escape()`` except it only
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
instance is passed to ``conditional_escape()``, the data is returned
unchanged.
Finally, in the above example, we remember to mark the result as safe
so that our HTML is inserted directly into the template without further
escaping.
There is no need to worry about the ``is_safe`` attribute in this case
(although including it wouldn't hurt anything). Whenever you are manually
handling the auto-escaping issues and returning a safe string, the
``is_safe`` attribute won't change anything either way.
Writing custom template tags Writing custom template tags
---------------------------- ----------------------------
@ -932,7 +977,9 @@ without having to be parsed multiple times.
Auto-escaping considerations Auto-escaping considerations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The output from template tags is not automatically run through the **New in Django development version**
The output from template tags is **not** automatically run through the
auto-escaping filters. However, there are still a couple of things you should auto-escaping filters. However, there are still a couple of things you should
keep in mind when writing a template tag: keep in mind when writing a template tag:

View File

@ -78,7 +78,8 @@ True
>>> paginator.pages >>> paginator.pages
2 2
# The paginator can provide a list of all available pages # The paginator can provide a list of all available pages.
>>> paginator = ObjectPaginator(Article.objects.all(), 10)
>>> paginator.page_range >>> paginator.page_range
[1, 2] [1, 2]
"""} """}

View File

@ -3,9 +3,12 @@
# Unit tests for cache framework # Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file. # Uses whatever cache backend is set in the test settings file.
from django.core.cache import cache
import time, unittest import time, unittest
from django.core.cache import cache
from django.utils.cache import patch_vary_headers
from django.http import HttpResponse
# functions/classes for complex data type tests # functions/classes for complex data type tests
def f(): def f():
return 42 return 42
@ -87,5 +90,30 @@ class Cache(unittest.TestCase):
cache.set(key, value) cache.set(key, value)
self.assertEqual(cache.get(key), value) self.assertEqual(cache.get(key), value)
class CacheUtils(unittest.TestCase):
"""TestCase for django.utils.cache functions."""
def test_patch_vary_headers(self):
headers = (
# Initial vary, new headers, resulting vary.
(None, ('Accept-Encoding',), 'Accept-Encoding'),
('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
(None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
)
for initial_vary, newheaders, resulting_vary in headers:
response = HttpResponse()
if initial_vary is not None:
response['Vary'] = initial_vary
patch_vary_headers(response, newheaders)
self.assertEqual(response['Vary'], resulting_vary)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -25,11 +25,23 @@
>>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']}) >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
>>> d['name'] >>> d['name']
'Simon' 'Simon'
>>> d.get('name')
'Simon'
>>> d.getlist('name') >>> d.getlist('name')
['Adrian', 'Simon'] ['Adrian', 'Simon']
>>> d['lastname']
Traceback (most recent call last):
...
MultiValueDictKeyError: "Key 'lastname' not found in <MultiValueDict: {'position': ['Developer'], 'name': ['Adrian', 'Simon']}>"
>>> d.get('lastname')
>>> d.get('lastname', 'nonexistent') >>> d.get('lastname', 'nonexistent')
'nonexistent' 'nonexistent'
>>> d.getlist('lastname')
[]
>>> d.setlist('lastname', ['Holovaty', 'Willison']) >>> d.setlist('lastname', ['Holovaty', 'Willison'])
>>> d.getlist('lastname')
['Holovaty', 'Willison']
### SortedDict ################################################################# ### SortedDict #################################################################

View File

@ -0,0 +1,360 @@
# -*- coding: utf-8 -*-
tests = r"""
>>> from django.newforms import *
# CharField ###################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
>>> f = CharField(min_length=5, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('1234')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 4, MIN LENGTH 5']
>>> f.clean('12345678901')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 11, MAX LENGTH 10']
# IntegerField ################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('4')
Traceback (most recent call last):
...
ValidationError: [u'MIN VALUE IS 5']
>>> f.clean('11')
Traceback (most recent call last):
...
ValidationError: [u'MAX VALUE IS 10']
# FloatField ##################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> f = FloatField(min_value=5, max_value=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('4')
Traceback (most recent call last):
...
ValidationError: [u'MIN VALUE IS 5']
>>> f.clean('11')
Traceback (most recent call last):
...
ValidationError: [u'MAX VALUE IS 10']
# DecimalField ################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_value'] = 'MIN VALUE IS %s'
>>> e['max_value'] = 'MAX VALUE IS %s'
>>> e['max_digits'] = 'MAX DIGITS IS %s'
>>> e['max_decimal_places'] = 'MAX DP IS %s'
>>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'
>>> f = DecimalField(min_value=5, max_value=10, error_messages=e)
>>> f2 = DecimalField(max_digits=4, decimal_places=2, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('4')
Traceback (most recent call last):
...
ValidationError: [u'MIN VALUE IS 5']
>>> f.clean('11')
Traceback (most recent call last):
...
ValidationError: [u'MAX VALUE IS 10']
>>> f2.clean('123.45')
Traceback (most recent call last):
...
ValidationError: [u'MAX DIGITS IS 4']
>>> f2.clean('1.234')
Traceback (most recent call last):
...
ValidationError: [u'MAX DP IS 2']
>>> f2.clean('123.4')
Traceback (most recent call last):
...
ValidationError: [u'MAX DIGITS BEFORE DP IS 2']
# DateField ###################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> f = DateField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
# TimeField ###################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> f = TimeField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
# DateTimeField ###############################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> f = DateTimeField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
# RegexField ##################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
>>> f = RegexField(r'^\d+$', min_length=5, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abcde')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('1234')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 4, MIN LENGTH 5']
>>> f.clean('12345678901')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 11, MAX LENGTH 10']
# EmailField ##################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['min_length'] = 'LENGTH %(length)s, MIN LENGTH %(min)s'
>>> e['max_length'] = 'LENGTH %(length)s, MAX LENGTH %(max)s'
>>> f = EmailField(min_length=8, max_length=10, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abcdefgh')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('a@b.com')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 7, MIN LENGTH 8']
>>> f.clean('aye@bee.com')
Traceback (most recent call last):
...
ValidationError: [u'LENGTH 11, MAX LENGTH 10']
# FileField ##################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['missing'] = 'MISSING'
>>> e['empty'] = 'EMPTY FILE'
>>> f = FileField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean({})
Traceback (most recent call last):
...
ValidationError: [u'MISSING']
>>> f.clean({'filename': 'name', 'content':''})
Traceback (most recent call last):
...
ValidationError: [u'EMPTY FILE']
# URLField ##################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID'
>>> e['invalid_link'] = 'INVALID LINK'
>>> f = URLField(verify_exists=True, error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('abc.c')
Traceback (most recent call last):
...
ValidationError: [u'INVALID']
>>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com')
Traceback (most recent call last):
...
ValidationError: [u'INVALID LINK']
# BooleanField ################################################################
>>> e = {'required': 'REQUIRED'}
>>> f = BooleanField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
# ChoiceField #################################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
>>> f = ChoiceField(choices=[('a', 'aye')], error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('b')
Traceback (most recent call last):
...
ValidationError: [u'b IS INVALID CHOICE']
# MultipleChoiceField #########################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
>>> e['invalid_list'] = 'NOT A LIST'
>>> f = MultipleChoiceField(choices=[('a', 'aye')], error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('b')
Traceback (most recent call last):
...
ValidationError: [u'NOT A LIST']
>>> f.clean(['b'])
Traceback (most recent call last):
...
ValidationError: [u'b IS INVALID CHOICE']
# SplitDateTimeField ##########################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_date'] = 'INVALID DATE'
>>> e['invalid_time'] = 'INVALID TIME'
>>> f = SplitDateTimeField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean(['a', 'b'])
Traceback (most recent call last):
...
ValidationError: [u'INVALID DATE', u'INVALID TIME']
# IPAddressField ##############################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid'] = 'INVALID IP ADDRESS'
>>> f = IPAddressField(error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('127.0.0')
Traceback (most recent call last):
...
ValidationError: [u'INVALID IP ADDRESS']
###############################################################################
# Create choices for the model choice field tests below.
>>> from regressiontests.forms.models import ChoiceModel
>>> ChoiceModel.objects.create(pk=1, name='a')
<ChoiceModel: ChoiceModel object>
>>> ChoiceModel.objects.create(pk=2, name='b')
<ChoiceModel: ChoiceModel object>
>>> ChoiceModel.objects.create(pk=3, name='c')
<ChoiceModel: ChoiceModel object>
# ModelChoiceField ############################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = 'INVALID CHOICE'
>>> f = ModelChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('4')
Traceback (most recent call last):
...
ValidationError: [u'INVALID CHOICE']
# ModelMultipleChoiceField ####################################################
>>> e = {'required': 'REQUIRED'}
>>> e['invalid_choice'] = '%s IS INVALID CHOICE'
>>> e['list'] = 'NOT A LIST OF VALUES'
>>> f = ModelMultipleChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'REQUIRED']
>>> f.clean('3')
Traceback (most recent call last):
...
ValidationError: [u'NOT A LIST OF VALUES']
>>> f.clean(['4'])
Traceback (most recent call last):
...
ValidationError: [u'4 IS INVALID CHOICE']
"""

View File

@ -10,6 +10,10 @@ class Defaults(models.Model):
def_date = models.DateField(default = datetime.date(1980, 1, 1)) def_date = models.DateField(default = datetime.date(1980, 1, 1))
value = models.IntegerField(default=42) value = models.IntegerField(default=42)
class ChoiceModel(models.Model):
"""For ModelChoiceField and ModelMultipleChoiceField tests."""
name = models.CharField(max_length=10)
__test__ = {'API_TESTS': """ __test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance >>> from django.newforms import form_for_model, form_for_instance

View File

@ -2,6 +2,7 @@
tests = r""" tests = r"""
>>> from django.newforms import * >>> from django.newforms import *
>>> from django.newforms.widgets import RadioFieldRenderer >>> from django.newforms.widgets import RadioFieldRenderer
>>> from django.utils.safestring import mark_safe
>>> import datetime >>> import datetime
>>> import time >>> import time
>>> import re >>> import re
@ -205,6 +206,8 @@ u'<textarea rows="10" cols="40" name="msg"></textarea>'
u'<textarea rows="10" cols="40" name="msg">value</textarea>' u'<textarea rows="10" cols="40" name="msg">value</textarea>'
>>> w.render('msg', 'some "quoted" & ampersanded value') >>> w.render('msg', 'some "quoted" & ampersanded value')
u'<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>' u'<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>'
>>> w.render('msg', mark_safe('pre &quot;quoted&quot; value'))
u'<textarea rows="10" cols="40" name="msg">pre &quot;quoted&quot; value</textarea>'
>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}) >>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>' u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>'
@ -375,6 +378,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<option value="5">5</option> <option value="5">5</option>
</select> </select>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<select name="escape">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="bad">you &amp; me</option>
<option value="good">you &gt; me</option>
</select>
# Unicode choices are correctly rendered as HTML
>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) >>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>' u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
@ -538,6 +552,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<option value="5">5</option> <option value="5">5</option>
</select> </select>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<select multiple="multiple" name="escape">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="bad">you &amp; me</option>
<option value="good">you &gt; me</option>
</select>
# Unicode choices are correctly rendered as HTML
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>' u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
@ -663,6 +688,16 @@ You can create your own custom renderers for RadioSelect to use.
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br /> <label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
<label><input type="radio" name="beatle" value="R" /> Ringo</label> <label><input type="radio" name="beatle" value="R" /> Ringo</label>
Or you can use custom RadioSelect fields that use your custom renderer.
>>> class CustomRadioSelect(RadioSelect):
... renderer = MyRenderer
>>> w = CustomRadioSelect()
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
<label><input type="radio" name="beatle" value="J" /> John</label><br />
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
A RadioFieldRenderer object also allows index access to individual RadioInput A RadioFieldRenderer object also allows index access to individual RadioInput
objects. objects.
>>> w = RadioSelect() >>> w = RadioSelect()
@ -682,6 +717,14 @@ Traceback (most recent call last):
... ...
IndexError: list index out of range IndexError: list index out of range
# Choices are escaped correctly
>>> w = RadioSelect()
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<ul>
<li><label><input type="radio" name="escape" value="bad" /> you &amp; me</label></li>
<li><label><input type="radio" name="escape" value="good" /> you &gt; me</label></li>
</ul>
# Unicode choices are correctly rendered as HTML # Unicode choices are correctly rendered as HTML
>>> w = RadioSelect() >>> w = RadioSelect()
>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])) >>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
@ -811,6 +854,17 @@ If 'choices' is passed to both the constructor and render(), then they'll both b
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li> <li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
</ul> </ul>
# Choices are escaped correctly
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
<ul>
<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
<li><label><input type="checkbox" name="escape" value="bad" /> you &amp; me</label></li>
<li><label><input type="checkbox" name="escape" value="good" /> you &gt; me</label></li>
</ul>
# Unicode choices are correctly rendered as HTML
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>' u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'

View File

@ -198,6 +198,12 @@ def get_filter_tests():
'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"), 'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "<1-800-2255-63> <1-800-2255-63>"), 'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "<1-800-2255-63> <1-800-2255-63>"),
# Ensure iriencode keeps safe strings:
'filter-iriencode01': ('{{ url|iriencode }}', {'url': '?test=1&me=2'}, '?test=1&amp;me=2'),
'filter-iriencode02': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': '?test=1&me=2'}, '?test=1&me=2'),
'filter-iriencode03': ('{{ url|iriencode }}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
'filter-iriencode04': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
# Chaining a bunch of safeness-preserving filters should not alter # Chaining a bunch of safeness-preserving filters should not alter
# the safe status either way. # the safe status either way.
'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "), 'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),

View File

@ -268,6 +268,12 @@ class Templates(unittest.TestCase):
# Embedded newlines make it not-a-tag. # Embedded newlines make it not-a-tag.
'basic-syntax24': ("{{ moo\n }}", {}, "{{ moo\n }}"), 'basic-syntax24': ("{{ moo\n }}", {}, "{{ moo\n }}"),
# Literal strings are permitted inside variables, mostly for i18n
# purposes.
'basic-syntax25': ('{{ "fred" }}', {}, "fred"),
'basic-syntax26': (r'{{ "\"fred\"" }}', {}, "\"fred\""),
'basic-syntax27': (r'{{ _("\"fred\"") }}', {}, "\"fred\""),
# List-index syntax allows a template to access a certain item of a subscriptable object. # List-index syntax allows a template to access a certain item of a subscriptable object.
'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"), 'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),