mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
gis: Merged revisions 6525-6613 via svnmerge from [repos:django/trunk trunk].
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6615 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f66ee9d006
commit
4ffbddf92d
6
AUTHORS
6
AUTHORS
@ -50,6 +50,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Fabrice Aneche <akh@nobugware.com>
|
Fabrice Aneche <akh@nobugware.com>
|
||||||
ant9000@netwise.it
|
ant9000@netwise.it
|
||||||
Florian Apolloner
|
Florian Apolloner
|
||||||
|
arien <regexbot@gmail.com>
|
||||||
David Ascher <http://ascher.ca/>
|
David Ascher <http://ascher.ca/>
|
||||||
david@kazserve.org
|
david@kazserve.org
|
||||||
Arthur <avandorp@gmail.com>
|
Arthur <avandorp@gmail.com>
|
||||||
@ -169,6 +170,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Nagy Károly <charlie@rendszergazda.com>
|
Nagy Károly <charlie@rendszergazda.com>
|
||||||
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
||||||
Ian G. Kelly <ian.g.kelly@gmail.com>
|
Ian G. Kelly <ian.g.kelly@gmail.com>
|
||||||
|
Thomas Kerpe <thomas@kerpe.net>
|
||||||
Ben Khoo <khoobks@westnet.com.au>
|
Ben Khoo <khoobks@westnet.com.au>
|
||||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||||
kilian <kilian.cavalotti@lip6.fr>
|
kilian <kilian.cavalotti@lip6.fr>
|
||||||
@ -213,6 +215,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jason McBrayer <http://www.carcosa.net/jason/>
|
Jason McBrayer <http://www.carcosa.net/jason/>
|
||||||
mccutchen@gmail.com
|
mccutchen@gmail.com
|
||||||
michael.mcewan@gmail.com
|
michael.mcewan@gmail.com
|
||||||
|
michal@plovarna.cz
|
||||||
mikko@sorl.net
|
mikko@sorl.net
|
||||||
Slawek Mikula <slawek dot mikula at gmail dot com>
|
Slawek Mikula <slawek dot mikula at gmail dot com>
|
||||||
mitakummaa@gmail.com
|
mitakummaa@gmail.com
|
||||||
@ -256,6 +259,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Brian Ray <http://brianray.chipy.org/>
|
Brian Ray <http://brianray.chipy.org/>
|
||||||
remco@diji.biz
|
remco@diji.biz
|
||||||
rhettg@gmail.com
|
rhettg@gmail.com
|
||||||
|
ricardojbarrios@gmail.com
|
||||||
Matt Riggott
|
Matt Riggott
|
||||||
Henrique Romano <onaiort@gmail.com>
|
Henrique Romano <onaiort@gmail.com>
|
||||||
Armin Ronacher
|
Armin Ronacher
|
||||||
@ -270,6 +274,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
serbaut@gmail.com
|
serbaut@gmail.com
|
||||||
John Shaffer <jshaffer2112@gmail.com>
|
John Shaffer <jshaffer2112@gmail.com>
|
||||||
Pete Shinners <pete@shinners.org>
|
Pete Shinners <pete@shinners.org>
|
||||||
|
jason.sidabras@gmail.com
|
||||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||||
SmileyChris <smileychris@gmail.com>
|
SmileyChris <smileychris@gmail.com>
|
||||||
smurf@smurf.noris.de
|
smurf@smurf.noris.de
|
||||||
@ -324,6 +329,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jakub Wiśniowski <restless.being@gmail.com>
|
Jakub Wiśniowski <restless.being@gmail.com>
|
||||||
Maciej Wiśniowski <pigletto@gmail.com>
|
Maciej Wiśniowski <pigletto@gmail.com>
|
||||||
wojtek
|
wojtek
|
||||||
|
Jason Yan <tailofthesun@gmail.com>
|
||||||
ye7cakf02@sneakemail.com
|
ye7cakf02@sneakemail.com
|
||||||
ymasuda@ethercube.com
|
ymasuda@ethercube.com
|
||||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||||
|
@ -140,13 +140,3 @@ class UserSettingsHolder(object):
|
|||||||
|
|
||||||
settings = LazySettings()
|
settings = LazySettings()
|
||||||
|
|
||||||
# This function replaces itself with django.utils.translation.gettext() the
|
|
||||||
# first time it's run. This is necessary because the import of
|
|
||||||
# django.utils.translation requires a working settings module, and loading it
|
|
||||||
# from within this file would cause a circular import.
|
|
||||||
def first_time_gettext(*args):
|
|
||||||
from django.utils.translation import gettext
|
|
||||||
__builtins__['_'] = gettext
|
|
||||||
return gettext(*args)
|
|
||||||
|
|
||||||
__builtins__['_'] = first_time_gettext
|
|
||||||
|
@ -30,7 +30,7 @@ INTERNAL_IPS = ()
|
|||||||
TIME_ZONE = 'America/Chicago'
|
TIME_ZONE = 'America/Chicago'
|
||||||
|
|
||||||
# Language code for this installation. All choices can be found here:
|
# Language code for this installation. All choices can be found here:
|
||||||
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
# Languages we provide translations for, out of the box. The language name
|
# Languages we provide translations for, out of the box. The language name
|
||||||
@ -275,6 +275,7 @@ SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can
|
|||||||
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
|
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
|
||||||
SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
|
SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
|
||||||
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
|
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
|
||||||
|
SESSION_COOKIE_PATH = '/' # The path of the session cookie.
|
||||||
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
|
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
|
||||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
|
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
|
||||||
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
|
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -6,12 +6,12 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django Javascript 1.0\n"
|
"Project-Id-Version: Django Javascript 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2007-07-14 13:45-0300\n"
|
"POT-Creation-Date: 2007-10-06 14:18-0300\n"
|
||||||
"PO-Revision-Date: 2007-07-14 14:36-0300\n"
|
"PO-Revision-Date: 2007-07-14 14:36-0300\n"
|
||||||
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
||||||
"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
|
"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
@ -44,8 +44,8 @@ msgstr "Seleccione los items a agregar y haga click en "
|
|||||||
msgid "Clear all"
|
msgid "Clear all"
|
||||||
msgstr "Eliminar todos"
|
msgstr "Eliminar todos"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:32
|
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
|
#: contrib/admin/media/js/dateparse.js:32
|
||||||
msgid ""
|
msgid ""
|
||||||
"January February March April May June July August September October November "
|
"January February March April May June July August September October November "
|
||||||
"December"
|
"December"
|
||||||
@ -53,14 +53,14 @@ msgstr ""
|
|||||||
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Setiembre Octubre "
|
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Setiembre Octubre "
|
||||||
"Noviembre Diciembre"
|
"Noviembre Diciembre"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:33
|
|
||||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
|
||||||
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
|
||||||
|
|
||||||
#: contrib/admin/media/js/calendar.js:25
|
#: contrib/admin/media/js/calendar.js:25
|
||||||
msgid "S M T W T F S"
|
msgid "S M T W T F S"
|
||||||
msgstr "D L M M J V S"
|
msgstr "D L M M J V S"
|
||||||
|
|
||||||
|
#: contrib/admin/media/js/dateparse.js:33
|
||||||
|
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||||
|
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||||
msgid "Show"
|
msgid "Show"
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -7,7 +7,7 @@ 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-08-06 23:19+0200\n"
|
"POT-Creation-Date: 2007-08-06 23:19+0200\n"
|
||||||
"PO-Revision-Date: 2007-08-12 23:05+0200\n"
|
"PO-Revision-Date: 2007-10-12 21:22+0200\n"
|
||||||
"Last-Translator: Aljosa Mohorovic <aljosa.mohorovic@gmail.com>\n"
|
"Last-Translator: Aljosa Mohorovic <aljosa.mohorovic@gmail.com>\n"
|
||||||
"Language-Team: Hrvatski jezik\n"
|
"Language-Team: Hrvatski jezik\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -28,7 +28,7 @@ msgstr "Unos za ovo polje je obavezan."
|
|||||||
#, 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."
|
||||||
msgstr[0] "Uneseni tekst mora sadržavati manje od %s znaka."
|
msgstr[0] ""
|
||||||
msgstr[1] "Uneseni tekst mora sadržavati manje od %s znakova."
|
msgstr[1] "Uneseni tekst mora sadržavati manje od %s znakova."
|
||||||
|
|
||||||
#: oldforms/__init__.py:413
|
#: oldforms/__init__.py:413
|
||||||
@ -398,62 +398,62 @@ msgstr "URL %s ne prikazuje ispravnu sliku."
|
|||||||
#: core/validators.py:196
|
#: core/validators.py:196
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
|
msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid."
|
||||||
msgstr ""
|
msgstr "Telefonski brojevi moraju biti u formatu XXX-XXX-XXXX. \"%s\" nije ispravan format."
|
||||||
|
|
||||||
#: core/validators.py:204
|
#: core/validators.py:204
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The URL %s does not point to a valid QuickTime video."
|
msgid "The URL %s does not point to a valid QuickTime video."
|
||||||
msgstr ""
|
msgstr "URL %s ne vodi na ispravan QuickTime video."
|
||||||
|
|
||||||
#: core/validators.py:208
|
#: core/validators.py:208
|
||||||
msgid "A valid URL is required."
|
msgid "A valid URL is required."
|
||||||
msgstr ""
|
msgstr "Ispravan URL je obavezan."
|
||||||
|
|
||||||
#: core/validators.py:222
|
#: core/validators.py:222
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Valid HTML is required. Specific errors are:\n"
|
"Valid HTML is required. Specific errors are:\n"
|
||||||
"%s"
|
"%s"
|
||||||
msgstr ""
|
msgstr "Ispravan HTML je obavezan. Pogreške:<br> %s"
|
||||||
|
|
||||||
#: core/validators.py:229
|
#: core/validators.py:229
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Badly formed XML: %s"
|
msgid "Badly formed XML: %s"
|
||||||
msgstr ""
|
msgstr "Loše formatiran XML: %s"
|
||||||
|
|
||||||
#: core/validators.py:246
|
#: core/validators.py:246
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Invalid URL: %s"
|
msgid "Invalid URL: %s"
|
||||||
msgstr ""
|
msgstr "Neispravan URL: %s"
|
||||||
|
|
||||||
#: core/validators.py:251 core/validators.py:253
|
#: core/validators.py:251 core/validators.py:253
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The URL %s is a broken link."
|
msgid "The URL %s is a broken link."
|
||||||
msgstr ""
|
msgstr "URL %s je neispravan (broken) link."
|
||||||
|
|
||||||
#: core/validators.py:259
|
#: core/validators.py:259
|
||||||
msgid "Enter a valid U.S. state abbreviation."
|
msgid "Enter a valid U.S. state abbreviation."
|
||||||
msgstr ""
|
msgstr "Enter a valid U.S. state abbreviation."
|
||||||
|
|
||||||
#: core/validators.py:273
|
#: core/validators.py:273
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Watch your mouth! The word %s is not allowed here."
|
msgid "Watch your mouth! The word %s is not allowed here."
|
||||||
msgid_plural "Watch your mouth! The words %s are not allowed here."
|
msgid_plural "Watch your mouth! The words %s are not allowed here."
|
||||||
msgstr[0] ""
|
msgstr[0] "Pazite na izražavanje! Riječ %s nije dopuštena."
|
||||||
msgstr[1] ""
|
msgstr[1] "Pazite na izražavanje! Riječi %s nisu dopuštene."
|
||||||
|
|
||||||
#: core/validators.py:280
|
#: core/validators.py:280
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This field must match the '%s' field."
|
msgid "This field must match the '%s' field."
|
||||||
msgstr ""
|
msgstr "Ovo polje mora biti jednako %s polju."
|
||||||
|
|
||||||
#: core/validators.py:299
|
#: core/validators.py:299
|
||||||
msgid "Please enter something for at least one field."
|
msgid "Please enter something for at least one field."
|
||||||
msgstr ""
|
msgstr "Molim unesite nešto bar za jedno polje."
|
||||||
|
|
||||||
#: core/validators.py:308 core/validators.py:319
|
#: core/validators.py:308 core/validators.py:319
|
||||||
msgid "Please enter both fields or leave them both empty."
|
msgid "Please enter both fields or leave them both empty."
|
||||||
msgstr ""
|
msgstr "Molim unesite vrijednosti za oba polja ili ostavite oba polja prazna."
|
||||||
|
|
||||||
#: core/validators.py:327
|
#: core/validators.py:327
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -463,7 +463,7 @@ msgstr ""
|
|||||||
#: core/validators.py:340
|
#: core/validators.py:340
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This field must be given if %(field)s is not %(value)s"
|
msgid "This field must be given if %(field)s is not %(value)s"
|
||||||
msgstr ""
|
msgstr "Ovo polje je obavezno ako je %(field)s različito od %(value)s"
|
||||||
|
|
||||||
#: core/validators.py:359
|
#: core/validators.py:359
|
||||||
msgid "Duplicate values are not allowed."
|
msgid "Duplicate values are not allowed."
|
||||||
@ -471,28 +471,27 @@ msgstr ""
|
|||||||
|
|
||||||
#: core/validators.py:374
|
#: core/validators.py:374
|
||||||
#, python-format
|
#, python-format
|
||||||
#, fuzzy
|
|
||||||
msgid "This value must be between %(lower)s and %(upper)s."
|
msgid "This value must be between %(lower)s and %(upper)s."
|
||||||
msgstr "i."
|
msgstr "Vrijednost mora biti između %(lower)s i %(upper)s."
|
||||||
|
|
||||||
#: core/validators.py:376
|
#: core/validators.py:376
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This value must be at least %s."
|
msgid "This value must be at least %s."
|
||||||
msgstr ""
|
msgstr "Vrijednost mora biti bar %s."
|
||||||
|
|
||||||
#: core/validators.py:378
|
#: core/validators.py:378
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This value must be no more than %s."
|
msgid "This value must be no more than %s."
|
||||||
msgstr ""
|
msgstr "Vrijednost ne može biti veća od %s."
|
||||||
|
|
||||||
#: core/validators.py:414
|
#: core/validators.py:414
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This value must be a power of %s."
|
msgid "This value must be a power of %s."
|
||||||
msgstr ""
|
msgstr "Ova vrijednost na kvadrat mora biti %s."
|
||||||
|
|
||||||
#: core/validators.py:424
|
#: core/validators.py:424
|
||||||
msgid "Please enter a valid decimal number."
|
msgid "Please enter a valid decimal number."
|
||||||
msgstr ""
|
msgstr "Molim unesite ispravan decimalni broj."
|
||||||
|
|
||||||
#: core/validators.py:431
|
#: core/validators.py:431
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -1879,7 +1878,6 @@ msgid "Documentation bookmarklets"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
|
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
|
||||||
@ -1890,107 +1888,110 @@ msgid ""
|
|||||||
"your computer is \"internal\").</p>\n"
|
"your computer is \"internal\").</p>\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p class=\"help\"> i</p>"
|
"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n"
|
||||||
|
"toolbar, or right-click the link and add it to your bookmarks. Now you can\n"
|
||||||
|
"select the bookmarklet from any page in the site. Note that some of these\n"
|
||||||
|
"bookmarklets require you to be viewing the site from a computer designated\n"
|
||||||
|
"as \"internal\" (talk to your system administrator if you aren't sure if\n"
|
||||||
|
"your computer is \"internal\").</p>\n"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:19
|
||||||
msgid "Documentation for this page"
|
msgid "Documentation for this page"
|
||||||
msgstr ""
|
msgstr "Dokumentacija za ovu stranicu"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
|
||||||
msgid ""
|
msgid ""
|
||||||
"Jumps you from any page to the documentation for the view that generates "
|
"Jumps you from any page to the documentation for the view that generates "
|
||||||
"that page."
|
"that page."
|
||||||
msgstr ""
|
msgstr "Preusmjeri te sa bilo koje stranice na dokumentaciju za taj prikaz (view) koji generira stranicu."
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
||||||
msgid "Show object ID"
|
msgid "Show object ID"
|
||||||
msgstr ""
|
msgstr "Prikaži ID objekta"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Shows the content-type and unique ID for pages that represent a single "
|
"Shows the content-type and unique ID for pages that represent a single "
|
||||||
"object."
|
"object."
|
||||||
msgstr "i."
|
msgstr "Prikazuje tip sadržaja i jedinstveni ID za stranice koje predstavljaju pojedinačan objekt."
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:25
|
||||||
msgid "Edit this object (current window)"
|
msgid "Edit this object (current window)"
|
||||||
msgstr ""
|
msgstr "Uredi objekt (u trenutno prozoru)"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
||||||
msgid "Jumps to the admin page for pages that represent a single object."
|
msgid "Jumps to the admin page for pages that represent a single object."
|
||||||
msgstr ""
|
msgstr "Preusmjeri na admin stranicu za stranice koje predstavljaju pojedinačan objekt."
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:28
|
||||||
msgid "Edit this object (new window)"
|
msgid "Edit this object (new window)"
|
||||||
msgstr ""
|
msgstr "Uredi objekt (novi prozor)"
|
||||||
|
|
||||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
|
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
|
||||||
msgid "As above, but opens the admin page in a new window."
|
msgid "As above, but opens the admin page in a new window."
|
||||||
msgstr ""
|
msgstr "Isto kao prethodno, ali otvara admin stranicu u novom prozoru."
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:37
|
#: contrib/contenttypes/models.py:37
|
||||||
msgid "python model class name"
|
msgid "python model class name"
|
||||||
msgstr ""
|
msgstr "ime klase (class) python modela"
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:40
|
#: contrib/contenttypes/models.py:40
|
||||||
msgid "content type"
|
msgid "content type"
|
||||||
msgstr ""
|
msgstr "tip sadržaja"
|
||||||
|
|
||||||
#: contrib/contenttypes/models.py:41
|
#: contrib/contenttypes/models.py:41
|
||||||
msgid "content types"
|
msgid "content types"
|
||||||
msgstr ""
|
msgstr "tipovi sadržaja"
|
||||||
|
|
||||||
#: contrib/auth/views.py:41
|
#: contrib/auth/views.py:41
|
||||||
msgid "Logged out"
|
msgid "Logged out"
|
||||||
msgstr ""
|
msgstr "Niste logirani"
|
||||||
|
|
||||||
#: contrib/auth/models.py:53 contrib/auth/models.py:73
|
#: contrib/auth/models.py:53 contrib/auth/models.py:73
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr ""
|
msgstr "ime"
|
||||||
|
|
||||||
#: contrib/auth/models.py:55
|
#: contrib/auth/models.py:55
|
||||||
msgid "codename"
|
msgid "codename"
|
||||||
msgstr ""
|
msgstr "kodno ime"
|
||||||
|
|
||||||
#: contrib/auth/models.py:58
|
#: contrib/auth/models.py:58
|
||||||
msgid "permission"
|
msgid "permission"
|
||||||
msgstr ""
|
msgstr "privilegija"
|
||||||
|
|
||||||
#: contrib/auth/models.py:59 contrib/auth/models.py:74
|
#: contrib/auth/models.py:59 contrib/auth/models.py:74
|
||||||
msgid "permissions"
|
msgid "permissions"
|
||||||
msgstr ""
|
msgstr "privilegije"
|
||||||
|
|
||||||
#: contrib/auth/models.py:77
|
#: contrib/auth/models.py:77
|
||||||
msgid "group"
|
msgid "group"
|
||||||
msgstr ""
|
msgstr "grupa"
|
||||||
|
|
||||||
#: contrib/auth/models.py:78 contrib/auth/models.py:121
|
#: contrib/auth/models.py:78 contrib/auth/models.py:121
|
||||||
msgid "groups"
|
msgid "groups"
|
||||||
msgstr ""
|
msgstr "grupe"
|
||||||
|
|
||||||
#: contrib/auth/models.py:111
|
#: contrib/auth/models.py:111
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr ""
|
msgstr "korisničko ime"
|
||||||
|
|
||||||
#: contrib/auth/models.py:111
|
#: contrib/auth/models.py:111
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
||||||
"digits and underscores)."
|
"digits and underscores)."
|
||||||
msgstr "i."
|
msgstr "Obavezno 30 alfanumeričkih znakova ili manje (slova, brojevi i povlaka)."
|
||||||
|
|
||||||
#: contrib/auth/models.py:112
|
#: contrib/auth/models.py:112
|
||||||
msgid "first name"
|
msgid "first name"
|
||||||
msgstr ""
|
msgstr "ime"
|
||||||
|
|
||||||
#: contrib/auth/models.py:113
|
#: contrib/auth/models.py:113
|
||||||
msgid "last name"
|
msgid "last name"
|
||||||
msgstr ""
|
msgstr "prezime"
|
||||||
|
|
||||||
#: contrib/auth/models.py:114
|
#: contrib/auth/models.py:114
|
||||||
msgid "e-mail address"
|
msgid "e-mail address"
|
||||||
msgstr ""
|
msgstr "e-mail adresa"
|
||||||
|
|
||||||
#: contrib/auth/models.py:115
|
#: contrib/auth/models.py:115
|
||||||
msgid "password"
|
msgid "password"
|
||||||
@ -2207,7 +2208,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: contrib/localflavor/de/de_states.py:17
|
#: contrib/localflavor/de/de_states.py:17
|
||||||
msgid "Saxony"
|
msgid "Saxony"
|
||||||
msgstr ""
|
msgstr "Saxony"
|
||||||
|
|
||||||
#: contrib/localflavor/de/de_states.py:18
|
#: contrib/localflavor/de/de_states.py:18
|
||||||
msgid "Saxony-Anhalt"
|
msgid "Saxony-Anhalt"
|
||||||
@ -2899,306 +2900,305 @@ msgstr ""
|
|||||||
|
|
||||||
#: contrib/localflavor/sk/sk_districts.py:85
|
#: contrib/localflavor/sk/sk_districts.py:85
|
||||||
msgid "Ziar nad Hronom"
|
msgid "Ziar nad Hronom"
|
||||||
msgstr ""
|
msgstr "Ziar nad Hronom"
|
||||||
|
|
||||||
#: contrib/localflavor/sk/sk_districts.py:86
|
#: contrib/localflavor/sk/sk_districts.py:86
|
||||||
msgid "Zilina"
|
msgid "Zilina"
|
||||||
msgstr ""
|
msgstr "Zilina"
|
||||||
|
|
||||||
#: contrib/localflavor/sk/forms.py:32
|
#: contrib/localflavor/sk/forms.py:32
|
||||||
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 ""
|
msgstr "Unesi ispravan poštanski broj formata XXXXX or XXX XX."
|
||||||
|
|
||||||
#: contrib/localflavor/cl/forms.py:32
|
#: contrib/localflavor/cl/forms.py:32
|
||||||
msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
|
msgid "Enter valid a Chilean RUT. The format is XX.XXX.XXX-X."
|
||||||
msgstr ""
|
msgstr "Unesi ispravan čileanski RUT formata XX.XXX.XXX-X."
|
||||||
|
|
||||||
#: contrib/localflavor/cl/forms.py:37
|
#: contrib/localflavor/cl/forms.py:37
|
||||||
msgid "Enter valid a Chilean RUT"
|
msgid "Enter valid a Chilean RUT"
|
||||||
msgstr ""
|
msgstr "Unesi ispravan čileanski RUT"
|
||||||
|
|
||||||
#: 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 ""
|
msgstr "Unesi ispravan finski broj socijalnog osiguranja."
|
||||||
|
|
||||||
#: contrib/sessions/models.py:68
|
#: contrib/sessions/models.py:68
|
||||||
msgid "session key"
|
msgid "session key"
|
||||||
msgstr ""
|
msgstr "session ključ (key)"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:69
|
#: contrib/sessions/models.py:69
|
||||||
msgid "session data"
|
msgid "session data"
|
||||||
msgstr ""
|
msgstr "session podaci"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:70
|
#: contrib/sessions/models.py:70
|
||||||
msgid "expire date"
|
msgid "expire date"
|
||||||
msgstr ""
|
msgstr "ističe datuma"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:74
|
#: contrib/sessions/models.py:74
|
||||||
msgid "session"
|
msgid "session"
|
||||||
msgstr ""
|
msgstr "session"
|
||||||
|
|
||||||
#: contrib/sessions/models.py:75
|
#: contrib/sessions/models.py:75
|
||||||
msgid "sessions"
|
msgid "sessions"
|
||||||
msgstr ""
|
msgstr "sessions"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:8
|
#: contrib/flatpages/models.py:8
|
||||||
#, fuzzy
|
|
||||||
msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
|
msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes."
|
||||||
msgstr "i."
|
msgstr "Primjer: '/about/contact/'. Provjerite ako imate prvi i preostale slash-eve (/)."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:9
|
#: contrib/flatpages/models.py:9
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr "naslov"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:10
|
#: contrib/flatpages/models.py:10
|
||||||
msgid "content"
|
msgid "content"
|
||||||
msgstr ""
|
msgstr "sadržaj"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:11
|
#: contrib/flatpages/models.py:11
|
||||||
msgid "enable comments"
|
msgid "enable comments"
|
||||||
msgstr ""
|
msgstr "uključi komentare"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:12
|
#: contrib/flatpages/models.py:12
|
||||||
msgid "template name"
|
msgid "template name"
|
||||||
msgstr ""
|
msgstr "ime template-a"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:13
|
#: contrib/flatpages/models.py:13
|
||||||
msgid ""
|
msgid ""
|
||||||
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
||||||
"will use 'flatpages/default.html'."
|
"will use 'flatpages/default.html'."
|
||||||
msgstr ""
|
msgstr "Primjer: 'flatpages/contact_page.html'. Ako navedeno nije definirano sistem će koristiti 'flatpages/default.html'."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:14
|
#: contrib/flatpages/models.py:14
|
||||||
msgid "registration required"
|
msgid "registration required"
|
||||||
msgstr ""
|
msgstr "registracija obavezna"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:14
|
#: contrib/flatpages/models.py:14
|
||||||
msgid "If this is checked, only logged-in users will be able to view the page."
|
msgid "If this is checked, only logged-in users will be able to view the page."
|
||||||
msgstr ""
|
msgstr "Ako je ovo selektirano samo logirani korisnici moći će vidjeti ovu stranicu."
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:18
|
#: contrib/flatpages/models.py:18
|
||||||
msgid "flat page"
|
msgid "flat page"
|
||||||
msgstr ""
|
msgstr "statična stranica"
|
||||||
|
|
||||||
#: contrib/flatpages/models.py:19
|
#: contrib/flatpages/models.py:19
|
||||||
msgid "flat pages"
|
msgid "flat pages"
|
||||||
msgstr ""
|
msgstr "statične stranice"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Monday"
|
msgid "Monday"
|
||||||
msgstr ""
|
msgstr "Ponedjeljak"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Tuesday"
|
msgid "Tuesday"
|
||||||
msgstr ""
|
msgstr "Utorak"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Wednesday"
|
msgid "Wednesday"
|
||||||
msgstr ""
|
msgstr "Srijeda"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Thursday"
|
msgid "Thursday"
|
||||||
msgstr ""
|
msgstr "Četvrtak"
|
||||||
|
|
||||||
#: utils/dates.py:6
|
#: utils/dates.py:6
|
||||||
msgid "Friday"
|
msgid "Friday"
|
||||||
msgstr ""
|
msgstr "Petak"
|
||||||
|
|
||||||
#: utils/dates.py:7
|
#: utils/dates.py:7
|
||||||
msgid "Saturday"
|
msgid "Saturday"
|
||||||
msgstr ""
|
msgstr "Subota"
|
||||||
|
|
||||||
#: utils/dates.py:7
|
#: utils/dates.py:7
|
||||||
msgid "Sunday"
|
msgid "Sunday"
|
||||||
msgstr ""
|
msgstr "Nedjelja"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Mon"
|
msgid "Mon"
|
||||||
msgstr ""
|
msgstr "Pon"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Tue"
|
msgid "Tue"
|
||||||
msgstr ""
|
msgstr "Uto"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Wed"
|
msgid "Wed"
|
||||||
msgstr ""
|
msgstr "Sri"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Thu"
|
msgid "Thu"
|
||||||
msgstr ""
|
msgstr "Čet"
|
||||||
|
|
||||||
#: utils/dates.py:10
|
#: utils/dates.py:10
|
||||||
msgid "Fri"
|
msgid "Fri"
|
||||||
msgstr ""
|
msgstr "Pet"
|
||||||
|
|
||||||
#: utils/dates.py:11
|
#: utils/dates.py:11
|
||||||
msgid "Sat"
|
msgid "Sat"
|
||||||
msgstr ""
|
msgstr "Sub"
|
||||||
|
|
||||||
#: utils/dates.py:11
|
#: utils/dates.py:11
|
||||||
msgid "Sun"
|
msgid "Sun"
|
||||||
msgstr ""
|
msgstr "Ned"
|
||||||
|
|
||||||
#: utils/dates.py:18
|
#: utils/dates.py:18
|
||||||
msgid "January"
|
msgid "January"
|
||||||
msgstr ""
|
msgstr "Siječanj"
|
||||||
|
|
||||||
#: utils/dates.py:18
|
#: utils/dates.py:18
|
||||||
msgid "February"
|
msgid "February"
|
||||||
msgstr ""
|
msgstr "Veljača"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "March"
|
msgid "March"
|
||||||
msgstr ""
|
msgstr "Ožujak"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "April"
|
msgid "April"
|
||||||
msgstr ""
|
msgstr "Travanj"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr ""
|
msgstr "Svibanj"
|
||||||
|
|
||||||
#: utils/dates.py:18 utils/dates.py:31
|
#: utils/dates.py:18 utils/dates.py:31
|
||||||
msgid "June"
|
msgid "June"
|
||||||
msgstr ""
|
msgstr "Lipanj"
|
||||||
|
|
||||||
#: utils/dates.py:19 utils/dates.py:31
|
#: utils/dates.py:19 utils/dates.py:31
|
||||||
msgid "July"
|
msgid "July"
|
||||||
msgstr ""
|
msgstr "Srpanj"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "August"
|
msgid "August"
|
||||||
msgstr ""
|
msgstr "Kolovoz"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "September"
|
msgid "September"
|
||||||
msgstr ""
|
msgstr "Rujan"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "October"
|
msgid "October"
|
||||||
msgstr ""
|
msgstr "Listopad"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "November"
|
msgid "November"
|
||||||
msgstr ""
|
msgstr "Studeni"
|
||||||
|
|
||||||
#: utils/dates.py:20
|
#: utils/dates.py:20
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr ""
|
msgstr "Prosinac"
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "jan"
|
msgid "jan"
|
||||||
msgstr ""
|
msgstr "sij."
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "feb"
|
msgid "feb"
|
||||||
msgstr ""
|
msgstr "velj."
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "mar"
|
msgid "mar"
|
||||||
msgstr ""
|
msgstr "ožu."
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "apr"
|
msgid "apr"
|
||||||
msgstr ""
|
msgstr "tra."
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "may"
|
msgid "may"
|
||||||
msgstr ""
|
msgstr "svi."
|
||||||
|
|
||||||
#: utils/dates.py:23
|
#: utils/dates.py:23
|
||||||
msgid "jun"
|
msgid "jun"
|
||||||
msgstr ""
|
msgstr "lip."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "jul"
|
msgid "jul"
|
||||||
msgstr ""
|
msgstr "srp."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "aug"
|
msgid "aug"
|
||||||
msgstr ""
|
msgstr "kol."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "sep"
|
msgid "sep"
|
||||||
msgstr ""
|
msgstr "ruj."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "oct"
|
msgid "oct"
|
||||||
msgstr ""
|
msgstr "lis."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "nov"
|
msgid "nov"
|
||||||
msgstr ""
|
msgstr "stu."
|
||||||
|
|
||||||
#: utils/dates.py:24
|
#: utils/dates.py:24
|
||||||
msgid "dec"
|
msgid "dec"
|
||||||
msgstr ""
|
msgstr "pro."
|
||||||
|
|
||||||
#: utils/dates.py:31
|
#: utils/dates.py:31
|
||||||
msgid "Jan."
|
msgid "Jan."
|
||||||
msgstr ""
|
msgstr "Sij."
|
||||||
|
|
||||||
#: utils/dates.py:31
|
#: utils/dates.py:31
|
||||||
msgid "Feb."
|
msgid "Feb."
|
||||||
msgstr ""
|
msgstr "Velj."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Aug."
|
msgid "Aug."
|
||||||
msgstr ""
|
msgstr "Kol."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Sept."
|
msgid "Sept."
|
||||||
msgstr ""
|
msgstr "Ruj."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Oct."
|
msgid "Oct."
|
||||||
msgstr ""
|
msgstr "Lis."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Nov."
|
msgid "Nov."
|
||||||
msgstr ""
|
msgstr "Stu."
|
||||||
|
|
||||||
#: utils/dates.py:32
|
#: utils/dates.py:32
|
||||||
msgid "Dec."
|
msgid "Dec."
|
||||||
msgstr ""
|
msgstr "Pro."
|
||||||
|
|
||||||
#: utils/timesince.py:12
|
#: utils/timesince.py:12
|
||||||
msgid "year"
|
msgid "year"
|
||||||
msgid_plural "years"
|
msgid_plural "years"
|
||||||
msgstr[0] ""
|
msgstr[0] "godina"
|
||||||
msgstr[1] ""
|
msgstr[1] "godina"
|
||||||
|
|
||||||
#: utils/timesince.py:13
|
#: utils/timesince.py:13
|
||||||
msgid "month"
|
msgid "month"
|
||||||
msgid_plural "months"
|
msgid_plural "months"
|
||||||
msgstr[0] ""
|
msgstr[0] "mjesec"
|
||||||
msgstr[1] ""
|
msgstr[1] "mjesec"
|
||||||
|
|
||||||
#: utils/timesince.py:14
|
#: utils/timesince.py:14
|
||||||
msgid "week"
|
msgid "week"
|
||||||
msgid_plural "weeks"
|
msgid_plural "weeks"
|
||||||
msgstr[0] ""
|
msgstr[0] "tjedan"
|
||||||
msgstr[1] ""
|
msgstr[1] "tjedan"
|
||||||
|
|
||||||
#: utils/timesince.py:15
|
#: utils/timesince.py:15
|
||||||
msgid "day"
|
msgid "day"
|
||||||
msgid_plural "days"
|
msgid_plural "days"
|
||||||
msgstr[0] ""
|
msgstr[0] "dan"
|
||||||
msgstr[1] ""
|
msgstr[1] "dan"
|
||||||
|
|
||||||
#: utils/timesince.py:16
|
#: utils/timesince.py:16
|
||||||
msgid "hour"
|
msgid "hour"
|
||||||
msgid_plural "hours"
|
msgid_plural "hours"
|
||||||
msgstr[0] ""
|
msgstr[0] "sati"
|
||||||
msgstr[1] ""
|
msgstr[1] "sati"
|
||||||
|
|
||||||
#: utils/timesince.py:17
|
#: utils/timesince.py:17
|
||||||
msgid "minute"
|
msgid "minute"
|
||||||
msgid_plural "minutes"
|
msgid_plural "minutes"
|
||||||
msgstr[0] ""
|
msgstr[0] "minute"
|
||||||
msgstr[1] ""
|
msgstr[1] "minuta"
|
||||||
|
|
||||||
#: utils/timesince.py:39
|
#: utils/timesince.py:39
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -3228,7 +3228,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: utils/dateformat.py:97
|
#: utils/dateformat.py:97
|
||||||
msgid "midnight"
|
msgid "midnight"
|
||||||
msgstr ""
|
msgstr "ponoć"
|
||||||
|
|
||||||
#: utils/dateformat.py:99
|
#: utils/dateformat.py:99
|
||||||
msgid "noon"
|
msgid "noon"
|
||||||
@ -3256,7 +3256,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: template/defaultfilters.py:485
|
#: template/defaultfilters.py:485
|
||||||
msgid "yes,no,maybe"
|
msgid "yes,no,maybe"
|
||||||
msgstr ""
|
msgstr "da,ne,možda"
|
||||||
|
|
||||||
#: template/defaultfilters.py:514
|
#: template/defaultfilters.py:514
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -45,7 +45,14 @@ var UKRAINIAN_MAP = {
|
|||||||
}
|
}
|
||||||
var CZECH_MAP = {
|
var CZECH_MAP = {
|
||||||
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
|
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
|
||||||
'ž':'z'
|
'ž':'z', 'Č':'C', 'Ď':'D', 'Ě':'E', 'Ň': 'N', 'Ř':'R', 'Š':'S', 'Ť':'T',
|
||||||
|
'Ů':'U', 'Ž':'Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
var POLISH_MAP = {
|
||||||
|
'ą':'a', 'ć':'c', 'ę':'e', 'ł':'l', 'ń':'n', 'ó':'o', 'ś':'s', 'ź':'z',
|
||||||
|
'ż':'z', 'Ą':'A', 'Ć':'C', 'Ę':'e', 'Ł':'L', 'Ń':'N', 'Ó':'o', 'Ś':'S',
|
||||||
|
'Ź':'Z', 'Ż':'Z'
|
||||||
}
|
}
|
||||||
|
|
||||||
var ALL_DOWNCODE_MAPS=new Array()
|
var ALL_DOWNCODE_MAPS=new Array()
|
||||||
@ -56,6 +63,7 @@ ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
|
|||||||
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
||||||
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
|
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
|
||||||
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
||||||
|
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
|
||||||
|
|
||||||
var Downcoder = new Object();
|
var Downcoder = new Object();
|
||||||
Downcoder.Initialize = function()
|
Downcoder.Initialize = function()
|
||||||
|
@ -4,7 +4,7 @@ from django.contrib.syndication.feeds import Feed
|
|||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
|
||||||
class LatestFreeCommentsFeed(Feed):
|
class LatestFreeCommentsFeed(Feed):
|
||||||
"Feed of latest comments on the current site."
|
"""Feed of latest free comments on the current site."""
|
||||||
|
|
||||||
comments_class = FreeComment
|
comments_class = FreeComment
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class LatestFreeCommentsFeed(Feed):
|
|||||||
return self.get_query_set()[:40]
|
return self.get_query_set()[:40]
|
||||||
|
|
||||||
class LatestCommentsFeed(LatestFreeCommentsFeed):
|
class LatestCommentsFeed(LatestFreeCommentsFeed):
|
||||||
"""Feed of latest free comments on the current site"""
|
"""Feed of latest comments on the current site."""
|
||||||
|
|
||||||
comments_class = Comment
|
comments_class = Comment
|
||||||
|
|
||||||
|
0
django/contrib/localflavor/es/__init__.py
Normal file
0
django/contrib/localflavor/es/__init__.py
Normal file
58
django/contrib/localflavor/es/es_provinces.py
Normal file
58
django/contrib/localflavor/es/es_provinces.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
PROVINCE_CHOICES = (
|
||||||
|
('01', _('Arava')),
|
||||||
|
('02', _('Albacete')),
|
||||||
|
('03', _('Alacant')),
|
||||||
|
('04', _('Almeria')),
|
||||||
|
('05', _('Avila')),
|
||||||
|
('06', _('Badajoz')),
|
||||||
|
('07', _('Illes Balears')),
|
||||||
|
('08', _('Barcelona')),
|
||||||
|
('09', _('Burgos')),
|
||||||
|
('10', _('Caceres')),
|
||||||
|
('11', _('Cadiz')),
|
||||||
|
('12', _('Castello')),
|
||||||
|
('13', _('Ciudad Real')),
|
||||||
|
('14', _('Cordoba')),
|
||||||
|
('15', _('A Coruna')),
|
||||||
|
('16', _('Cuenca')),
|
||||||
|
('17', _('Girona')),
|
||||||
|
('18', _('Granada')),
|
||||||
|
('19', _('Guadalajara')),
|
||||||
|
('20', _('Guipuzkoa')),
|
||||||
|
('21', _('Huelva')),
|
||||||
|
('22', _('Huesca')),
|
||||||
|
('23', _('Jaen')),
|
||||||
|
('24', _('Leon')),
|
||||||
|
('25', _('Lleida')),
|
||||||
|
('26', _('La Rioja')),
|
||||||
|
('27', _('Lugo')),
|
||||||
|
('28', _('Madrid')),
|
||||||
|
('29', _('Malaga')),
|
||||||
|
('30', _('Murcia')),
|
||||||
|
('31', _('Navarre')),
|
||||||
|
('32', _('Ourense')),
|
||||||
|
('33', _('Asturias')),
|
||||||
|
('34', _('Palencia')),
|
||||||
|
('35', _('Las Palmas')),
|
||||||
|
('36', _('Pontevedra')),
|
||||||
|
('37', _('Salamanca')),
|
||||||
|
('38', _('Santa Cruz de Tenerife')),
|
||||||
|
('39', _('Cantabria')),
|
||||||
|
('40', _('Segovia')),
|
||||||
|
('41', _('Seville')),
|
||||||
|
('42', _('Soria')),
|
||||||
|
('43', _('Tarragona')),
|
||||||
|
('44', _('Teruel')),
|
||||||
|
('45', _('Toledo')),
|
||||||
|
('46', _('Valencia')),
|
||||||
|
('47', _('Valladolid')),
|
||||||
|
('48', _('Bizkaia')),
|
||||||
|
('49', _('Zamora')),
|
||||||
|
('50', _('Zaragoza')),
|
||||||
|
('51', _('Ceuta')),
|
||||||
|
('52', _('Melilla')),
|
||||||
|
)
|
||||||
|
|
23
django/contrib/localflavor/es/es_regions.py
Normal file
23
django/contrib/localflavor/es/es_regions.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
REGION_CHOICES = (
|
||||||
|
('AN', _('Andalusia')),
|
||||||
|
('AR', _('Aragon')),
|
||||||
|
('O', _('Principality of Asturias')),
|
||||||
|
('IB', _('Balearic Islands')),
|
||||||
|
('PV', _('Basque Country')),
|
||||||
|
('CN', _('Canary Islands')),
|
||||||
|
('S', _('Cantabria')),
|
||||||
|
('CM', _('Castile-La Mancha')),
|
||||||
|
('CL', _('Castile and Leon')),
|
||||||
|
('CT', _('Catalonia')),
|
||||||
|
('EX', _('Extremadura')),
|
||||||
|
('GA', _('Galicia')),
|
||||||
|
('LO', _('La Rioja')),
|
||||||
|
('M', _('Madrid')),
|
||||||
|
('MU', _('Region of Murcia')),
|
||||||
|
('NA', _('Foral Community of Navarre')),
|
||||||
|
('VC', _('Valencian Community')),
|
||||||
|
)
|
||||||
|
|
173
django/contrib/localflavor/es/forms.py
Normal file
173
django/contrib/localflavor/es/forms.py
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Spanish-specific Form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.newforms import ValidationError
|
||||||
|
from django.newforms.fields import RegexField, Select, EMPTY_VALUES
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
import re
|
||||||
|
|
||||||
|
class ESPostalCodeField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validates its input as a spanish postal code.
|
||||||
|
|
||||||
|
Spanish postal code is a five digits string, with two first digits
|
||||||
|
between 01 and 52, assigned to provinces code.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ESPostalCodeField, self).__init__(
|
||||||
|
r'^(0[1-9]|[1-4][0-9]|5[0-2])\d{3}$',
|
||||||
|
max_length=None, min_length=None,
|
||||||
|
error_message=_('Enter a valid postal code in the range and format 01XXX - 52XXX.'),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
class ESPhoneNumberField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validates its input as a Spanish phone number.
|
||||||
|
Information numbers are ommited.
|
||||||
|
|
||||||
|
Spanish phone numbers are nine digit numbers, where first digit is 6 (for
|
||||||
|
cell phones), 8 (for special phones), or 9 (for landlines and special
|
||||||
|
phones)
|
||||||
|
|
||||||
|
TODO: accept and strip characters like dot, hyphen... in phone number
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ESPhoneNumberField, self).__init__(r'^(6|8|9)\d{8}$',
|
||||||
|
max_length=None, min_length=None,
|
||||||
|
error_message=_('Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.'),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
class ESIdentityCardNumberField(RegexField):
|
||||||
|
"""
|
||||||
|
Spanish NIF/NIE/CIF (Fiscal Identification Number) code.
|
||||||
|
|
||||||
|
Validates three diferent formats:
|
||||||
|
|
||||||
|
NIF (individuals): 12345678A
|
||||||
|
CIF (companies): A12345678
|
||||||
|
NIE (foreigners): X12345678A
|
||||||
|
|
||||||
|
according to a couple of simple checksum algorithms.
|
||||||
|
|
||||||
|
Value can include a space or hyphen separator between number and letters.
|
||||||
|
Number length is not checked for NIF (or NIE), old values start with a 1,
|
||||||
|
and future values can contain digits greater than 8. The CIF control digit
|
||||||
|
can be a number or a letter depending on company type. Algorithm is not
|
||||||
|
public, and different authors have different opinions on which ones allows
|
||||||
|
letters, so both validations are assumed true for all types.
|
||||||
|
"""
|
||||||
|
def __init__(self, only_nif=False, *args, **kwargs):
|
||||||
|
self.only_nif = only_nif
|
||||||
|
self.nif_control = 'TRWAGMYFPDXBNJZSQVHLCKE'
|
||||||
|
self.cif_control = 'JABCDEFGHI'
|
||||||
|
self.cif_types = 'ABCDEFGHKLMNPQS'
|
||||||
|
self.nie_types = 'XT'
|
||||||
|
if self.only_nif:
|
||||||
|
self.id_types = 'NIF or NIE'
|
||||||
|
else:
|
||||||
|
self.id_types = 'NIF, NIE, or CIF'
|
||||||
|
super(ESIdentityCardNumberField, self).__init__(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types + self.cif_types.lower() + self.nie_types.lower(), self.nif_control + self.nif_control.lower()),
|
||||||
|
max_length=None, min_length=None,
|
||||||
|
error_message=_('Please enter a valid %s.' % self.id_types),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(ESIdentityCardNumberField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
nif_get_checksum = lambda d: self.nif_control[int(d)%23]
|
||||||
|
|
||||||
|
value = value.upper().replace(' ', '').replace('-', '')
|
||||||
|
m = re.match(r'^([%s]?)[ -]?(\d+)[ -]?([%s]?)$' % (self.cif_types + self.nie_types, self.nif_control), value)
|
||||||
|
letter1, number, letter2 = m.groups()
|
||||||
|
|
||||||
|
if not letter1 and letter2:
|
||||||
|
# NIF
|
||||||
|
if letter2 == nif_get_checksum(number):
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
raise ValidationError, _('Invalid checksum for NIF.')
|
||||||
|
elif letter1 in self.nie_types and letter2:
|
||||||
|
# NIE
|
||||||
|
if letter2 == nif_get_checksum(number):
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
raise ValidationError, _('Invalid checksum for NIE.')
|
||||||
|
elif not self.only_nif and letter1 in self.cif_types and len(number) in [7, 8]:
|
||||||
|
# CIF
|
||||||
|
if not letter2:
|
||||||
|
number, letter2 = number[:-1], int(number[-1])
|
||||||
|
checksum = cif_get_checksum(number)
|
||||||
|
if letter2 in [checksum, self.cif_control[checksum]]:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
raise ValidationError, _('Invalid checksum for CIF.')
|
||||||
|
else:
|
||||||
|
raise ValidationError, _('Please enter a valid %s.' % self.id_types)
|
||||||
|
|
||||||
|
class ESCCCField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validates its input as a Spanish bank account or CCC
|
||||||
|
(Codigo Cuenta Cliente).
|
||||||
|
|
||||||
|
Spanish CCC is in format EEEE-OOOO-CC-AAAAAAAAAA where:
|
||||||
|
|
||||||
|
E = entity
|
||||||
|
O = office
|
||||||
|
C = checksum
|
||||||
|
A = account
|
||||||
|
|
||||||
|
It's also valid to use a space as delimiter, or to use no delimiter.
|
||||||
|
|
||||||
|
First checksum digit validates entity and office, and last one
|
||||||
|
validates account. Validation is done multiplying every digit of 10
|
||||||
|
digit value (with leading 0 if necessary) by number in its position in
|
||||||
|
string 1, 2, 4, 8, 5, 10, 9, 7, 3, 6. Sum resulting numbers and extract
|
||||||
|
it from 11. Result is checksum except when 10 then is 1, or when 11
|
||||||
|
then is 0.
|
||||||
|
|
||||||
|
TODO: allow IBAN validation too
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ESCCCField, self).__init__(r'^\d{4}[ -]?\d{4}[ -]?\d{2}[ -]?\d{10}$',
|
||||||
|
max_length=None, min_length=None,
|
||||||
|
error_message=_('Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.'),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(ESCCCField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
control_str = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6]
|
||||||
|
m = re.match(r'^(\d{4})[ -]?(\d{4})[ -]?(\d{2})[ -]?(\d{10})$', value)
|
||||||
|
entity, office, checksum, account = m.groups()
|
||||||
|
get_checksum = lambda d: str(11 - sum([int(digit) * int(control) for digit, control in zip(d, control_str)]) % 11).replace('10', '1').replace('11', '0')
|
||||||
|
if get_checksum('00' + entity + office) + get_checksum(account) == checksum:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
raise ValidationError, _('Invalid checksum for bank account number.')
|
||||||
|
|
||||||
|
class ESRegionSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of spanish regions as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from es_regions import REGION_CHOICES
|
||||||
|
super(ESRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
|
||||||
|
|
||||||
|
class ESProvinceSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of spanish provinces as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from es_provinces import PROVINCE_CHOICES
|
||||||
|
super(ESProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
def cif_get_checksum(number):
|
||||||
|
s1 = sum([int(digit) for pos, digit in enumerate(number) if int(pos) % 2])
|
||||||
|
s2 = sum([sum([int(unit) for unit in str(int(digit) * 2)]) for pos, digit in enumerate(number) if not int(pos) % 2])
|
||||||
|
return 10 - ((s1 + s2) % 10)
|
||||||
|
|
@ -2,6 +2,8 @@
|
|||||||
Polish-specific form helpers
|
Polish-specific form helpers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from django.newforms import ValidationError
|
from django.newforms import ValidationError
|
||||||
from django.newforms.fields import Select, RegexField
|
from django.newforms.fields import Select, RegexField
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
@ -34,20 +36,6 @@ class PLNationalIdentificationNumberField(RegexField):
|
|||||||
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
|
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def has_valid_checksum(self, number):
|
|
||||||
"""
|
|
||||||
Calculates a checksum with the provided algorithm.
|
|
||||||
"""
|
|
||||||
multiple_table = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1)
|
|
||||||
result = 0
|
|
||||||
for i in range(len(number)):
|
|
||||||
result += int(number[i])*multiple_table[i]
|
|
||||||
|
|
||||||
if result % 10 == 0:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
|
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
|
||||||
max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
|
max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
|
||||||
@ -59,17 +47,95 @@ class PLNationalIdentificationNumberField(RegexField):
|
|||||||
raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
|
raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
|
||||||
return u'%s' % value
|
return u'%s' % value
|
||||||
|
|
||||||
|
def has_valid_checksum(self, number):
|
||||||
|
"""
|
||||||
|
Calculates a checksum with the provided algorithm.
|
||||||
|
"""
|
||||||
|
multiple_table = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1)
|
||||||
|
result = 0
|
||||||
|
for i in range(len(number)):
|
||||||
|
result += int(number[i]) * multiple_table[i]
|
||||||
|
return result % 10 == 0
|
||||||
|
|
||||||
class PLTaxNumberField(RegexField):
|
class PLTaxNumberField(RegexField):
|
||||||
"""
|
"""
|
||||||
A form field that validates as Polish Tax Number (NIP).
|
A form field that validates as Polish Tax Number (NIP).
|
||||||
Valid forms are: XXX-XXX-YY-YY or XX-XX-YYY-YYY.
|
Valid forms are: XXX-XXX-YY-YY or XX-XX-YYY-YYY.
|
||||||
|
|
||||||
|
Checksum algorithm based on documentation at
|
||||||
|
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
|
super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None,
|
||||||
error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
|
error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self,value):
|
||||||
|
super(PLTaxNumberField, self).clean(value)
|
||||||
|
value = re.sub("[-]", "", value)
|
||||||
|
if not self.has_valid_checksum(value):
|
||||||
|
raise ValidationError(_(u'Wrong checksum for the Tax Number (NIP).'))
|
||||||
|
return u'%s' % value
|
||||||
|
|
||||||
|
def has_valid_checksum(self, number):
|
||||||
|
"""
|
||||||
|
Calculates a checksum with the provided algorithm.
|
||||||
|
"""
|
||||||
|
multiple_table = (6, 5, 7, 2, 3, 4, 5, 6, 7)
|
||||||
|
result = 0
|
||||||
|
for i in range(len(number)-1):
|
||||||
|
result += int(number[i]) * multiple_table[i]
|
||||||
|
|
||||||
|
result %= 11
|
||||||
|
if result == int(number[-1]):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
class PLNationalBusinessRegisterField(RegexField):
|
||||||
|
"""
|
||||||
|
A form field that validated as Polish National Official Business Register Number (REGON)
|
||||||
|
Valid forms are: 7 or 9 digits number
|
||||||
|
|
||||||
|
More on the field: http://www.stat.gov.pl/bip/regon_ENG_HTML.htm
|
||||||
|
|
||||||
|
The checksum algorithm is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(PLNationalBusinessRegisterField, self).__init__(r'^\d{7,9}$',
|
||||||
|
max_length=None, min_length=None, error_message=_(u'National Business Register Number (REGON) consists of 7 or 9 digits.'),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self,value):
|
||||||
|
super(PLNationalBusinessRegisterField, self).clean(value)
|
||||||
|
if not self.has_valid_checksum(value):
|
||||||
|
raise ValidationError(_(u'Wrong checksum for the National Business Register Number (REGON).'))
|
||||||
|
return u'%s' % value
|
||||||
|
|
||||||
|
def has_valid_checksum(self, number):
|
||||||
|
"""
|
||||||
|
Calculates a checksum with the provided algorithm.
|
||||||
|
"""
|
||||||
|
multiple_table_7 = (2, 3, 4, 5, 6, 7)
|
||||||
|
multiple_table_9 = (8, 9, 2, 3, 4, 5, 6, 7)
|
||||||
|
result = 0
|
||||||
|
|
||||||
|
if len(number) == 7:
|
||||||
|
multiple_table = multiple_table_7
|
||||||
|
else:
|
||||||
|
multiple_table = multiple_table_9
|
||||||
|
|
||||||
|
for i in range(len(number)-1):
|
||||||
|
result += int(number[i]) * multiple_table[i]
|
||||||
|
|
||||||
|
result %= 11
|
||||||
|
if result == 10:
|
||||||
|
result = 0
|
||||||
|
if result == int(number[-1]):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
class PLPostalCodeField(RegexField):
|
class PLPostalCodeField(RegexField):
|
||||||
"""
|
"""
|
||||||
|
@ -48,6 +48,7 @@ class SessionBase(object):
|
|||||||
return self._session.get(key, default)
|
return self._session.get(key, default)
|
||||||
|
|
||||||
def pop(self, key, *args):
|
def pop(self, key, *args):
|
||||||
|
self.modified = self.modified or key in self._session
|
||||||
return self._session.pop(key, *args)
|
return self._session.pop(key, *args)
|
||||||
|
|
||||||
def set_test_cookie(self):
|
def set_test_cookie(self):
|
||||||
|
@ -39,8 +39,10 @@ class SessionMiddleware(object):
|
|||||||
|
|
||||||
# Save the seesion data and refresh the client cookie.
|
# Save the seesion data and refresh the client cookie.
|
||||||
request.session.save()
|
request.session.save()
|
||||||
response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key,
|
response.set_cookie(settings.SESSION_COOKIE_NAME,
|
||||||
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
|
request.session.session_key, max_age=max_age,
|
||||||
|
expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
|
||||||
|
path=settings.SESSION_COOKIE_PATH,
|
||||||
secure=settings.SESSION_COOKIE_SECURE or None)
|
secure=settings.SESSION_COOKIE_SECURE or None)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -3,6 +3,7 @@ r"""
|
|||||||
>>> from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
|
>>> from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
|
||||||
>>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession
|
>>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession
|
||||||
>>> from django.contrib.sessions.backends.file import SessionStore as FileSession
|
>>> from django.contrib.sessions.backends.file import SessionStore as FileSession
|
||||||
|
>>> from django.contrib.sessions.backends.base import SessionBase
|
||||||
|
|
||||||
>>> db_session = DatabaseSession()
|
>>> db_session = DatabaseSession()
|
||||||
>>> db_session.modified
|
>>> db_session.modified
|
||||||
@ -52,6 +53,28 @@ True
|
|||||||
>>> cache_session.delete(cache_session.session_key)
|
>>> cache_session.delete(cache_session.session_key)
|
||||||
>>> cache_session.exists(cache_session.session_key)
|
>>> cache_session.exists(cache_session.session_key)
|
||||||
False
|
False
|
||||||
|
|
||||||
|
>>> s = SessionBase()
|
||||||
|
>>> s._session['some key'] = 'exists' # Pre-populate the session with some data
|
||||||
|
>>> s.accessed = False # Reset to pretend this wasn't accessed previously
|
||||||
|
|
||||||
|
>>> s.accessed, s.modified
|
||||||
|
(False, False)
|
||||||
|
|
||||||
|
>>> s.pop('non existant key', 'does not exist')
|
||||||
|
'does not exist'
|
||||||
|
>>> s.accessed, s.modified
|
||||||
|
(True, False)
|
||||||
|
|
||||||
|
>>> s.accessed = False # Reset the accessed flag
|
||||||
|
|
||||||
|
>>> s.pop('some key')
|
||||||
|
'exists'
|
||||||
|
>>> s.accessed, s.modified
|
||||||
|
(True, True)
|
||||||
|
|
||||||
|
>>> s.pop('some key', 'does not exist')
|
||||||
|
'does not exist'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -89,6 +89,7 @@ class Feed(object):
|
|||||||
categories = self.__get_dynamic_attr('categories', obj),
|
categories = self.__get_dynamic_attr('categories', obj),
|
||||||
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
||||||
feed_guid = self.__get_dynamic_attr('feed_guid', obj),
|
feed_guid = self.__get_dynamic_attr('feed_guid', obj),
|
||||||
|
ttl = self.__get_dynamic_attr('ttl', obj),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
8
django/core/cache/backends/base.py
vendored
8
django/core/cache/backends/base.py
vendored
@ -14,6 +14,14 @@ class BaseCache(object):
|
|||||||
timeout = 300
|
timeout = 300
|
||||||
self.default_timeout = timeout
|
self.default_timeout = timeout
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=None):
|
||||||
|
"""
|
||||||
|
Set a value in the cache if the key does not already exist. If
|
||||||
|
timeout is given, that timeout will be used for the key; otherwise
|
||||||
|
the default cache timeout will be used.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
"""
|
"""
|
||||||
Fetch a given key from the cache. If the key does not exist, return
|
Fetch a given key from the cache. If the key does not exist, return
|
||||||
|
8
django/core/cache/backends/db.py
vendored
8
django/core/cache/backends/db.py
vendored
@ -38,6 +38,12 @@ class CacheClass(BaseCache):
|
|||||||
return pickle.loads(base64.decodestring(row[1]))
|
return pickle.loads(base64.decodestring(row[1]))
|
||||||
|
|
||||||
def set(self, key, value, timeout=None):
|
def set(self, key, value, timeout=None):
|
||||||
|
return self._base_set('set', key, value, timeout)
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=None):
|
||||||
|
return self._base_set('add', key, value, timeout)
|
||||||
|
|
||||||
|
def _base_set(self, mode, key, value, timeout=None):
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
timeout = self.default_timeout
|
timeout = self.default_timeout
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
@ -50,7 +56,7 @@ class CacheClass(BaseCache):
|
|||||||
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
|
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
|
||||||
cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
|
cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
|
||||||
try:
|
try:
|
||||||
if cursor.fetchone():
|
if mode == 'set' and cursor.fetchone():
|
||||||
cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key])
|
cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key])
|
||||||
else:
|
else:
|
||||||
cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)])
|
cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)])
|
||||||
|
3
django/core/cache/backends/dummy.py
vendored
3
django/core/cache/backends/dummy.py
vendored
@ -6,6 +6,9 @@ class CacheClass(BaseCache):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def add(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
20
django/core/cache/backends/filebased.py
vendored
20
django/core/cache/backends/filebased.py
vendored
@ -17,6 +17,26 @@ class CacheClass(SimpleCacheClass):
|
|||||||
del self._cache
|
del self._cache
|
||||||
del self._expire_info
|
del self._expire_info
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=None):
|
||||||
|
fname = self._key_to_file(key)
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.default_timeout
|
||||||
|
try:
|
||||||
|
filelist = os.listdir(self._dir)
|
||||||
|
except (IOError, OSError):
|
||||||
|
self._createdir()
|
||||||
|
filelist = []
|
||||||
|
if len(filelist) > self._max_entries:
|
||||||
|
self._cull(filelist)
|
||||||
|
if os.path.basename(fname) not in filelist:
|
||||||
|
try:
|
||||||
|
f = open(fname, 'wb')
|
||||||
|
now = time.time()
|
||||||
|
pickle.dump(now + timeout, f, 2)
|
||||||
|
pickle.dump(value, f, 2)
|
||||||
|
except (IOError, OSError):
|
||||||
|
pass
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
fname = self._key_to_file(key)
|
fname = self._key_to_file(key)
|
||||||
try:
|
try:
|
||||||
|
7
django/core/cache/backends/locmem.py
vendored
7
django/core/cache/backends/locmem.py
vendored
@ -14,6 +14,13 @@ class CacheClass(SimpleCacheClass):
|
|||||||
SimpleCacheClass.__init__(self, host, params)
|
SimpleCacheClass.__init__(self, host, params)
|
||||||
self._lock = RWLock()
|
self._lock = RWLock()
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=None):
|
||||||
|
self._lock.writer_enters()
|
||||||
|
try:
|
||||||
|
SimpleCacheClass.add(self, key, value, timeout)
|
||||||
|
finally:
|
||||||
|
self._lock.writer_leaves()
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
should_delete = False
|
should_delete = False
|
||||||
self._lock.reader_enters()
|
self._lock.reader_enters()
|
||||||
|
3
django/core/cache/backends/memcached.py
vendored
3
django/core/cache/backends/memcached.py
vendored
@ -16,6 +16,9 @@ class CacheClass(BaseCache):
|
|||||||
BaseCache.__init__(self, params)
|
BaseCache.__init__(self, params)
|
||||||
self._cache = memcache.Client(server.split(';'))
|
self._cache = memcache.Client(server.split(';'))
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=0):
|
||||||
|
self._cache.add(key.encode('ascii', 'ignore'), value, timeout or self.default_timeout)
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
val = self._cache.get(smart_str(key))
|
val = self._cache.get(smart_str(key))
|
||||||
if val is None:
|
if val is None:
|
||||||
|
9
django/core/cache/backends/simple.py
vendored
9
django/core/cache/backends/simple.py
vendored
@ -21,6 +21,15 @@ class CacheClass(BaseCache):
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
self._cull_frequency = 3
|
self._cull_frequency = 3
|
||||||
|
|
||||||
|
def add(self, key, value, timeout=None):
|
||||||
|
if len(self._cache) >= self._max_entries:
|
||||||
|
self._cull()
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.default_timeout
|
||||||
|
if key not in self._cache.keys():
|
||||||
|
self._cache[key] = value
|
||||||
|
self._expire_info[key] = time.time() + timeout
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
exp = self._expire_info.get(key)
|
exp = self._expire_info.get(key)
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
class ModPythonRequest(http.HttpRequest):
|
class ModPythonRequest(http.HttpRequest):
|
||||||
def __init__(self, req):
|
def __init__(self, req):
|
||||||
self._req = req
|
self._req = req
|
||||||
self.path = force_unicode(req.uri, errors='ignore')
|
self.path = force_unicode(req.uri)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# Since this is called as part of error handling, we need to be very
|
# Since this is called as part of error handling, we need to be very
|
||||||
@ -136,6 +136,8 @@ class ModPythonRequest(http.HttpRequest):
|
|||||||
method = property(_get_method)
|
method = property(_get_method)
|
||||||
|
|
||||||
class ModPythonHandler(BaseHandler):
|
class ModPythonHandler(BaseHandler):
|
||||||
|
request_class = ModPythonRequest
|
||||||
|
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
# mod_python fakes the environ, and thus doesn't process SetEnv. This fixes that
|
# mod_python fakes the environ, and thus doesn't process SetEnv. This fixes that
|
||||||
os.environ.update(req.subprocess_env)
|
os.environ.update(req.subprocess_env)
|
||||||
@ -150,13 +152,16 @@ class ModPythonHandler(BaseHandler):
|
|||||||
|
|
||||||
dispatcher.send(signal=signals.request_started)
|
dispatcher.send(signal=signals.request_started)
|
||||||
try:
|
try:
|
||||||
request = ModPythonRequest(req)
|
try:
|
||||||
|
request = self.request_class(req)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
response = http.HttpResponseBadRequest()
|
||||||
|
else:
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
|
||||||
# Apply response middleware
|
# Apply response middleware
|
||||||
for middleware_method in self._response_middleware:
|
for middleware_method in self._response_middleware:
|
||||||
response = middleware_method(request, response)
|
response = middleware_method(request, response)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
dispatcher.send(signal=signals.request_finished)
|
dispatcher.send(signal=signals.request_finished)
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
|
|||||||
class WSGIRequest(http.HttpRequest):
|
class WSGIRequest(http.HttpRequest):
|
||||||
def __init__(self, environ):
|
def __init__(self, environ):
|
||||||
self.environ = environ
|
self.environ = environ
|
||||||
self.path = force_unicode(environ['PATH_INFO'], errors='ignore')
|
self.path = force_unicode(environ['PATH_INFO'])
|
||||||
self.META = environ
|
self.META = environ
|
||||||
self.method = environ['REQUEST_METHOD'].upper()
|
self.method = environ['REQUEST_METHOD'].upper()
|
||||||
|
|
||||||
@ -165,7 +165,9 @@ class WSGIRequest(http.HttpRequest):
|
|||||||
content_length = int(self.environ.get('CONTENT_LENGTH', 0))
|
content_length = int(self.environ.get('CONTENT_LENGTH', 0))
|
||||||
except ValueError: # if CONTENT_LENGTH was empty string or not an integer
|
except ValueError: # if CONTENT_LENGTH was empty string or not an integer
|
||||||
content_length = 0
|
content_length = 0
|
||||||
safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length)
|
if content_length > 0:
|
||||||
|
safe_copyfileobj(self.environ['wsgi.input'], buf,
|
||||||
|
size=content_length)
|
||||||
self._raw_post_data = buf.getvalue()
|
self._raw_post_data = buf.getvalue()
|
||||||
buf.close()
|
buf.close()
|
||||||
return self._raw_post_data
|
return self._raw_post_data
|
||||||
@ -179,6 +181,7 @@ class WSGIRequest(http.HttpRequest):
|
|||||||
|
|
||||||
class WSGIHandler(BaseHandler):
|
class WSGIHandler(BaseHandler):
|
||||||
initLock = Lock()
|
initLock = Lock()
|
||||||
|
request_class = WSGIRequest
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -194,13 +197,16 @@ class WSGIHandler(BaseHandler):
|
|||||||
|
|
||||||
dispatcher.send(signal=signals.request_started)
|
dispatcher.send(signal=signals.request_started)
|
||||||
try:
|
try:
|
||||||
request = WSGIRequest(environ)
|
try:
|
||||||
|
request = self.request_class(environ)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
response = http.HttpResponseBadRequest()
|
||||||
|
else:
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
|
||||||
# Apply response middleware
|
# Apply response middleware
|
||||||
for middleware_method in self._response_middleware:
|
for middleware_method in self._response_middleware:
|
||||||
response = middleware_method(request, response)
|
response = middleware_method(request, response)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
dispatcher.send(signal=signals.request_finished)
|
dispatcher.send(signal=signals.request_finished)
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ class SafeMIMEText(MIMEText):
|
|||||||
if '\n' in val or '\r' in val:
|
if '\n' in val or '\r' in val:
|
||||||
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
||||||
try:
|
try:
|
||||||
val = str(force_unicode(val))
|
val = force_unicode(val).encode('ascii')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
if name.lower() in ('to', 'from', 'cc'):
|
if name.lower() in ('to', 'from', 'cc'):
|
||||||
result = []
|
result = []
|
||||||
@ -92,7 +92,7 @@ class SafeMIMEMultipart(MIMEMultipart):
|
|||||||
if '\n' in val or '\r' in val:
|
if '\n' in val or '\r' in val:
|
||||||
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
||||||
try:
|
try:
|
||||||
val = str(force_unicode(val))
|
val = force_unicode(val).encode('ascii')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
if name.lower() in ('to', 'from', 'cc'):
|
if name.lower() in ('to', 'from', 'cc'):
|
||||||
result = []
|
result = []
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import django
|
|
||||||
from django.core.management.base import BaseCommand, CommandError, handle_default_options
|
|
||||||
from optparse import OptionParser
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from optparse import OptionParser
|
||||||
from imp import find_module
|
from imp import find_module
|
||||||
|
|
||||||
|
import django
|
||||||
|
from django.core.management.base import BaseCommand, CommandError, handle_default_options
|
||||||
|
|
||||||
# For backwards compatibility: get_version() used to be in this module.
|
# For backwards compatibility: get_version() used to be in this module.
|
||||||
get_version = django.get_version
|
get_version = django.get_version
|
||||||
|
|
||||||
@ -14,18 +15,21 @@ _commands = None
|
|||||||
|
|
||||||
def find_commands(management_dir):
|
def find_commands(management_dir):
|
||||||
"""
|
"""
|
||||||
Given a path to a management directory, return a list of all the command names
|
Given a path to a management directory, returns a list of all the command
|
||||||
that are available. Returns an empty list if no commands are defined.
|
names that are available.
|
||||||
|
|
||||||
|
Returns an empty list if no commands are defined.
|
||||||
"""
|
"""
|
||||||
command_dir = os.path.join(management_dir, 'commands')
|
command_dir = os.path.join(management_dir, 'commands')
|
||||||
try:
|
try:
|
||||||
return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
|
return [f[:-3] for f in os.listdir(command_dir)
|
||||||
|
if not f.startswith('_') and f.endswith('.py')]
|
||||||
except OSError:
|
except OSError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def find_management_module(app_name):
|
def find_management_module(app_name):
|
||||||
"""
|
"""
|
||||||
Determine the path to the management module for the application named,
|
Determines the path to the management module for the application named,
|
||||||
without acutally importing the application or the management module.
|
without acutally importing the application or the management module.
|
||||||
|
|
||||||
Raises ImportError if the management module cannot be found for any reason.
|
Raises ImportError if the management module cannot be found for any reason.
|
||||||
@ -77,7 +81,7 @@ def get_commands(load_user_commands=True, project_directory=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:
|
if load_user_commands:
|
||||||
# Get commands from all installed apps
|
# Get commands from all installed apps.
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
for app_name in settings.INSTALLED_APPS:
|
for app_name in settings.INSTALLED_APPS:
|
||||||
try:
|
try:
|
||||||
@ -150,10 +154,13 @@ class ManagementUtility(object):
|
|||||||
Returns the script's main help text, as a string.
|
Returns the script's main help text, as a string.
|
||||||
"""
|
"""
|
||||||
usage = ['%s <subcommand> [options] [args]' % self.prog_name]
|
usage = ['%s <subcommand> [options] [args]' % self.prog_name]
|
||||||
usage.append('Django command line tool, version %s' % django.get_version())
|
usage.append('Django command line tool,'
|
||||||
usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name)
|
' version %s' % django.get_version())
|
||||||
|
usage.append("Type '%s help <subcommand>' for help on a specific"
|
||||||
|
" subcommand." % self.prog_name)
|
||||||
usage.append('Available subcommands:')
|
usage.append('Available subcommands:')
|
||||||
commands = get_commands(self.user_commands, self.project_directory).keys()
|
commands = get_commands(self.user_commands,
|
||||||
|
self.project_directory).keys()
|
||||||
commands.sort()
|
commands.sort()
|
||||||
for cmd in commands:
|
for cmd in commands:
|
||||||
usage.append(' %s' % cmd)
|
usage.append(' %s' % cmd)
|
||||||
@ -166,14 +173,16 @@ 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, self.project_directory)[subcommand]
|
app_name = get_commands(self.user_commands,
|
||||||
|
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
|
||||||
else:
|
else:
|
||||||
klass = load_command_class(app_name, subcommand)
|
klass = load_command_class(app_name, subcommand)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name))
|
sys.stderr.write("Unknown command: %r\nType '%s help' for"
|
||||||
|
" usage.\n" % (subcommand, self.prog_name))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return klass
|
return klass
|
||||||
|
|
||||||
@ -182,9 +191,9 @@ class ManagementUtility(object):
|
|||||||
Given the command-line arguments, this figures out which subcommand is
|
Given the command-line arguments, this figures out which subcommand is
|
||||||
being run, creates a parser appropriate to that command, and runs it.
|
being run, creates a parser appropriate to that command, and runs it.
|
||||||
"""
|
"""
|
||||||
# Preprocess options to extract --settings and --pythonpath. These options
|
# Preprocess options to extract --settings and --pythonpath.
|
||||||
# could affect the commands that are available, so they must be processed
|
# These options could affect the commands that are available, so they
|
||||||
# early
|
# must be processed early.
|
||||||
parser = LaxOptionParser(version=get_version(),
|
parser = LaxOptionParser(version=get_version(),
|
||||||
option_list=BaseCommand.option_list)
|
option_list=BaseCommand.option_list)
|
||||||
try:
|
try:
|
||||||
@ -208,7 +217,8 @@ class ManagementUtility(object):
|
|||||||
# Special-cases: We want 'django-admin.py --version' and
|
# Special-cases: We want 'django-admin.py --version' and
|
||||||
# 'django-admin.py --help' to work, for backwards compatibility.
|
# 'django-admin.py --help' to work, for backwards compatibility.
|
||||||
elif self.argv[1:] == ['--version']:
|
elif self.argv[1:] == ['--version']:
|
||||||
print django.get_version()
|
# LaxOptionParser already takes care of printing the version.
|
||||||
|
pass
|
||||||
elif self.argv[1:] == ['--help']:
|
elif self.argv[1:] == ['--help']:
|
||||||
sys.stderr.write(self.main_help_text() + '\n')
|
sys.stderr.write(self.main_help_text() + '\n')
|
||||||
else:
|
else:
|
||||||
@ -230,7 +240,7 @@ class ProjectManagementUtility(ManagementUtility):
|
|||||||
|
|
||||||
def setup_environ(settings_mod):
|
def setup_environ(settings_mod):
|
||||||
"""
|
"""
|
||||||
Configure the runtime environment. This can also be used by external
|
Configures the runtime environment. This can also be used by external
|
||||||
scripts wanting to set up a similar environment to manage.py.
|
scripts wanting to set up a similar environment to manage.py.
|
||||||
"""
|
"""
|
||||||
# Add this project to sys.path so that it's importable in the conventional
|
# Add this project to sys.path so that it's importable in the conventional
|
||||||
@ -244,7 +254,8 @@ def setup_environ(settings_mod):
|
|||||||
sys.path.pop()
|
sys.path.pop()
|
||||||
|
|
||||||
# Set DJANGO_SETTINGS_MODULE appropriately.
|
# Set DJANGO_SETTINGS_MODULE appropriately.
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
|
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name,
|
||||||
|
settings_name)
|
||||||
return project_directory
|
return project_directory
|
||||||
|
|
||||||
def execute_from_command_line(argv=None):
|
def execute_from_command_line(argv=None):
|
||||||
|
@ -35,6 +35,8 @@ def get_validation_errors(outfile, app=None):
|
|||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||||
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
|
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
|
||||||
|
if f.name.endswith('_'):
|
||||||
|
e.add(opts, '"%s": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.' % f.name)
|
||||||
if isinstance(f, models.CharField) and f.max_length in (None, 0):
|
if isinstance(f, models.CharField) and f.max_length in (None, 0):
|
||||||
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
||||||
if isinstance(f, models.DecimalField):
|
if isinstance(f, models.DecimalField):
|
||||||
|
@ -249,8 +249,9 @@ class RegexURLResolver(object):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
try:
|
try:
|
||||||
self._urlconf_module = __import__(self.urlconf_name, {}, {}, [''])
|
self._urlconf_module = __import__(self.urlconf_name, {}, {}, [''])
|
||||||
except ValueError, e:
|
except Exception, e:
|
||||||
# Invalid urlconf_name, such as "foo.bar." (note trailing period)
|
# Either an invalid urlconf_name, such as "foo.bar.", or some
|
||||||
|
# kind of problem during the actual import.
|
||||||
raise ImproperlyConfigured, "Error while importing URLconf %r: %s" % (self.urlconf_name, e)
|
raise ImproperlyConfigured, "Error while importing URLconf %r: %s" % (self.urlconf_name, e)
|
||||||
return self._urlconf_module
|
return self._urlconf_module
|
||||||
urlconf_module = property(_get_urlconf_module)
|
urlconf_module = property(_get_urlconf_module)
|
||||||
|
@ -127,6 +127,27 @@ class BaseDatabaseOperations(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError('Full-text search is not implemented for this database backend')
|
raise NotImplementedError('Full-text search is not implemented for this database backend')
|
||||||
|
|
||||||
|
def last_executed_query(self, cursor, sql, params):
|
||||||
|
"""
|
||||||
|
Returns a string of the query last executed by the given cursor, with
|
||||||
|
placeholders replaced with actual values.
|
||||||
|
|
||||||
|
`sql` is the raw query containing placeholders, and `params` is the
|
||||||
|
sequence of parameters. These are used by default, but this method
|
||||||
|
exists for database backends to provide a better implementation
|
||||||
|
according to their own quoting schemes.
|
||||||
|
"""
|
||||||
|
from django.utils.encoding import smart_unicode, force_unicode
|
||||||
|
|
||||||
|
# Convert params to contain Unicode values.
|
||||||
|
to_unicode = lambda s: force_unicode(s, strings_only=True)
|
||||||
|
if isinstance(params, (list, tuple)):
|
||||||
|
u_params = tuple([to_unicode(val) for val in params])
|
||||||
|
else:
|
||||||
|
u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
|
||||||
|
|
||||||
|
return smart_unicode(sql) % u_params
|
||||||
|
|
||||||
def last_insert_id(self, cursor, table_name, pk_name):
|
def last_insert_id(self, cursor, table_name, pk_name):
|
||||||
"""
|
"""
|
||||||
Given a cursor object that has just performed an INSERT statement into
|
Given a cursor object that has just performed an INSERT statement into
|
||||||
|
@ -5,7 +5,7 @@ Requires psycopg 2: http://initd.org/projects/psycopg2
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures
|
from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures
|
||||||
from django.db.backends.postgresql.operations import DatabaseOperations
|
from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
|
||||||
try:
|
try:
|
||||||
import psycopg2 as Database
|
import psycopg2 as Database
|
||||||
import psycopg2.extensions
|
import psycopg2.extensions
|
||||||
@ -21,6 +21,13 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
|||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
needs_datetime_string_cast = False
|
needs_datetime_string_cast = False
|
||||||
|
|
||||||
|
class DatabaseOperations(PostgresqlDatabaseOperations):
|
||||||
|
def last_executed_query(self, cursor, sql, params):
|
||||||
|
# With psycopg2, cursor objects have a "query" attribute that is the
|
||||||
|
# exact query sent to the database. See docs here:
|
||||||
|
# http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query
|
||||||
|
return cursor.query
|
||||||
|
|
||||||
class DatabaseWrapper(BaseDatabaseWrapper):
|
class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
features = DatabaseFeatures()
|
features = DatabaseFeatures()
|
||||||
ops = DatabaseOperations()
|
ops = DatabaseOperations()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import md5
|
import md5
|
||||||
from time import time
|
from time import time
|
||||||
from django.utils.encoding import smart_unicode, force_unicode
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import decimal
|
import decimal
|
||||||
@ -11,7 +10,7 @@ except ImportError:
|
|||||||
class CursorDebugWrapper(object):
|
class CursorDebugWrapper(object):
|
||||||
def __init__(self, cursor, db):
|
def __init__(self, cursor, db):
|
||||||
self.cursor = cursor
|
self.cursor = cursor
|
||||||
self.db = db
|
self.db = db # Instance of a BaseDatabaseWrapper subclass
|
||||||
|
|
||||||
def execute(self, sql, params=()):
|
def execute(self, sql, params=()):
|
||||||
start = time()
|
start = time()
|
||||||
@ -19,8 +18,9 @@ class CursorDebugWrapper(object):
|
|||||||
return self.cursor.execute(sql, params)
|
return self.cursor.execute(sql, params)
|
||||||
finally:
|
finally:
|
||||||
stop = time()
|
stop = time()
|
||||||
|
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
|
||||||
self.db.queries.append({
|
self.db.queries.append({
|
||||||
'sql': smart_unicode(sql) % convert_args(params),
|
'sql': sql,
|
||||||
'time': "%.3f" % (stop - start),
|
'time': "%.3f" % (stop - start),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ class CursorDebugWrapper(object):
|
|||||||
finally:
|
finally:
|
||||||
stop = time()
|
stop = time()
|
||||||
self.db.queries.append({
|
self.db.queries.append({
|
||||||
'sql': 'MANY: ' + sql + ' ' + smart_unicode(tuple(param_list)),
|
'sql': '%s times: %s' % (len(param_list), sql),
|
||||||
'time': "%.3f" % (stop - start),
|
'time': "%.3f" % (stop - start),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -41,16 +41,6 @@ class CursorDebugWrapper(object):
|
|||||||
else:
|
else:
|
||||||
return getattr(self.cursor, attr)
|
return getattr(self.cursor, attr)
|
||||||
|
|
||||||
def convert_args(args):
|
|
||||||
"""
|
|
||||||
Convert sequence or dictionary to contain unicode values.
|
|
||||||
"""
|
|
||||||
to_unicode = lambda s: force_unicode(s, strings_only=True)
|
|
||||||
if isinstance(args, (list, tuple)):
|
|
||||||
return tuple([to_unicode(val) for val in args])
|
|
||||||
else:
|
|
||||||
return dict([(to_unicode(k), to_unicode(v)) for k, v in args.items()])
|
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# Converters from database (string) to Python #
|
# Converters from database (string) to Python #
|
||||||
###############################################
|
###############################################
|
||||||
|
@ -395,6 +395,8 @@ class Field(object):
|
|||||||
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
|
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
|
||||||
if self.choices:
|
if self.choices:
|
||||||
defaults['widget'] = forms.Select(choices=self.get_choices())
|
defaults['widget'] = forms.Select(choices=self.get_choices())
|
||||||
|
if self.has_default():
|
||||||
|
defaults['initial'] = self.get_default()
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return form_class(**defaults)
|
return form_class(**defaults)
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Refactored "safe reference" from dispatcher.py"""
|
"""Refactored "safe reference" from dispatcher.py"""
|
||||||
import weakref, traceback
|
import weakref, traceback
|
||||||
|
from django.utils.functional import curry
|
||||||
|
|
||||||
def safeRef(target, onDelete = None):
|
def safeRef(target, onDelete = None):
|
||||||
"""Return a *safe* weak reference to a callable target
|
"""Return a *safe* weak reference to a callable target
|
||||||
@ -17,7 +18,7 @@ def safeRef(target, onDelete = None):
|
|||||||
# Turn a bound method into a BoundMethodWeakref instance.
|
# Turn a bound method into a BoundMethodWeakref instance.
|
||||||
# Keep track of these instances for lookup by disconnect().
|
# Keep track of these instances for lookup by disconnect().
|
||||||
assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,)
|
assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,)
|
||||||
reference = BoundMethodWeakref(
|
reference = get_bound_method_weakref(
|
||||||
target=target,
|
target=target,
|
||||||
onDelete=onDelete
|
onDelete=onDelete
|
||||||
)
|
)
|
||||||
@ -163,3 +164,75 @@ class BoundMethodWeakref(object):
|
|||||||
if function is not None:
|
if function is not None:
|
||||||
return function.__get__(target)
|
return function.__get__(target)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
|
||||||
|
"""A specialized BoundMethodWeakref, for platforms where instance methods
|
||||||
|
are not descriptors.
|
||||||
|
|
||||||
|
It assumes that the function name and the target attribute name are the
|
||||||
|
same, instead of assuming that the function is a descriptor. This approach
|
||||||
|
is equally fast, but not 100% reliable because functions can be stored on an
|
||||||
|
attribute named differenty than the function's name such as in:
|
||||||
|
|
||||||
|
class A: pass
|
||||||
|
def foo(self): return "foo"
|
||||||
|
A.bar = foo
|
||||||
|
|
||||||
|
But this shouldn't be a common use case. So, on platforms where methods
|
||||||
|
aren't descriptors (such as Jython) this implementation has the advantage
|
||||||
|
of working in the most cases.
|
||||||
|
"""
|
||||||
|
def __init__(self, target, onDelete=None):
|
||||||
|
"""Return a weak-reference-like instance for a bound method
|
||||||
|
|
||||||
|
target -- the instance-method target for the weak
|
||||||
|
reference, must have im_self and im_func attributes
|
||||||
|
and be reconstructable via:
|
||||||
|
target.im_func.__get__( target.im_self )
|
||||||
|
which is true of built-in instance methods.
|
||||||
|
onDelete -- optional callback which will be called
|
||||||
|
when this weak reference ceases to be valid
|
||||||
|
(i.e. either the object or the function is garbage
|
||||||
|
collected). Should take a single argument,
|
||||||
|
which will be passed a pointer to this object.
|
||||||
|
"""
|
||||||
|
assert getattr(target.im_self, target.__name__) == target, \
|
||||||
|
("method %s isn't available as the attribute %s of %s" %
|
||||||
|
(target, target.__name__, target.im_self))
|
||||||
|
super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
"""Return a strong reference to the bound method
|
||||||
|
|
||||||
|
If the target cannot be retrieved, then will
|
||||||
|
return None, otherwise returns a bound instance
|
||||||
|
method for our object and function.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
You may call this method any number of times,
|
||||||
|
as it does not invalidate the reference.
|
||||||
|
"""
|
||||||
|
target = self.weakSelf()
|
||||||
|
if target is not None:
|
||||||
|
function = self.weakFunc()
|
||||||
|
if function is not None:
|
||||||
|
# Using curry() would be another option, but it erases the
|
||||||
|
# "signature" of the function. That is, after a function is
|
||||||
|
# curried, the inspect module can't be used to determine how
|
||||||
|
# many arguments the function expects, nor what keyword
|
||||||
|
# arguments it supports, and pydispatcher needs this
|
||||||
|
# information.
|
||||||
|
return getattr(target, function.__name__)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_bound_method_weakref(target, onDelete):
|
||||||
|
"""Instantiates the appropiate BoundMethodWeakRef, depending on the details of
|
||||||
|
the underlying class method implementation"""
|
||||||
|
if hasattr(target, '__get__'):
|
||||||
|
# target method is a descriptor, so the default implementation works:
|
||||||
|
return BoundMethodWeakref(target=target, onDelete=onDelete)
|
||||||
|
else:
|
||||||
|
# no luck, use the alternative implementation:
|
||||||
|
return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)
|
||||||
|
|
||||||
|
@ -261,19 +261,23 @@ class HttpResponse(object):
|
|||||||
else:
|
else:
|
||||||
self._container = [content]
|
self._container = [content]
|
||||||
self._is_string = True
|
self._is_string = True
|
||||||
self._headers = {'content-type': content_type}
|
|
||||||
self.cookies = SimpleCookie()
|
self.cookies = SimpleCookie()
|
||||||
if status:
|
if status:
|
||||||
self.status_code = status
|
self.status_code = status
|
||||||
|
|
||||||
|
# _headers is a mapping of the lower-case name to the original case of
|
||||||
|
# the header (required for working with legacy systems) and the header
|
||||||
|
# value.
|
||||||
|
self._headers = {'content-type': ('Content-Type', content_type)}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"Full HTTP message, including headers"
|
"Full HTTP message, including headers"
|
||||||
return '\n'.join(['%s: %s' % (key, value)
|
return '\n'.join(['%s: %s' % (key, value)
|
||||||
for key, value in self._headers.items()]) \
|
for key, value in self._headers.values()]) \
|
||||||
+ '\n\n' + self.content
|
+ '\n\n' + self.content
|
||||||
|
|
||||||
def __setitem__(self, header, value):
|
def __setitem__(self, header, value):
|
||||||
self._headers[header.lower()] = value
|
self._headers[header.lower()] = (header, value)
|
||||||
|
|
||||||
def __delitem__(self, header):
|
def __delitem__(self, header):
|
||||||
try:
|
try:
|
||||||
@ -282,7 +286,7 @@ class HttpResponse(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def __getitem__(self, header):
|
def __getitem__(self, header):
|
||||||
return self._headers[header.lower()]
|
return self._headers[header.lower()][1]
|
||||||
|
|
||||||
def has_header(self, header):
|
def has_header(self, header):
|
||||||
"Case-insensitive check for a header"
|
"Case-insensitive check for a header"
|
||||||
@ -291,10 +295,10 @@ class HttpResponse(object):
|
|||||||
__contains__ = has_header
|
__contains__ = has_header
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return self._headers.items()
|
return self._headers.values()
|
||||||
|
|
||||||
def get(self, header, alternate):
|
def get(self, header, alternate):
|
||||||
return self._headers.get(header, alternate)
|
return self._headers.get(header.lower(), (None, alternate))[1]
|
||||||
|
|
||||||
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None):
|
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None):
|
||||||
self.cookies[key] = value
|
self.cookies[key] = value
|
||||||
@ -304,17 +308,13 @@ class HttpResponse(object):
|
|||||||
self.cookies[key][var.replace('_', '-')] = val
|
self.cookies[key][var.replace('_', '-')] = val
|
||||||
|
|
||||||
def delete_cookie(self, key, path='/', domain=None):
|
def delete_cookie(self, key, path='/', domain=None):
|
||||||
self.cookies[key] = ''
|
self.set_cookie(key, max_age=0, path=path, domain=domain,
|
||||||
if path is not None:
|
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
||||||
self.cookies[key]['path'] = path
|
|
||||||
if domain is not None:
|
|
||||||
self.cookies[key]['domain'] = domain
|
|
||||||
self.cookies[key]['expires'] = 0
|
|
||||||
self.cookies[key]['max-age'] = 0
|
|
||||||
|
|
||||||
def _get_content(self):
|
def _get_content(self):
|
||||||
content = smart_str(''.join(self._container), self._charset)
|
if self.has_header('Content-Encoding'):
|
||||||
return content
|
return ''.join(self._container)
|
||||||
|
return smart_str(''.join(self._container), self._charset)
|
||||||
|
|
||||||
def _set_content(self, value):
|
def _set_content(self, value):
|
||||||
self._container = [value]
|
self._container = [value]
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import md5
|
||||||
|
import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django import http
|
from django import http
|
||||||
from django.core.mail import mail_managers
|
from django.core.mail import mail_managers
|
||||||
import md5
|
from django.utils.http import urlquote
|
||||||
import re
|
|
||||||
|
|
||||||
class CommonMiddleware(object):
|
class CommonMiddleware(object):
|
||||||
"""
|
"""
|
||||||
@ -46,9 +48,9 @@ class CommonMiddleware(object):
|
|||||||
if new_url != old_url:
|
if new_url != old_url:
|
||||||
# Redirect
|
# Redirect
|
||||||
if new_url[0]:
|
if new_url[0]:
|
||||||
newurl = "%s://%s%s" % (request.is_secure() and 'https' or 'http', new_url[0], new_url[1])
|
newurl = "%s://%s%s" % (request.is_secure() and 'https' or 'http', new_url[0], urlquote(new_url[1]))
|
||||||
else:
|
else:
|
||||||
newurl = new_url[1]
|
newurl = urlquote(new_url[1])
|
||||||
if request.GET:
|
if request.GET:
|
||||||
newurl += '?' + request.GET.urlencode()
|
newurl += '?' + request.GET.urlencode()
|
||||||
return http.HttpResponsePermanentRedirect(newurl)
|
return http.HttpResponsePermanentRedirect(newurl)
|
||||||
|
@ -19,8 +19,9 @@ class GZipMiddleware(object):
|
|||||||
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 or if the
|
||||||
# content-type is Javascript (silly IE...)
|
# content-type is Javascript and the user's browser is IE.
|
||||||
is_js = "javascript" in response.get('Content-Type', '').lower()
|
is_js = ("msie" in request.META.get('HTTP_USER_AGENT', '').lower() and
|
||||||
|
"javascript" in response.get('Content-Type', '').lower())
|
||||||
if response.has_header('Content-Encoding') or is_js:
|
if response.has_header('Content-Encoding') or is_js:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ from django.utils.translation import ugettext
|
|||||||
from django.utils.encoding import StrAndUnicode, smart_unicode
|
from django.utils.encoding import StrAndUnicode, smart_unicode
|
||||||
|
|
||||||
from util import ErrorList, ValidationError
|
from util import ErrorList, ValidationError
|
||||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
|
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from decimal import Decimal, DecimalException
|
from decimal import Decimal, DecimalException
|
||||||
@ -284,6 +284,8 @@ DEFAULT_DATETIME_INPUT_FORMATS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
class DateTimeField(Field):
|
class DateTimeField(Field):
|
||||||
|
widget = DateTimeInput
|
||||||
|
|
||||||
def __init__(self, input_formats=None, *args, **kwargs):
|
def __init__(self, input_formats=None, *args, **kwargs):
|
||||||
super(DateTimeField, self).__init__(*args, **kwargs)
|
super(DateTimeField, self).__init__(*args, **kwargs)
|
||||||
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
|
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
|
||||||
@ -300,6 +302,12 @@ class DateTimeField(Field):
|
|||||||
return value
|
return value
|
||||||
if isinstance(value, datetime.date):
|
if isinstance(value, datetime.date):
|
||||||
return datetime.datetime(value.year, value.month, value.day)
|
return datetime.datetime(value.year, value.month, value.day)
|
||||||
|
if isinstance(value, list):
|
||||||
|
# Input comes from a SplitDateTimeWidget, for example. So, it's two
|
||||||
|
# components: date and time.
|
||||||
|
if len(value) != 2:
|
||||||
|
raise ValidationError(ugettext(u'Enter a valid date/time.'))
|
||||||
|
value = '%s %s' % tuple(value)
|
||||||
for format in self.input_formats:
|
for format in self.input_formats:
|
||||||
try:
|
try:
|
||||||
return datetime.datetime(*time.strptime(value, format)[:6])
|
return datetime.datetime(*time.strptime(value, format)[:6])
|
||||||
|
@ -19,7 +19,7 @@ from util import flatatt
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'Widget', 'TextInput', 'PasswordInput',
|
'Widget', 'TextInput', 'PasswordInput',
|
||||||
'HiddenInput', 'MultipleHiddenInput',
|
'HiddenInput', 'MultipleHiddenInput',
|
||||||
'FileInput', 'Textarea', 'CheckboxInput',
|
'FileInput', 'DateTimeInput', 'Textarea', 'CheckboxInput',
|
||||||
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
|
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
|
||||||
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
|
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
|
||||||
)
|
)
|
||||||
@ -151,6 +151,22 @@ class Textarea(Widget):
|
|||||||
final_attrs = self.build_attrs(attrs, name=name)
|
final_attrs = self.build_attrs(attrs, name=name)
|
||||||
return u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))
|
return u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))
|
||||||
|
|
||||||
|
class DateTimeInput(Input):
|
||||||
|
input_type = 'text'
|
||||||
|
format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59'
|
||||||
|
|
||||||
|
def __init__(self, attrs=None, format=None):
|
||||||
|
super(DateTimeInput, self).__init__(attrs)
|
||||||
|
if format:
|
||||||
|
self.format = format
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None):
|
||||||
|
if value is None:
|
||||||
|
value = ''
|
||||||
|
elif hasattr(value, 'strftime'):
|
||||||
|
value = value.strftime(self.format)
|
||||||
|
return super(DateTimeInput, self).render(name, value, attrs)
|
||||||
|
|
||||||
class CheckboxInput(Widget):
|
class CheckboxInput(Widget):
|
||||||
def __init__(self, attrs=None, check_test=bool):
|
def __init__(self, attrs=None, check_test=bool):
|
||||||
super(CheckboxInput, self).__init__(attrs)
|
super(CheckboxInput, self).__init__(attrs)
|
||||||
@ -170,6 +186,13 @@ class CheckboxInput(Widget):
|
|||||||
final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
|
final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
|
||||||
return u'<input%s />' % flatatt(final_attrs)
|
return u'<input%s />' % flatatt(final_attrs)
|
||||||
|
|
||||||
|
def value_from_datadict(self, data, files, name):
|
||||||
|
if name not in data:
|
||||||
|
# A missing value means False because HTML form submission does not
|
||||||
|
# send results for unselected checkboxes.
|
||||||
|
return False
|
||||||
|
return super(CheckboxInput, self).value_from_datadict(data, files, name)
|
||||||
|
|
||||||
class Select(Widget):
|
class Select(Widget):
|
||||||
def __init__(self, attrs=None, choices=()):
|
def __init__(self, attrs=None, choices=()):
|
||||||
super(Select, self).__init__(attrs)
|
super(Select, self).__init__(attrs)
|
||||||
@ -425,5 +448,5 @@ class SplitDateTimeWidget(MultiWidget):
|
|||||||
|
|
||||||
def decompress(self, value):
|
def decompress(self, value):
|
||||||
if value:
|
if value:
|
||||||
return [value.date(), value.time()]
|
return [value.date(), value.time().replace(microsecond=0)]
|
||||||
return [None, None]
|
return [None, None]
|
||||||
|
@ -517,8 +517,14 @@ def firstof(parser, token):
|
|||||||
{% endif %}{% endif %}{% endif %}
|
{% endif %}{% endif %}{% endif %}
|
||||||
|
|
||||||
but obviously much cleaner!
|
but obviously much cleaner!
|
||||||
|
|
||||||
|
You can also use a literal string as a fallback value in case all
|
||||||
|
passed variables are False::
|
||||||
|
|
||||||
|
{% firstof var1 var2 var3 "fallback value" %}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bits = token.contents.split()[1:]
|
bits = token.split_contents()[1:]
|
||||||
if len(bits) < 1:
|
if len(bits) < 1:
|
||||||
raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
|
raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
|
||||||
return FirstOfNode(bits)
|
return FirstOfNode(bits)
|
||||||
@ -675,7 +681,7 @@ def do_if(parser, token):
|
|||||||
{% if athlete_list and coach_list or cheerleader_list %}
|
{% if athlete_list and coach_list or cheerleader_list %}
|
||||||
|
|
||||||
If you need to combine ``and`` and ``or`` to do advanced logic, just use
|
If you need to combine ``and`` and ``or`` to do advanced logic, just use
|
||||||
nested if tags. For example:
|
nested if tags. For example::
|
||||||
|
|
||||||
{% if athlete_list %}
|
{% if athlete_list %}
|
||||||
{% if coach_list or cheerleader_list %}
|
{% if coach_list or cheerleader_list %}
|
||||||
|
57
django/templatetags/cache.py
Normal file
57
django/templatetags/cache.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from django.template import Library, Node, TemplateSyntaxError
|
||||||
|
from django.template import resolve_variable
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
class CacheNode(Node):
|
||||||
|
def __init__(self, nodelist, expire_time, fragment_name, vary_on):
|
||||||
|
self.nodelist = nodelist
|
||||||
|
self.expire_time = expire_time
|
||||||
|
self.fragment_name = fragment_name
|
||||||
|
self.vary_on = vary_on
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
# Build a unicode key for this fragment and all vary-on's.
|
||||||
|
cache_key = u':'.join([self.fragment_name] + \
|
||||||
|
[force_unicode(resolve_variable(var, context)) for var in self.vary_on])
|
||||||
|
value = cache.get(cache_key)
|
||||||
|
if value is None:
|
||||||
|
value = self.nodelist.render(context)
|
||||||
|
cache.set(cache_key, value, self.expire_time)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def do_cache(parser, token):
|
||||||
|
"""
|
||||||
|
This will cache the contents of a template fragment for a given amount
|
||||||
|
of time.
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache [expire_time] [fragment_name] %}
|
||||||
|
.. some expensive processing ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
This tag also supports varying by a list of arguments::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache [expire_time] [fragment_name] [var1] [var2] .. %}
|
||||||
|
.. some expensive processing ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
Each unique set of arguments will result in a unique cache entry.
|
||||||
|
"""
|
||||||
|
nodelist = parser.parse(('endcache',))
|
||||||
|
parser.delete_first_token()
|
||||||
|
tokens = token.contents.split()
|
||||||
|
if len(tokens) < 3:
|
||||||
|
raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
|
||||||
|
try:
|
||||||
|
expire_time = int(tokens[1])
|
||||||
|
except ValueError:
|
||||||
|
raise TemplateSyntaxError(u"First argument to '%r' must be an integer (got '%s')." % (tokens[0], tokens[1]))
|
||||||
|
return CacheNode(nodelist, expire_time, tokens[2], tokens[3:])
|
||||||
|
|
||||||
|
register.tag('cache', do_cache)
|
@ -1,3 +1,5 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
from django.template import Node, Variable
|
from django.template import Node, Variable
|
||||||
from django.template import TemplateSyntaxError, TokenParser, Library
|
from django.template import TemplateSyntaxError, TokenParser, Library
|
||||||
from django.template import TOKEN_TEXT, TOKEN_VAR
|
from django.template import TOKEN_TEXT, TOKEN_VAR
|
||||||
@ -68,9 +70,11 @@ class BlockTranslateNode(Node):
|
|||||||
count = self.counter.resolve(context)
|
count = self.counter.resolve(context)
|
||||||
context[self.countervar] = count
|
context[self.countervar] = count
|
||||||
plural = self.render_token_list(self.plural)
|
plural = self.render_token_list(self.plural)
|
||||||
result = translation.ungettext(singular, plural, count) % context
|
result = translation.ungettext(singular, plural, count)
|
||||||
else:
|
else:
|
||||||
result = translation.ugettext(singular) % context
|
result = translation.ugettext(singular)
|
||||||
|
# Escape all isolated '%' before substituting in the context.
|
||||||
|
result = re.sub('%(?!\()', '%%', result) % context
|
||||||
context.pop()
|
context.pop()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ from django.core.management import call_command
|
|||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.test import signals
|
from django.test import signals
|
||||||
from django.template import Template
|
from django.template import Template
|
||||||
|
from django.utils.translation import deactivate
|
||||||
|
|
||||||
# The prefix to put on the default database name when creating
|
# The prefix to put on the default database name when creating
|
||||||
# the test database.
|
# the test database.
|
||||||
@ -43,7 +44,7 @@ def setup_test_environment():
|
|||||||
|
|
||||||
- Installing the instrumented test renderer
|
- Installing the instrumented test renderer
|
||||||
- Diverting the email sending functions to a test buffer
|
- Diverting the email sending functions to a test buffer
|
||||||
|
- Setting the active locale to match the LANGUAGE_CODE setting.
|
||||||
"""
|
"""
|
||||||
Template.original_render = Template.render
|
Template.original_render = Template.render
|
||||||
Template.render = instrumented_test_render
|
Template.render = instrumented_test_render
|
||||||
@ -53,6 +54,8 @@ def setup_test_environment():
|
|||||||
|
|
||||||
mail.outbox = []
|
mail.outbox = []
|
||||||
|
|
||||||
|
deactivate()
|
||||||
|
|
||||||
def teardown_test_environment():
|
def teardown_test_environment():
|
||||||
"""Perform any global post-test teardown. This involves:
|
"""Perform any global post-test teardown. This involves:
|
||||||
|
|
||||||
|
22
django/utils/checksums.py
Normal file
22
django/utils/checksums.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Common checksum routines (used in multiple localflavor/ cases, for example).
|
||||||
|
"""
|
||||||
|
|
||||||
|
__all__ = ['luhn',]
|
||||||
|
|
||||||
|
LUHN_ODD_LOOKUP = (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) # sum_of_digits(index * 2)
|
||||||
|
|
||||||
|
def luhn(candidate):
|
||||||
|
"""
|
||||||
|
Checks a candidate number for validity according to the Luhn
|
||||||
|
algorithm (used in validation of, for example, credit cards).
|
||||||
|
Both numeric and string candidates are accepted.
|
||||||
|
"""
|
||||||
|
if not isinstance(candidate, basestring):
|
||||||
|
candidate = str(candidate)
|
||||||
|
try:
|
||||||
|
evens = sum([int(c) for c in candidate[-1::-2]])
|
||||||
|
odds = sum([LUHN_ODD_LOOKUP[int(c)] for c in candidate[-2::-2]])
|
||||||
|
return ((evens + odds) % 10 == 0)
|
||||||
|
except ValueError: # Raised if an int conversion fails
|
||||||
|
return False
|
@ -46,19 +46,29 @@ class MergeDict(object):
|
|||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
""" returns a copy of this object"""
|
"""Returns a copy of this object."""
|
||||||
return self.__copy__()
|
return self.__copy__()
|
||||||
|
|
||||||
class SortedDict(dict):
|
class SortedDict(dict):
|
||||||
"A dictionary that keeps its keys in the order in which they're inserted."
|
"""
|
||||||
|
A dictionary that keeps its keys in the order in which they're inserted.
|
||||||
|
"""
|
||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
if data is None: data = {}
|
if data is None:
|
||||||
|
data = {}
|
||||||
dict.__init__(self, data)
|
dict.__init__(self, data)
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
self.keyOrder = data.keys()
|
self.keyOrder = data.keys()
|
||||||
else:
|
else:
|
||||||
self.keyOrder = [key for key, value in data]
|
self.keyOrder = [key for key, value in data]
|
||||||
|
|
||||||
|
def __deepcopy__(self,memo):
|
||||||
|
from copy import deepcopy
|
||||||
|
obj = self.__class__()
|
||||||
|
for k, v in self.items():
|
||||||
|
obj[k] = deepcopy(v, memo)
|
||||||
|
return obj
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
dict.__setitem__(self, key, value)
|
dict.__setitem__(self, key, value)
|
||||||
if key not in self.keyOrder:
|
if key not in self.keyOrder:
|
||||||
@ -72,6 +82,20 @@ class SortedDict(dict):
|
|||||||
for k in self.keyOrder:
|
for k in self.keyOrder:
|
||||||
yield k
|
yield k
|
||||||
|
|
||||||
|
def pop(self, k, *args):
|
||||||
|
result = dict.pop(self, k, *args)
|
||||||
|
try:
|
||||||
|
self.keyOrder.remove(k)
|
||||||
|
except ValueError:
|
||||||
|
# Key wasn't in the dictionary in the first place. No problem.
|
||||||
|
pass
|
||||||
|
return result
|
||||||
|
|
||||||
|
def popitem(self):
|
||||||
|
result = dict.popitem(self)
|
||||||
|
self.keyOrder.remove(result[0])
|
||||||
|
return result
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return zip(self.keyOrder, self.values())
|
return zip(self.keyOrder, self.values())
|
||||||
|
|
||||||
@ -102,20 +126,21 @@ class SortedDict(dict):
|
|||||||
return dict.setdefault(self, key, default)
|
return dict.setdefault(self, 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."""
|
||||||
return self[self.keyOrder[index]]
|
return self[self.keyOrder[index]]
|
||||||
|
|
||||||
def insert(self, index, key, value):
|
def insert(self, index, key, value):
|
||||||
"Inserts the key, value pair before the item with the given index."
|
"""Inserts the key, value pair before the item with the given index."""
|
||||||
if key in self.keyOrder:
|
if key in self.keyOrder:
|
||||||
n = self.keyOrder.index(key)
|
n = self.keyOrder.index(key)
|
||||||
del self.keyOrder[n]
|
del self.keyOrder[n]
|
||||||
if n < index: index -= 1
|
if n < index:
|
||||||
|
index -= 1
|
||||||
self.keyOrder.insert(index, key)
|
self.keyOrder.insert(index, key)
|
||||||
dict.__setitem__(self, key, value)
|
dict.__setitem__(self, key, value)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"Returns a copy of this object."
|
"""Returns a copy of this object."""
|
||||||
# This way of initializing the copy means it works for subclasses, too.
|
# This way of initializing the copy means it works for subclasses, too.
|
||||||
obj = self.__class__(self)
|
obj = self.__class__(self)
|
||||||
obj.keyOrder = self.keyOrder
|
obj.keyOrder = self.keyOrder
|
||||||
@ -133,7 +158,8 @@ class MultiValueDictKeyError(KeyError):
|
|||||||
|
|
||||||
class MultiValueDict(dict):
|
class MultiValueDict(dict):
|
||||||
"""
|
"""
|
||||||
A subclass of dictionary customized to handle multiple values for the same key.
|
A subclass of dictionary customized to handle multiple values for the
|
||||||
|
same key.
|
||||||
|
|
||||||
>>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
|
>>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
|
||||||
>>> d['name']
|
>>> d['name']
|
||||||
@ -176,15 +202,17 @@ class MultiValueDict(dict):
|
|||||||
|
|
||||||
def __deepcopy__(self, memo=None):
|
def __deepcopy__(self, memo=None):
|
||||||
import copy
|
import copy
|
||||||
if memo is None: memo = {}
|
if memo is None:
|
||||||
|
memo = {}
|
||||||
result = self.__class__()
|
result = self.__class__()
|
||||||
memo[id(self)] = result
|
memo[id(self)] = result
|
||||||
for key, value in dict.items(self):
|
for key, value in dict.items(self):
|
||||||
dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo))
|
dict.__setitem__(result, copy.deepcopy(key, memo),
|
||||||
|
copy.deepcopy(value, memo))
|
||||||
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 default value if the requested data doesn't exist."""
|
||||||
try:
|
try:
|
||||||
val = self[key]
|
val = self[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -194,7 +222,7 @@ 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 an empty list if the requested data doesn't exist."""
|
||||||
try:
|
try:
|
||||||
return dict.__getitem__(self, key)
|
return dict.__getitem__(self, key)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -214,7 +242,7 @@ class MultiValueDict(dict):
|
|||||||
return self.getlist(key)
|
return self.getlist(key)
|
||||||
|
|
||||||
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])
|
dict.__setitem__(self, key, self.getlist(key) + [value])
|
||||||
|
|
||||||
@ -226,19 +254,22 @@ class MultiValueDict(dict):
|
|||||||
return [(key, self[key]) for key in self.keys()]
|
return [(key, self[key]) for key in self.keys()]
|
||||||
|
|
||||||
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 dict.items(self)
|
||||||
|
|
||||||
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."""
|
||||||
return [self[key] for key in self.keys()]
|
return [self[key] for key in self.keys()]
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"Returns a copy of this object."
|
"""Returns a copy of this object."""
|
||||||
return self.__deepcopy__()
|
return self.__deepcopy__()
|
||||||
|
|
||||||
def update(self, *args, **kwargs):
|
def update(self, *args, **kwargs):
|
||||||
"update() extends rather than replaces existing key lists. Also accepts keyword args."
|
"""
|
||||||
|
update() extends rather than replaces existing key lists.
|
||||||
|
Also accepts keyword args.
|
||||||
|
"""
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
raise TypeError, "update expected at most 1 arguments, got %d" % len(args)
|
raise TypeError, "update expected at most 1 arguments, got %d" % len(args)
|
||||||
if args:
|
if args:
|
||||||
@ -299,4 +330,3 @@ class FileDict(dict):
|
|||||||
d = dict(self, content='<omitted>')
|
d = dict(self, content='<omitted>')
|
||||||
return dict.__repr__(d)
|
return dict.__repr__(d)
|
||||||
return dict.__repr__(self)
|
return dict.__repr__(self)
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
|
|||||||
|
|
||||||
If strings_only is True, don't convert (some) non-string-like objects.
|
If strings_only is True, don't convert (some) non-string-like objects.
|
||||||
"""
|
"""
|
||||||
if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.time, float)):
|
if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.date, datetime.time, float)):
|
||||||
return s
|
return s
|
||||||
if not isinstance(s, basestring,):
|
if not isinstance(s, basestring,):
|
||||||
if hasattr(s, '__unicode__'):
|
if hasattr(s, '__unicode__'):
|
||||||
|
@ -45,7 +45,7 @@ class SyndicationFeed(object):
|
|||||||
"Base class for all syndication feeds. Subclasses should provide write()"
|
"Base class for all syndication feeds. Subclasses should provide write()"
|
||||||
def __init__(self, title, link, description, language=None, author_email=None,
|
def __init__(self, title, link, description, language=None, author_email=None,
|
||||||
author_name=None, author_link=None, subtitle=None, categories=None,
|
author_name=None, author_link=None, subtitle=None, categories=None,
|
||||||
feed_url=None, feed_copyright=None, feed_guid=None):
|
feed_url=None, feed_copyright=None, feed_guid=None, ttl=None):
|
||||||
to_unicode = lambda s: force_unicode(s, strings_only=True)
|
to_unicode = lambda s: force_unicode(s, strings_only=True)
|
||||||
if categories:
|
if categories:
|
||||||
categories = [force_unicode(c) for c in categories]
|
categories = [force_unicode(c) for c in categories]
|
||||||
@ -62,12 +62,13 @@ class SyndicationFeed(object):
|
|||||||
'feed_url': iri_to_uri(feed_url),
|
'feed_url': iri_to_uri(feed_url),
|
||||||
'feed_copyright': to_unicode(feed_copyright),
|
'feed_copyright': to_unicode(feed_copyright),
|
||||||
'id': feed_guid or link,
|
'id': feed_guid or link,
|
||||||
|
'ttl': ttl,
|
||||||
}
|
}
|
||||||
self.items = []
|
self.items = []
|
||||||
|
|
||||||
def add_item(self, title, link, description, author_email=None,
|
def add_item(self, title, link, description, author_email=None,
|
||||||
author_name=None, author_link=None, pubdate=None, comments=None,
|
author_name=None, author_link=None, pubdate=None, comments=None,
|
||||||
unique_id=None, enclosure=None, categories=(), item_copyright=None):
|
unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None):
|
||||||
"""
|
"""
|
||||||
Adds an item to the feed. All args are expected to be Python Unicode
|
Adds an item to the feed. All args are expected to be Python Unicode
|
||||||
objects except pubdate, which is a datetime.datetime object, and
|
objects except pubdate, which is a datetime.datetime object, and
|
||||||
@ -89,6 +90,7 @@ class SyndicationFeed(object):
|
|||||||
'enclosure': enclosure,
|
'enclosure': enclosure,
|
||||||
'categories': categories or (),
|
'categories': categories or (),
|
||||||
'item_copyright': to_unicode(item_copyright),
|
'item_copyright': to_unicode(item_copyright),
|
||||||
|
'ttl': ttl,
|
||||||
})
|
})
|
||||||
|
|
||||||
def num_items(self):
|
def num_items(self):
|
||||||
@ -146,6 +148,8 @@ class RssFeed(SyndicationFeed):
|
|||||||
if self.feed['feed_copyright'] is not None:
|
if self.feed['feed_copyright'] is not None:
|
||||||
handler.addQuickElement(u"copyright", self.feed['feed_copyright'])
|
handler.addQuickElement(u"copyright", self.feed['feed_copyright'])
|
||||||
handler.addQuickElement(u"lastBuildDate", rfc2822_date(self.latest_post_date()).decode('ascii'))
|
handler.addQuickElement(u"lastBuildDate", rfc2822_date(self.latest_post_date()).decode('ascii'))
|
||||||
|
if self.feed['ttl'] is not None:
|
||||||
|
handler.addQuickElement(u"ttl", self.feed['ttl'])
|
||||||
self.write_items(handler)
|
self.write_items(handler)
|
||||||
self.endChannelElement(handler)
|
self.endChannelElement(handler)
|
||||||
handler.endElement(u"rss")
|
handler.endElement(u"rss")
|
||||||
@ -190,6 +194,8 @@ class Rss201rev2Feed(RssFeed):
|
|||||||
handler.addQuickElement(u"comments", item['comments'])
|
handler.addQuickElement(u"comments", item['comments'])
|
||||||
if item['unique_id'] is not None:
|
if item['unique_id'] is not None:
|
||||||
handler.addQuickElement(u"guid", item['unique_id'])
|
handler.addQuickElement(u"guid", item['unique_id'])
|
||||||
|
if item['ttl'] is not None:
|
||||||
|
handler.addQuickElement(u"ttl", item['ttl'])
|
||||||
|
|
||||||
# Enclosure.
|
# Enclosure.
|
||||||
if item['enclosure'] is not None:
|
if item['enclosure'] is not None:
|
||||||
|
@ -53,7 +53,11 @@ def lazy(func, *resultclasses):
|
|||||||
self._delegate_unicode = unicode in resultclasses
|
self._delegate_unicode = unicode in resultclasses
|
||||||
assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
|
assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
|
||||||
if self._delegate_unicode:
|
if self._delegate_unicode:
|
||||||
self.__unicode__ = self.__unicode_cast
|
# Each call to lazy() makes a new __proxy__ object, so this
|
||||||
|
# doesn't interfere with any other lazy() results.
|
||||||
|
__proxy__.__unicode__ = __proxy__.__unicode_cast
|
||||||
|
elif self._delegate_str:
|
||||||
|
__proxy__.__str__ = __proxy__.__str_cast
|
||||||
|
|
||||||
def __promise__(self, klass, funcname, func):
|
def __promise__(self, klass, funcname, func):
|
||||||
# Builds a wrapper around some magic method and registers that magic
|
# Builds a wrapper around some magic method and registers that magic
|
||||||
@ -72,14 +76,8 @@ def lazy(func, *resultclasses):
|
|||||||
def __unicode_cast(self):
|
def __unicode_cast(self):
|
||||||
return self.__func(*self.__args, **self.__kw)
|
return self.__func(*self.__args, **self.__kw)
|
||||||
|
|
||||||
def __str__(self):
|
def __str_cast(self):
|
||||||
# As __str__ is always a method on the type (class), it is looked
|
|
||||||
# up (and found) there first. So we can't just assign to it on a
|
|
||||||
# per-instance basis in __init__.
|
|
||||||
if self._delegate_str:
|
|
||||||
return str(self.__func(*self.__args, **self.__kw))
|
return str(self.__func(*self.__args, **self.__kw))
|
||||||
else:
|
|
||||||
return Promise.__str__(self)
|
|
||||||
|
|
||||||
def __cmp__(self, rhs):
|
def __cmp__(self, rhs):
|
||||||
if self._delegate_str:
|
if self._delegate_str:
|
||||||
|
@ -9,7 +9,8 @@ def urlquote(url, safe='/'):
|
|||||||
can safely be used as part of an argument to a subsequent iri_to_uri() call
|
can safely be used as part of an argument to a subsequent iri_to_uri() call
|
||||||
without double-quoting occurring.
|
without double-quoting occurring.
|
||||||
"""
|
"""
|
||||||
return force_unicode(urllib.quote(smart_str(url)))
|
return force_unicode(urllib.quote(smart_str(url), safe))
|
||||||
|
|
||||||
urlquote = allow_lazy(urlquote, unicode)
|
urlquote = allow_lazy(urlquote, unicode)
|
||||||
|
|
||||||
def urlquote_plus(url, safe=''):
|
def urlquote_plus(url, safe=''):
|
||||||
|
@ -8,7 +8,7 @@ __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
|
|||||||
'ngettext_lazy', 'string_concat', 'activate', 'deactivate',
|
'ngettext_lazy', 'string_concat', 'activate', 'deactivate',
|
||||||
'get_language', 'get_language_bidi', 'get_date_formats',
|
'get_language', 'get_language_bidi', 'get_date_formats',
|
||||||
'get_partial_date_formats', 'check_for_language', 'to_locale',
|
'get_partial_date_formats', 'check_for_language', 'to_locale',
|
||||||
'get_language_from_request', 'install', 'templatize', 'ugettext',
|
'get_language_from_request', 'templatize', 'ugettext',
|
||||||
'ungettext', 'deactivate_all']
|
'ungettext', 'deactivate_all']
|
||||||
|
|
||||||
# Here be dragons, so a short explanation of the logic won't hurt:
|
# Here be dragons, so a short explanation of the logic won't hurt:
|
||||||
@ -96,9 +96,6 @@ def to_locale(language):
|
|||||||
def get_language_from_request(request):
|
def get_language_from_request(request):
|
||||||
return real_get_language_from_request(request)
|
return real_get_language_from_request(request)
|
||||||
|
|
||||||
def install():
|
|
||||||
return real_install()
|
|
||||||
|
|
||||||
def templatize(src):
|
def templatize(src):
|
||||||
return real_templatize(src)
|
return real_templatize(src)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ def ungettext(singular, plural, number):
|
|||||||
return force_unicode(ngettext(singular, plural, number))
|
return force_unicode(ngettext(singular, plural, number))
|
||||||
|
|
||||||
activate = lambda x: None
|
activate = lambda x: None
|
||||||
deactivate = deactivate_all = install = lambda: None
|
deactivate = deactivate_all = lambda: None
|
||||||
get_language = lambda: settings.LANGUAGE_CODE
|
get_language = lambda: settings.LANGUAGE_CODE
|
||||||
get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
|
get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
|
||||||
get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
|
get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
"Translation helper functions"
|
"Translation helper functions"
|
||||||
|
|
||||||
import os, re, sys
|
import locale
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
import gettext as gettext_module
|
import gettext as gettext_module
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -25,14 +29,24 @@ _active = {}
|
|||||||
# The default translation is based on the settings file.
|
# The default translation is based on the settings file.
|
||||||
_default = None
|
_default = None
|
||||||
|
|
||||||
# This is a cache for accept-header to translation object mappings to prevent
|
# This is a cache for normalised accept-header languages to prevent multiple
|
||||||
# the accept parser to run multiple times for one user.
|
# file lookups when checking the same locale on repeated requests.
|
||||||
_accepted = {}
|
_accepted = {}
|
||||||
|
|
||||||
def to_locale(language):
|
# Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9.
|
||||||
|
accept_language_re = re.compile(r'''
|
||||||
|
([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*) # "en", "en-au", "x-y-z", "*"
|
||||||
|
(?:;q=(0(?:\.\d{,3})?|1(?:.0{,3})?))? # Optional "q=1.00", "q=0.8"
|
||||||
|
(?:\s*,\s*|$) # Multiple accepts per header.
|
||||||
|
''', re.VERBOSE)
|
||||||
|
|
||||||
|
def to_locale(language, to_lower=False):
|
||||||
"Turns a language name (en-us) into a locale name (en_US)."
|
"Turns a language name (en-us) into a locale name (en_US)."
|
||||||
p = language.find('-')
|
p = language.find('-')
|
||||||
if p >= 0:
|
if p >= 0:
|
||||||
|
if to_lower:
|
||||||
|
return language[:p].lower()+'_'+language[p+1:].lower()
|
||||||
|
else:
|
||||||
return language[:p].lower()+'_'+language[p+1:].upper()
|
return language[:p].lower()+'_'+language[p+1:].upper()
|
||||||
else:
|
else:
|
||||||
return language.lower()
|
return language.lower()
|
||||||
@ -249,8 +263,10 @@ def catalog():
|
|||||||
|
|
||||||
def do_translate(message, translation_function):
|
def do_translate(message, translation_function):
|
||||||
"""
|
"""
|
||||||
Translate 'message' using the given 'translation_function' name -- which
|
Translates 'message' using the given 'translation_function' name -- which
|
||||||
will be either gettext or ugettext.
|
will be either gettext or ugettext. It uses the current thread to find the
|
||||||
|
translation object to use. If no current translation is activated, the
|
||||||
|
message will be run through the default translation object.
|
||||||
"""
|
"""
|
||||||
global _default, _active
|
global _default, _active
|
||||||
t = _active.get(currentThread(), None)
|
t = _active.get(currentThread(), None)
|
||||||
@ -262,12 +278,6 @@ def do_translate(message, translation_function):
|
|||||||
return getattr(_default, translation_function)(message)
|
return getattr(_default, translation_function)(message)
|
||||||
|
|
||||||
def gettext(message):
|
def gettext(message):
|
||||||
"""
|
|
||||||
This function will be patched into the builtins module to provide the _
|
|
||||||
helper function. It will use the current thread as a discriminator to find
|
|
||||||
the translation object to use. If no current translation is activated, the
|
|
||||||
message will be run through the default translation object.
|
|
||||||
"""
|
|
||||||
return do_translate(message, 'gettext')
|
return do_translate(message, 'gettext')
|
||||||
|
|
||||||
def ugettext(message):
|
def ugettext(message):
|
||||||
@ -338,45 +348,39 @@ def get_language_from_request(request):
|
|||||||
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
||||||
return lang_code
|
return lang_code
|
||||||
|
|
||||||
lang_code = request.COOKIES.get('django_language', None)
|
lang_code = request.COOKIES.get('django_language')
|
||||||
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
if lang_code and lang_code in supported and check_for_language(lang_code):
|
||||||
return lang_code
|
return lang_code
|
||||||
|
|
||||||
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None)
|
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
|
||||||
if accept is not None:
|
for lang, unused in parse_accept_lang_header(accept):
|
||||||
|
if lang == '*':
|
||||||
|
break
|
||||||
|
|
||||||
t = _accepted.get(accept, None)
|
# We have a very restricted form for our language files (no encoding
|
||||||
if t is not None:
|
# specifier, since they all must be UTF-8 and only one possible
|
||||||
return t
|
# language each time. So we avoid the overhead of gettext.find() and
|
||||||
|
# look up the MO file manually.
|
||||||
|
|
||||||
def _parsed(el):
|
normalized = locale.locale_alias.get(to_locale(lang, True))
|
||||||
p = el.find(';q=')
|
if not normalized:
|
||||||
if p >= 0:
|
continue
|
||||||
lang = el[:p].strip()
|
|
||||||
order = int(float(el[p+3:].strip())*100)
|
|
||||||
else:
|
|
||||||
lang = el
|
|
||||||
order = 100
|
|
||||||
p = lang.find('-')
|
|
||||||
if p >= 0:
|
|
||||||
mainlang = lang[:p]
|
|
||||||
else:
|
|
||||||
mainlang = lang
|
|
||||||
return (lang, mainlang, order)
|
|
||||||
|
|
||||||
langs = [_parsed(el) for el in accept.split(',')]
|
# Remove the default encoding from locale_alias
|
||||||
langs.sort(lambda a,b: -1*cmp(a[2], b[2]))
|
normalized = normalized.split('.')[0]
|
||||||
|
|
||||||
for lang, mainlang, order in langs:
|
if normalized in _accepted:
|
||||||
if lang in supported or mainlang in supported:
|
# We've seen this locale before and have an MO file for it, so no
|
||||||
langfile = gettext_module.find('django', globalpath, [to_locale(lang)])
|
# need to check again.
|
||||||
if langfile:
|
return _accepted[normalized]
|
||||||
# reconstruct the actual language from the language
|
|
||||||
# filename, because otherwise we might incorrectly
|
for lang in (normalized, normalized.split('_')[0]):
|
||||||
# report de_DE if we only have de available, but
|
if lang not in supported:
|
||||||
# did find de_DE because of language normalization
|
continue
|
||||||
lang = langfile[len(globalpath):].split(os.path.sep)[1]
|
langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
|
||||||
_accepted[accept] = lang
|
'django.mo')
|
||||||
|
if os.path.exists(langfile):
|
||||||
|
_accepted[normalized] = lang
|
||||||
return lang
|
return lang
|
||||||
|
|
||||||
return settings.LANGUAGE_CODE
|
return settings.LANGUAGE_CODE
|
||||||
@ -414,13 +418,6 @@ def get_partial_date_formats():
|
|||||||
month_day_format = settings.MONTH_DAY_FORMAT
|
month_day_format = settings.MONTH_DAY_FORMAT
|
||||||
return year_month_format, month_day_format
|
return year_month_format, month_day_format
|
||||||
|
|
||||||
def install():
|
|
||||||
"""
|
|
||||||
Installs the gettext function as the default translation function under
|
|
||||||
the name '_'.
|
|
||||||
"""
|
|
||||||
__builtins__['_'] = gettext
|
|
||||||
|
|
||||||
dot_re = re.compile(r'\S')
|
dot_re = re.compile(r'\S')
|
||||||
def blankout(src, char):
|
def blankout(src, char):
|
||||||
"""
|
"""
|
||||||
@ -516,3 +513,23 @@ def templatize(src):
|
|||||||
out.write(blankout(t.contents, 'X'))
|
out.write(blankout(t.contents, 'X'))
|
||||||
return out.getvalue()
|
return out.getvalue()
|
||||||
|
|
||||||
|
def parse_accept_lang_header(lang_string):
|
||||||
|
"""
|
||||||
|
Parses the lang_string, which is the body of an HTTP Accept-Language
|
||||||
|
header, and returns a list of (lang, q-value), ordered by 'q' values.
|
||||||
|
|
||||||
|
Any format errors in lang_string results in an empty list being returned.
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
pieces = accept_language_re.split(lang_string)
|
||||||
|
if pieces[-1]:
|
||||||
|
return []
|
||||||
|
for i in range(0, len(pieces) - 1, 3):
|
||||||
|
first, lang, priority = pieces[i : i + 3]
|
||||||
|
if first:
|
||||||
|
return []
|
||||||
|
priority = priority and float(priority) or 1.0
|
||||||
|
result.append((lang, priority))
|
||||||
|
result.sort(lambda x, y: -cmp(x[1], y[1]))
|
||||||
|
return result
|
||||||
|
|
||||||
|
@ -201,16 +201,15 @@ def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_na
|
|||||||
if source is None:
|
if source is None:
|
||||||
return None, [], None, []
|
return None, [], None, []
|
||||||
|
|
||||||
encoding=None
|
encoding = 'ascii'
|
||||||
for line in source[:2]:
|
for line in source[:2]:
|
||||||
# File coding may be specified (and may not be UTF-8). Match
|
# File coding may be specified. Match pattern from PEP-263
|
||||||
# pattern from PEP-263 (http://www.python.org/dev/peps/pep-0263/)
|
# (http://www.python.org/dev/peps/pep-0263/)
|
||||||
match = re.search(r'coding[:=]\s*([-\w.]+)', line)
|
match = re.search(r'coding[:=]\s*([-\w.]+)', line)
|
||||||
if match:
|
if match:
|
||||||
encoding = match.group(1)
|
encoding = match.group(1)
|
||||||
break
|
break
|
||||||
if encoding:
|
source = [unicode(sline, encoding, 'replace') for sline in source]
|
||||||
source = [unicode(sline, encoding) for sline in source]
|
|
||||||
|
|
||||||
lower_bound = max(0, lineno - context_lines)
|
lower_bound = max(0, lineno - context_lines)
|
||||||
upper_bound = lineno + context_lines
|
upper_bound = lineno + context_lines
|
||||||
|
@ -62,7 +62,7 @@ with the standard ``Auth*`` and ``Require`` directives::
|
|||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
<Location /exmaple/>
|
<Location /example/>
|
||||||
AuthType Basic
|
AuthType Basic
|
||||||
AuthName "example.com"
|
AuthName "example.com"
|
||||||
**AuthBasicAuthoritative Off**
|
**AuthBasicAuthoritative Off**
|
||||||
|
@ -119,8 +119,8 @@ in your database that is in the proper format that Django's database-cache
|
|||||||
system expects.
|
system expects.
|
||||||
|
|
||||||
Once you've created that database table, set your ``CACHE_BACKEND`` setting to
|
Once you've created that database table, set your ``CACHE_BACKEND`` setting to
|
||||||
``"db://tablename/"``, where ``tablename`` is the name of the database table.
|
``"db://tablename"``, where ``tablename`` is the name of the database table.
|
||||||
In this example, the cache table's name is ``my_cache_table``:
|
In this example, the cache table's name is ``my_cache_table``::
|
||||||
|
|
||||||
CACHE_BACKEND = 'db://my_cache_table'
|
CACHE_BACKEND = 'db://my_cache_table'
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ entire site. Just add ``'django.middleware.cache.CacheMiddleware'`` to your
|
|||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
(The order of ``MIDDLEWARE_CLASSES`` matters. See "Order of MIDDLEWARE_CLASSES"
|
(The order of ``MIDDLEWARE_CLASSES`` matters. See `Order of MIDDLEWARE_CLASSES`_
|
||||||
below.)
|
below.)
|
||||||
|
|
||||||
Then, add the following required settings to your Django settings file:
|
Then, add the following required settings to your Django settings file:
|
||||||
@ -288,6 +288,36 @@ Or, using Python 2.4's decorator syntax::
|
|||||||
above example, the result of the ``slashdot_this()`` view will be cached for 15
|
above example, the result of the ``slashdot_this()`` view will be cached for 15
|
||||||
minutes.
|
minutes.
|
||||||
|
|
||||||
|
Template fragment caching
|
||||||
|
=========================
|
||||||
|
|
||||||
|
If you're after even more control, you can also cache template fragments using
|
||||||
|
the ``cache`` template tag. To give your template access to this tag, put ``{%
|
||||||
|
load cache %}`` near the top of your template.
|
||||||
|
|
||||||
|
The ``{% cache %}`` template tag caches the contents of the block for a given
|
||||||
|
amount of time. It takes at least two arguments: the cache timeout, in
|
||||||
|
seconds, and the name to give the cache fragment. For example::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache 500 sidebar %}
|
||||||
|
.. sidebar ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
Sometimes you might want to cache multiple copies of a fragment depending on
|
||||||
|
some dynamic data that appears inside the fragment. For example you may want a
|
||||||
|
separate cached copy of the sidebar used in the previous example for every user
|
||||||
|
of your site. This can be easily achieved by passing additional arguments to
|
||||||
|
the ``{% cache %}`` template tag to uniquely identify the cache fragment::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache 500 sidebar request.user.username %}
|
||||||
|
.. sidebar for logged in user ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
If you need more than one argument to identify the fragment that's fine, simply
|
||||||
|
pass as many arguments to ``{% cache %}`` as you need!
|
||||||
|
|
||||||
The low-level cache API
|
The low-level cache API
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
@ -326,6 +356,15 @@ get() can take a ``default`` argument::
|
|||||||
>>> cache.get('my_key', 'has expired')
|
>>> cache.get('my_key', 'has expired')
|
||||||
'has expired'
|
'has expired'
|
||||||
|
|
||||||
|
To add a key only if it doesn't already exist, there is an add() method. It
|
||||||
|
takes the same parameters as set(), but will not attempt to update the cache
|
||||||
|
if the key specified is already present::
|
||||||
|
|
||||||
|
>>> cache.set('add_key', 'Initial value')
|
||||||
|
>>> cache.add('add_key', 'New value')
|
||||||
|
>>> cache.get('add_key')
|
||||||
|
'Initial value'
|
||||||
|
|
||||||
There's also a get_many() interface that only hits the cache once. get_many()
|
There's also a get_many() interface that only hits the cache once. get_many()
|
||||||
returns a dictionary with all the keys you asked for that actually exist in the
|
returns a dictionary with all the keys you asked for that actually exist in the
|
||||||
cache (and haven't expired)::
|
cache (and haven't expired)::
|
||||||
@ -556,8 +595,11 @@ within the ``MIDDLEWARE_CLASSES`` setting, because the cache middleware needs
|
|||||||
to know which headers by which to vary the cache storage. Middleware always
|
to know which headers by which to vary the cache storage. Middleware always
|
||||||
adds something to the ``Vary`` response header when it can.
|
adds something to the ``Vary`` response header when it can.
|
||||||
|
|
||||||
Put the ``CacheMiddleware`` after any middlewares that might add something to
|
Put the ``CacheMiddleware`` *before* any other middleware that might add
|
||||||
the ``Vary`` header. The following middlewares do so:
|
something to the ``Vary`` header (response middleware is applied in reverse
|
||||||
|
order). The following middleware modules do so:
|
||||||
|
|
||||||
* ``SessionMiddleware`` adds ``Cookie``
|
* ``SessionMiddleware`` adds ``Cookie``
|
||||||
* ``GZipMiddleware`` adds ``Accept-Encoding``
|
* ``GZipMiddleware`` adds ``Accept-Encoding``
|
||||||
|
* ``LocaleMiddleware`` adds ``Accept-Language``
|
||||||
|
|
||||||
|
@ -335,6 +335,10 @@ Please follow these coding standards when writing code for inclusion in Django:
|
|||||||
|
|
||||||
* Unless otherwise specified, follow `PEP 8`_.
|
* Unless otherwise specified, follow `PEP 8`_.
|
||||||
|
|
||||||
|
You could use a tool like `pep8.py`_ to check for some problems in this
|
||||||
|
area, but remember that PEP 8 is only a guide, so respect the style of
|
||||||
|
the surrounding code as a primary goal.
|
||||||
|
|
||||||
* Use four spaces for indentation.
|
* Use four spaces for indentation.
|
||||||
|
|
||||||
* Use underscores, not camelCase, for variable, function and method names
|
* Use underscores, not camelCase, for variable, function and method names
|
||||||
@ -924,5 +928,6 @@ requests for commit access are potential flame-war starters, and will be ignored
|
|||||||
.. _`#django`: irc://irc.freenode.net/django
|
.. _`#django`: irc://irc.freenode.net/django
|
||||||
.. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
|
.. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
|
||||||
.. _PEP 8: http://www.python.org/peps/pep-0008.html
|
.. _PEP 8: http://www.python.org/peps/pep-0008.html
|
||||||
|
.. _pep8.py: http://svn.browsershots.org/trunk/devtools/pep8/pep8.py
|
||||||
.. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n
|
.. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n
|
||||||
.. _`tags/releases`: http://code.djangoproject.com/browser/django/tags/releases
|
.. _`tags/releases`: http://code.djangoproject.com/browser/django/tags/releases
|
||||||
|
@ -76,6 +76,14 @@ the ``mysql`` backend.
|
|||||||
If you are trying to use an older version of MySQL and the ``mysql_old``
|
If you are trying to use an older version of MySQL and the ``mysql_old``
|
||||||
backend, then 1.2.0 *might* work for you.
|
backend, then 1.2.0 *might* work for you.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If you see ``ImportError: cannot import name ImmutableSet`` when trying to
|
||||||
|
use Django, your MySQLdb installation may contain an outdated ``sets.py``
|
||||||
|
file that conflicts with the built-in module of the same name from Python
|
||||||
|
2.4 and later. To fix this, verify that you have installed MySQLdb version
|
||||||
|
1.2.1p2 or newer, then delete the ``sets.py`` file in the MySQLdb
|
||||||
|
directory that was left by an earlier version.
|
||||||
|
|
||||||
.. _MySQLdb: http://sourceforge.net/projects/mysql-python
|
.. _MySQLdb: http://sourceforge.net/projects/mysql-python
|
||||||
|
|
||||||
Creating your database
|
Creating your database
|
||||||
|
@ -741,22 +741,25 @@ Customized actions
|
|||||||
|
|
||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
If you want to add an action of your own to ``manage.py``, you can.
|
Applications can register their own actions with ``manage.py``. For example,
|
||||||
Simply add a ``management/commands`` directory to your application.
|
you might want to add a ``manage.py`` action for a Django app that you're
|
||||||
Each python module in that directory will be discovered and registered as
|
distributing.
|
||||||
|
|
||||||
|
To do this, just add a ``management/commands`` directory to your application.
|
||||||
|
Each Python module in that directory will be auto-discovered and registered as
|
||||||
a command that can be executed as an action when you run ``manage.py``::
|
a command that can be executed as an action when you run ``manage.py``::
|
||||||
|
|
||||||
/fancy_blog
|
blog/
|
||||||
__init__.py
|
__init__.py
|
||||||
models.py
|
models.py
|
||||||
/management
|
management/
|
||||||
__init__.py
|
__init__.py
|
||||||
/commands
|
commands/
|
||||||
__init__.py
|
__init__.py
|
||||||
explode.py
|
explode.py
|
||||||
views.py
|
views.py
|
||||||
|
|
||||||
In this example, ``explode`` command will be made available to any project
|
In this example, the ``explode`` command will be made available to any project
|
||||||
that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``.
|
that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``.
|
||||||
|
|
||||||
The ``explode.py`` module has only one requirement -- it must define a class
|
The ``explode.py`` module has only one requirement -- it must define a class
|
||||||
|
@ -48,7 +48,7 @@ with the given URL with a site ID that corresponds to the SITE_ID_ setting.
|
|||||||
If it finds a match, it follows this algorithm:
|
If it finds a match, it follows this algorithm:
|
||||||
|
|
||||||
* If the flatpage has a custom template, it loads that template. Otherwise,
|
* If the flatpage has a custom template, it loads that template. Otherwise,
|
||||||
it loads the template ``flatpages/default``.
|
it loads the template ``flatpages/default.html``.
|
||||||
* It passes that template a single context variable, ``flatpage``, which is
|
* It passes that template a single context variable, ``flatpage``, which is
|
||||||
the flatpage object. It uses RequestContext_ in rendering the template.
|
the flatpage object. It uses RequestContext_ in rendering the template.
|
||||||
|
|
||||||
|
@ -63,7 +63,10 @@ installed.
|
|||||||
* If you're using MySQL, you'll need MySQLdb_, version 1.2.1p2 or higher.
|
* If you're using MySQL, you'll need MySQLdb_, version 1.2.1p2 or higher.
|
||||||
You will also want to read the database-specific notes for the `MySQL backend`_.
|
You will also want to read the database-specific notes for the `MySQL backend`_.
|
||||||
|
|
||||||
* If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher.
|
* If you're using SQLite and either Python 2.3 or Python 2.4, you'll need
|
||||||
|
pysqlite_. Use version 2.0.3 or higher. Python 2.5 ships with an sqlite
|
||||||
|
wrapper in the standard library, so you don't need to install anything extra
|
||||||
|
in that case.
|
||||||
|
|
||||||
* If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher.
|
* If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher.
|
||||||
You will also want to read the database-specific notes for the `Oracle backend`_.
|
You will also want to read the database-specific notes for the `Oracle backend`_.
|
||||||
|
@ -178,8 +178,9 @@ request, before Django decides which view to execute.
|
|||||||
``process_request()`` should return either ``None`` or an ``HttpResponse``
|
``process_request()`` should return either ``None`` or an ``HttpResponse``
|
||||||
object. If it returns ``None``, Django will continue processing this request,
|
object. If it returns ``None``, Django will continue processing this request,
|
||||||
executing any other middleware and, then, the appropriate view. If it returns
|
executing any other middleware and, then, the appropriate view. If it returns
|
||||||
an ``HttpResponse`` object, Django won't bother calling ANY other middleware or
|
an ``HttpResponse`` object, Django won't bother calling ANY other request,
|
||||||
the appropriate view; it'll return that ``HttpResponse``.
|
view or exception middleware, or the appropriate view; it'll return that
|
||||||
|
``HttpResponse``. Response middleware is always called on every response.
|
||||||
|
|
||||||
process_view
|
process_view
|
||||||
------------
|
------------
|
||||||
@ -197,8 +198,9 @@ arguments that will be passed to the view. Neither ``view_args`` nor
|
|||||||
return either ``None`` or an ``HttpResponse`` object. If it returns ``None``,
|
return either ``None`` or an ``HttpResponse`` object. If it returns ``None``,
|
||||||
Django will continue processing this request, executing any other
|
Django will continue processing this request, executing any other
|
||||||
``process_view()`` middleware and, then, the appropriate view. If it returns an
|
``process_view()`` middleware and, then, the appropriate view. If it returns an
|
||||||
``HttpResponse`` object, Django won't bother calling ANY other middleware or
|
``HttpResponse`` object, Django won't bother calling ANY other request, view
|
||||||
the appropriate view; it'll return that ``HttpResponse``.
|
or exception middleware, or the appropriate view; it'll return that
|
||||||
|
``HttpResponse``. Response middleware is always called on every response.
|
||||||
|
|
||||||
process_response
|
process_response
|
||||||
----------------
|
----------------
|
||||||
@ -236,7 +238,8 @@ Guidelines
|
|||||||
|
|
||||||
* Feel free to look at Django's available middleware for examples. The
|
* Feel free to look at Django's available middleware for examples. The
|
||||||
core Django middleware classes are in ``django/middleware/`` in the
|
core Django middleware classes are in ``django/middleware/`` in the
|
||||||
Django distribution. The session middleware is in ``django/contrib/sessions``.
|
Django distribution. The session middleware is in
|
||||||
|
``django/contrib/sessions``.
|
||||||
|
|
||||||
* If you write a middleware component that you think would be useful to
|
* If you write a middleware component that you think would be useful to
|
||||||
other people, contribute to the community! Let us know, and we'll
|
other people, contribute to the community! Let us know, and we'll
|
||||||
|
@ -678,7 +678,9 @@ set.
|
|||||||
|
|
||||||
If ``True``, this field must be unique throughout the table.
|
If ``True``, this field must be unique throughout the table.
|
||||||
|
|
||||||
This is enforced at the database level and at the Django admin-form level.
|
This is enforced at the database level and at the Django admin-form level. If
|
||||||
|
you try to add save a model with a duplicate value in a ``unique`` field, a
|
||||||
|
``django.db.IntegrityError`` will be raised by the model's ``save()`` method.
|
||||||
|
|
||||||
``unique_for_date``
|
``unique_for_date``
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -87,17 +87,19 @@ lived under the ``weblog/`` directory, you would *also* need to add
|
|||||||
**parent directories** of anything you import directly must be on the Python
|
**parent directories** of anything you import directly must be on the Python
|
||||||
path.
|
path.
|
||||||
|
|
||||||
.. caution::
|
.. note::
|
||||||
|
|
||||||
If you're using Windows, remember that the path will contain backslashes.
|
If you're using Windows, it is still recommended that you use forward
|
||||||
This string is passed through Python's string parser twice, so you need to
|
slashes in the pathnames, even though Windows normally uses backslashes
|
||||||
escape each backslash **twice**::
|
for its native separator. Apache knows how to convert from the forward
|
||||||
|
slash format to the native format, so this approach is portable and easier
|
||||||
|
to read (it avoids tricky problems with having to double-escape
|
||||||
|
backslashes).
|
||||||
|
|
||||||
PythonPath "['c:\\\\path\\\\to\\\\project'] + sys.path"
|
This is valid even on a Windows system::
|
||||||
|
|
||||||
Or, use raw strings::
|
PythonPath "['c:/path/to/project'] + sys.path"
|
||||||
|
|
||||||
PythonPath "[r'c:\\path\\to\\project'] + sys.path"
|
|
||||||
|
|
||||||
You can also add directives such as ``PythonAutoReload Off`` for performance.
|
You can also add directives such as ``PythonAutoReload Off`` for performance.
|
||||||
See the `mod_python documentation`_ for a full list of options.
|
See the `mod_python documentation`_ for a full list of options.
|
||||||
|
@ -100,7 +100,7 @@ Start with this basic ``Form`` subclass, which we'll call ``ContactForm``::
|
|||||||
subject = forms.CharField(max_length=100)
|
subject = forms.CharField(max_length=100)
|
||||||
message = forms.CharField()
|
message = forms.CharField()
|
||||||
sender = forms.EmailField()
|
sender = forms.EmailField()
|
||||||
cc_myself = forms.BooleanField()
|
cc_myself = forms.BooleanField(required=False)
|
||||||
|
|
||||||
A form is composed of ``Field`` objects. In this case, our form has four
|
A form is composed of ``Field`` objects. In this case, our form has four
|
||||||
fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
|
fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
|
||||||
@ -860,6 +860,23 @@ classes::
|
|||||||
<li>Instrument: <input type="text" name="instrument" /></li>
|
<li>Instrument: <input type="text" name="instrument" /></li>
|
||||||
<li>Haircut type: <input type="text" name="haircut_type" /></li>
|
<li>Haircut type: <input type="text" name="haircut_type" /></li>
|
||||||
|
|
||||||
|
|
||||||
|
Prefixes for forms
|
||||||
|
------------------
|
||||||
|
|
||||||
|
You can put several Django forms inside one ``<form>`` tag. To give each
|
||||||
|
``Form`` its own namespace you need to use the ``prefix`` keyword argument::
|
||||||
|
|
||||||
|
>>> mother = PersonForm(prefix="mother")
|
||||||
|
>>> father = PersonForm(prefix="father")
|
||||||
|
>>> print mother.as_ul()
|
||||||
|
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li>
|
||||||
|
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li>
|
||||||
|
>>> print father.as_ul()
|
||||||
|
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
|
||||||
|
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
|
||||||
|
|
||||||
|
|
||||||
Fields
|
Fields
|
||||||
======
|
======
|
||||||
|
|
||||||
@ -1043,7 +1060,7 @@ fields. We've specified ``auto_id=False`` to simplify the output::
|
|||||||
... subject = forms.CharField(max_length=100, help_text='100 characters max.')
|
... subject = forms.CharField(max_length=100, help_text='100 characters max.')
|
||||||
... message = forms.CharField()
|
... message = forms.CharField()
|
||||||
... sender = forms.EmailField(help_text='A valid e-mail address, please.')
|
... sender = forms.EmailField(help_text='A valid e-mail address, please.')
|
||||||
... cc_myself = forms.BooleanField()
|
... cc_myself = forms.BooleanField(required=False)
|
||||||
>>> f = HelpTextContactForm(auto_id=False)
|
>>> f = HelpTextContactForm(auto_id=False)
|
||||||
>>> print f.as_table()
|
>>> print f.as_table()
|
||||||
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr>
|
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr>
|
||||||
@ -1122,9 +1139,20 @@ For each field, we describe the default widget used if you don't specify
|
|||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* Default widget: ``CheckboxInput``
|
* Default widget: ``CheckboxInput``
|
||||||
* Empty value: ``None``
|
* Empty value: ``False``
|
||||||
* Normalizes to: A Python ``True`` or ``False`` value.
|
* Normalizes to: A Python ``True`` or ``False`` value.
|
||||||
* Validates nothing (i.e., it never raises a ``ValidationError``).
|
* Validates that the check box is checked (i.e. the value is ``True``) if
|
||||||
|
the field has ``required=True``.
|
||||||
|
|
||||||
|
**New in Django development version:** The empty value for a ``CheckboxInput``
|
||||||
|
(and hence the standard ``BooleanField``) has changed to return ``False``
|
||||||
|
instead of ``None`` in the development version.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Since all ``Field`` subclasses have ``required=True`` by default, the
|
||||||
|
validation condition here is important. If you want to include a checkbox
|
||||||
|
in your form that can be either checked or unchecked, you must remember to
|
||||||
|
pass in ``required=False`` when creating the ``BooleanField``.
|
||||||
|
|
||||||
``CharField``
|
``CharField``
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
@ -1132,7 +1160,8 @@ For each field, we describe the default widget used if you don't specify
|
|||||||
* Default widget: ``TextInput``
|
* Default widget: ``TextInput``
|
||||||
* Empty value: ``''`` (an empty string)
|
* Empty value: ``''`` (an empty string)
|
||||||
* Normalizes to: A Unicode object.
|
* Normalizes to: A Unicode object.
|
||||||
* Validates nothing, unless ``max_length`` or ``min_length`` is provided.
|
* Validates ``max_length`` or ``min_length``, if they are provided.
|
||||||
|
Otherwise, all inputs are valid.
|
||||||
|
|
||||||
Has two optional arguments for validation, ``max_length`` and ``min_length``.
|
Has two optional arguments for validation, ``max_length`` and ``min_length``.
|
||||||
If provided, these arguments ensure that the string is at most or at least the
|
If provided, these arguments ensure that the string is at most or at least the
|
||||||
@ -1172,7 +1201,7 @@ If no ``input_formats`` argument is provided, the default input formats are::
|
|||||||
``DateTimeField``
|
``DateTimeField``
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* Default widget: ``TextInput``
|
* Default widget: ``DateTimeInput``
|
||||||
* Empty value: ``None``
|
* Empty value: ``None``
|
||||||
* Normalizes to: A Python ``datetime.datetime`` object.
|
* Normalizes to: A Python ``datetime.datetime`` object.
|
||||||
* Validates that the given value is either a ``datetime.datetime``,
|
* Validates that the given value is either a ``datetime.datetime``,
|
||||||
@ -1193,6 +1222,9 @@ If no ``input_formats`` argument is provided, the default input formats are::
|
|||||||
'%m/%d/%y %H:%M', # '10/25/06 14:30'
|
'%m/%d/%y %H:%M', # '10/25/06 14:30'
|
||||||
'%m/%d/%y', # '10/25/06'
|
'%m/%d/%y', # '10/25/06'
|
||||||
|
|
||||||
|
**New in Django development version:** The ``DateTimeField`` used to use a
|
||||||
|
``TextInput`` widget by default. This has now changed.
|
||||||
|
|
||||||
``DecimalField``
|
``DecimalField``
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -1508,7 +1540,7 @@ like so::
|
|||||||
subject = forms.CharField(max_length=100)
|
subject = forms.CharField(max_length=100)
|
||||||
message = forms.CharField()
|
message = forms.CharField()
|
||||||
senders = MultiEmailField()
|
senders = MultiEmailField()
|
||||||
cc_myself = forms.BooleanField()
|
cc_myself = forms.BooleanField(required=False)
|
||||||
|
|
||||||
Widgets
|
Widgets
|
||||||
=======
|
=======
|
||||||
@ -1529,6 +1561,7 @@ commonly used groups of widgets:
|
|||||||
``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
|
``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
|
||||||
instances.
|
instances.
|
||||||
``FileInput`` ``<input type='file' ...``
|
``FileInput`` ``<input type='file' ...``
|
||||||
|
``DateTimeInput`` ``<input type='text' ...``
|
||||||
``Textarea`` ``<textarea>...</textarea>``
|
``Textarea`` ``<textarea>...</textarea>``
|
||||||
``CheckboxInput`` ``<input type='checkbox' ...``
|
``CheckboxInput`` ``<input type='checkbox' ...``
|
||||||
``Select`` ``<select><option ...``
|
``Select`` ``<select><option ...``
|
||||||
@ -1542,6 +1575,9 @@ commonly used groups of widgets:
|
|||||||
one for the Date, and one for the Time.
|
one for the Date, and one for the Time.
|
||||||
============================ ===========================================
|
============================ ===========================================
|
||||||
|
|
||||||
|
**New in Django development version:** The ``DateTimeInput`` has been added
|
||||||
|
since the last release.
|
||||||
|
|
||||||
Specifying widgets
|
Specifying widgets
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -2033,7 +2069,7 @@ have a ``Message`` model that holds each contact submission. Something like::
|
|||||||
subject = models.CharField(max_length=100)
|
subject = models.CharField(max_length=100)
|
||||||
message = models.TextField()
|
message = models.TextField()
|
||||||
sender = models.EmailField()
|
sender = models.EmailField()
|
||||||
cc_myself = models.BooleanField()
|
cc_myself = models.BooleanField(required=False)
|
||||||
|
|
||||||
You could use this model to create a form (using ``form_for_model()``). You
|
You could use this model to create a form (using ``form_for_model()``). You
|
||||||
could also use existing ``Message`` instances to create a form for editing
|
could also use existing ``Message`` instances to create a form for editing
|
||||||
|
@ -172,7 +172,7 @@ of the case of the actual model class name.
|
|||||||
ADMIN_FOR
|
ADMIN_FOR
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Default: ``()`` (Empty list)
|
Default: ``()`` (Empty tuple)
|
||||||
|
|
||||||
Used for admin-site settings modules, this should be a tuple of settings
|
Used for admin-site settings modules, this should be a tuple of settings
|
||||||
modules (in the format ``'foo.bar.baz'``) for which this site is an admin.
|
modules (in the format ``'foo.bar.baz'``) for which this site is an admin.
|
||||||
@ -578,6 +578,17 @@ strings for translation, but the translation won't happen at runtime -- so
|
|||||||
you'll have to remember to wrap the languages in the *real* ``gettext()`` in
|
you'll have to remember to wrap the languages in the *real* ``gettext()`` in
|
||||||
any code that uses ``LANGUAGES`` at runtime.
|
any code that uses ``LANGUAGES`` at runtime.
|
||||||
|
|
||||||
|
LOCALE_PATHS
|
||||||
|
------------
|
||||||
|
|
||||||
|
Default: ``()`` (Empty tuple)
|
||||||
|
|
||||||
|
A list of directories where Django looks for translation files.
|
||||||
|
See the `internationalization docs section`_ explaining the variable and the
|
||||||
|
default behavior.
|
||||||
|
|
||||||
|
.. _internationalization docs section: ../i18n/#using-translations-in-your-own-projects
|
||||||
|
|
||||||
LOGIN_REDIRECT_URL
|
LOGIN_REDIRECT_URL
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -773,6 +784,18 @@ Default: ``'sessionid'``
|
|||||||
The name of the cookie to use for sessions. This can be whatever you want.
|
The name of the cookie to use for sessions. This can be whatever you want.
|
||||||
See the `session docs`_.
|
See the `session docs`_.
|
||||||
|
|
||||||
|
SESSION_COOKIE_PATH
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
Default: ``'/'``
|
||||||
|
|
||||||
|
The path set on the session cookie. Should match the URL path of your Django
|
||||||
|
installation (or be parent of that path). This is useful if you have multiple
|
||||||
|
Django instances running under the same hostname; they can use different
|
||||||
|
cookie paths and each instance will only see its own session cookie.
|
||||||
|
|
||||||
SESSION_COOKIE_SECURE
|
SESSION_COOKIE_SECURE
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
@ -547,6 +547,22 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas
|
|||||||
|
|
||||||
copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
|
copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
|
||||||
|
|
||||||
|
# TTL -- One of the following three is optional. The framework looks
|
||||||
|
# for them in this order. Ignored for Atom feeds.
|
||||||
|
|
||||||
|
def ttl(self, obj):
|
||||||
|
"""
|
||||||
|
Takes the object returned by get_object() and returns the feed's
|
||||||
|
TTL (Time to live) as a normal Python string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def ttl(self):
|
||||||
|
"""
|
||||||
|
Returns the feed's ttl as a normal Python string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ttl = 600 # Hard-coded Time to live.
|
||||||
|
|
||||||
# ITEMS -- One of the following three is required. The framework looks
|
# ITEMS -- One of the following three is required. The framework looks
|
||||||
# for them in this order.
|
# for them in this order.
|
||||||
|
|
||||||
|
@ -2,13 +2,35 @@
|
|||||||
The Django template language: For template authors
|
The Django template language: For template authors
|
||||||
==================================================
|
==================================================
|
||||||
|
|
||||||
|
This document explains the language syntax of the Django template system. If
|
||||||
|
you're looking for a more technical perspective on how it works and how to
|
||||||
|
extend it, see `The Django template language: For Python programmers`_.
|
||||||
|
|
||||||
Django's template language is designed to strike a balance between power and
|
Django's template language is designed to strike a balance between power and
|
||||||
ease. It's designed to feel comfortable to those used to working with HTML. If
|
ease. It's designed to feel comfortable to those used to working with HTML. If
|
||||||
you have any exposure to other text-based template languages, such as Smarty_
|
you have any exposure to other text-based template languages, such as Smarty_
|
||||||
or CheetahTemplate_, you should feel right at home with Django's templates.
|
or CheetahTemplate_, you should feel right at home with Django's templates.
|
||||||
|
|
||||||
|
.. admonition:: Philosophy
|
||||||
|
|
||||||
|
If you have a background in programming, or if you're used to languages
|
||||||
|
like PHP which mix programming code directly into HTML, you'll want to
|
||||||
|
bear in mind that the Django template system is not simply Python embedded
|
||||||
|
into HTML. This is by design: the template system is meant to express
|
||||||
|
presentation, not program logic.
|
||||||
|
|
||||||
|
The Django template system provides tags which function similarly to some
|
||||||
|
programming constructs -- an ``{% if %}`` tag for boolean tests, a ``{%
|
||||||
|
for %}`` tag for looping, etc. -- but these are not simply executed as the
|
||||||
|
corresponding Python code, and the template system will not execute
|
||||||
|
arbitrary Python expressions. Only the tags, filters and syntax listed
|
||||||
|
below are supported by default (although you can add `your own
|
||||||
|
extensions`_ to the template language as needed).
|
||||||
|
|
||||||
|
.. _`The Django template language: For Python programmers`: ../templates_python/
|
||||||
.. _Smarty: http://smarty.php.net/
|
.. _Smarty: http://smarty.php.net/
|
||||||
.. _CheetahTemplate: http://www.cheetahtemplate.org/
|
.. _CheetahTemplate: http://www.cheetahtemplate.org/
|
||||||
|
.. _your own extensions: ../templates_python/#extending-the-template-system
|
||||||
|
|
||||||
Templates
|
Templates
|
||||||
=========
|
=========
|
||||||
@ -454,6 +476,11 @@ This is equivalent to::
|
|||||||
{{ var3 }}
|
{{ var3 }}
|
||||||
{% endif %}{% endif %}{% endif %}
|
{% endif %}{% endif %}{% endif %}
|
||||||
|
|
||||||
|
You can also use a literal string as a fallback value in case all
|
||||||
|
passed variables are False::
|
||||||
|
|
||||||
|
{% firstof var1 var2 var3 "fallback value" %}
|
||||||
|
|
||||||
for
|
for
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
@ -1438,12 +1465,3 @@ A collection of template tags that can be useful while designing a website,
|
|||||||
such as a generator of Lorem Ipsum text. See the `webdesign documentation`_.
|
such as a generator of Lorem Ipsum text. See the `webdesign documentation`_.
|
||||||
|
|
||||||
.. _webdesign documentation: ../webdesign/
|
.. _webdesign documentation: ../webdesign/
|
||||||
|
|
||||||
Next steps
|
|
||||||
==========
|
|
||||||
|
|
||||||
Read the document `The Django template language: For Python programmers`_ if
|
|
||||||
you're interested in learning the template system from a technical
|
|
||||||
perspective -- how it works and how to extend it.
|
|
||||||
|
|
||||||
.. _The Django template language\: For Python programmers: ../templates_python/
|
|
||||||
|
@ -41,7 +41,7 @@ From the command line, ``cd`` into a directory where you'd like to store your
|
|||||||
code, then run the command ``django-admin.py startproject mysite``. This
|
code, then run the command ``django-admin.py startproject mysite``. This
|
||||||
will create a ``mysite`` directory in your current directory.
|
will create a ``mysite`` directory in your current directory.
|
||||||
|
|
||||||
.. admonition:: Max OS X permissions
|
.. admonition:: Mac OS X permissions
|
||||||
|
|
||||||
If you're using Mac OS X, you may see the message "permission
|
If you're using Mac OS X, you may see the message "permission
|
||||||
denied" when you try to run ``django-admin.py startproject``. This
|
denied" when you try to run ``django-admin.py startproject``. This
|
||||||
|
@ -14,6 +14,7 @@ class FieldErrors(models.Model):
|
|||||||
choices = models.CharField(max_length=10, choices='bad')
|
choices = models.CharField(max_length=10, choices='bad')
|
||||||
choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
|
choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
|
||||||
index = models.CharField(max_length=10, db_index='bad')
|
index = models.CharField(max_length=10, db_index='bad')
|
||||||
|
field_ = models.CharField(max_length=10)
|
||||||
|
|
||||||
class Target(models.Model):
|
class Target(models.Model):
|
||||||
tgt_safe = models.CharField(max_length=10)
|
tgt_safe = models.CharField(max_length=10)
|
||||||
@ -116,6 +117,7 @@ invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tup
|
|||||||
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
||||||
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples.
|
||||||
invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
|
invalid_models.fielderrors: "index": "db_index" should be either None, True or False.
|
||||||
|
invalid_models.fielderrors: "field_": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.
|
||||||
invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
|
invalid_models.clash1: Accessor for field 'foreign' clashes with field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
|
||||||
invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
|
invalid_models.clash1: Accessor for field 'foreign' clashes with related m2m field 'Target.clash1_set'. Add a related_name argument to the definition for 'foreign'.
|
||||||
invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.
|
invalid_models.clash1: Reverse query name for field 'foreign' clashes with field 'Target.clash1'. Add a related_name argument to the definition for 'foreign'.
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
"""
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # Python 2.3 fallback
|
||||||
|
|
||||||
|
__test__ = {'API_TESTS': """
|
||||||
>>> from django.contrib.auth.models import User, Group, Permission
|
>>> from django.contrib.auth.models import User, Group, Permission
|
||||||
>>> from django.contrib.contenttypes.models import ContentType
|
>>> from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
@ -28,10 +33,10 @@ False
|
|||||||
# reloading user to purge the _perm_cache
|
# reloading user to purge the _perm_cache
|
||||||
|
|
||||||
>>> user = User.objects.get(username="test")
|
>>> user = User.objects.get(username="test")
|
||||||
>>> user.get_all_permissions()
|
>>> user.get_all_permissions() == set([u'auth.test'])
|
||||||
set([u'auth.test'])
|
True
|
||||||
>>> user.get_group_permissions()
|
>>> user.get_group_permissions() == set([])
|
||||||
set([])
|
True
|
||||||
>>> user.has_module_perms("Group")
|
>>> user.has_module_perms("Group")
|
||||||
False
|
False
|
||||||
>>> user.has_module_perms("auth")
|
>>> user.has_module_perms("auth")
|
||||||
@ -43,8 +48,8 @@ True
|
|||||||
>>> user.user_permissions.add(perm)
|
>>> user.user_permissions.add(perm)
|
||||||
>>> user.save()
|
>>> user.save()
|
||||||
>>> user = User.objects.get(username="test")
|
>>> user = User.objects.get(username="test")
|
||||||
>>> user.get_all_permissions()
|
>>> user.get_all_permissions() == set([u'auth.test2', u'auth.test', u'auth.test3'])
|
||||||
set([u'auth.test2', u'auth.test', u'auth.test3'])
|
True
|
||||||
>>> user.has_perm('test')
|
>>> user.has_perm('test')
|
||||||
False
|
False
|
||||||
>>> user.has_perm('auth.test')
|
>>> user.has_perm('auth.test')
|
||||||
@ -57,10 +62,11 @@ True
|
|||||||
>>> group.save()
|
>>> group.save()
|
||||||
>>> user.groups.add(group)
|
>>> user.groups.add(group)
|
||||||
>>> user = User.objects.get(username="test")
|
>>> user = User.objects.get(username="test")
|
||||||
>>> user.get_all_permissions()
|
>>> exp = set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
|
||||||
set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
|
>>> user.get_all_permissions() == exp
|
||||||
>>> user.get_group_permissions()
|
True
|
||||||
set([u'auth.test_group'])
|
>>> user.get_group_permissions() == set([u'auth.test_group'])
|
||||||
|
True
|
||||||
>>> user.has_perms(['auth.test3', 'auth.test_group'])
|
>>> user.has_perms(['auth.test3', 'auth.test_group'])
|
||||||
True
|
True
|
||||||
"""
|
"""}
|
||||||
|
6
tests/regressiontests/cache/tests.py
vendored
6
tests/regressiontests/cache/tests.py
vendored
@ -19,6 +19,12 @@ class Cache(unittest.TestCase):
|
|||||||
cache.set("key", "value")
|
cache.set("key", "value")
|
||||||
self.assertEqual(cache.get("key"), "value")
|
self.assertEqual(cache.get("key"), "value")
|
||||||
|
|
||||||
|
def test_add(self):
|
||||||
|
# test add (only add if key isn't already in cache)
|
||||||
|
cache.add("addkey1", "value")
|
||||||
|
cache.add("addkey1", "newvalue")
|
||||||
|
self.assertEqual(cache.get("addkey1"), "value")
|
||||||
|
|
||||||
def test_non_existent(self):
|
def test_non_existent(self):
|
||||||
# get with non-existent keys
|
# get with non-existent keys
|
||||||
self.assertEqual(cache.get("does_not_exist"), None)
|
self.assertEqual(cache.get("does_not_exist"), None)
|
||||||
|
@ -54,6 +54,17 @@
|
|||||||
True
|
True
|
||||||
>>> print repr(d)
|
>>> print repr(d)
|
||||||
{'one': 'not one', 'two': 'two', 'three': 'three'}
|
{'one': 'not one', 'two': 'two', 'three': 'three'}
|
||||||
|
>>> d.pop('one', 'missing')
|
||||||
|
'not one'
|
||||||
|
>>> d.pop('one', 'missing')
|
||||||
|
'missing'
|
||||||
|
|
||||||
|
We don't know which item will be popped in popitem(), so we'll just check that
|
||||||
|
the number of keys has decreased.
|
||||||
|
>>> l = len(d)
|
||||||
|
>>> _ = d.popitem()
|
||||||
|
>>> l - len(d)
|
||||||
|
1
|
||||||
|
|
||||||
Init from sequence of tuples
|
Init from sequence of tuples
|
||||||
>>> d = SortedDict((
|
>>> d = SortedDict((
|
||||||
|
343
tests/regressiontests/forms/localflavor/es.py
Normal file
343
tests/regressiontests/forms/localflavor/es.py
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ ES form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# ESPostalCodeField ##############################################################
|
||||||
|
|
||||||
|
ESPostalCodeField validates that data is a five-digit spanish postal code.
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESPostalCodeField
|
||||||
|
>>> f = ESPostalCodeField()
|
||||||
|
>>> f.clean('08028')
|
||||||
|
u'08028'
|
||||||
|
>>> f.clean('28080')
|
||||||
|
u'28080'
|
||||||
|
>>> f.clean('53001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('0801')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('080001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('00999')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('08 01')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('08A01')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ESPostalCodeField(required=False)
|
||||||
|
>>> f.clean('08028')
|
||||||
|
u'08028'
|
||||||
|
>>> f.clean('28080')
|
||||||
|
u'28080'
|
||||||
|
>>> f.clean('53001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('0801')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('080001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('00999')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('08 01')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('08A01')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid postal code in the range and format 01XXX - 52XXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ESPhoneNumberField ##############################################################
|
||||||
|
|
||||||
|
ESPhoneNumberField validates that data is a nine-digit spanish phone number.
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESPhoneNumberField
|
||||||
|
>>> f = ESPhoneNumberField()
|
||||||
|
>>> f.clean('650010101')
|
||||||
|
u'650010101'
|
||||||
|
>>> f.clean('931234567')
|
||||||
|
u'931234567'
|
||||||
|
>>> f.clean('800123123')
|
||||||
|
u'800123123'
|
||||||
|
>>> f.clean('555555555')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('789789789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('99123123')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('9999123123')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ESPhoneNumberField(required=False)
|
||||||
|
>>> f.clean('650010101')
|
||||||
|
u'650010101'
|
||||||
|
>>> f.clean('931234567')
|
||||||
|
u'931234567'
|
||||||
|
>>> f.clean('800123123')
|
||||||
|
u'800123123'
|
||||||
|
>>> f.clean('555555555')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('789789789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('99123123')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('9999123123')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number in one of the formats 6XXXXXXXX, 8XXXXXXXX or 9XXXXXXXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ESIdentityCardNumberField ##############################################################
|
||||||
|
|
||||||
|
ESIdentityCardNumberField validates that data is a identification spanish code for companies or individuals (CIF, NIF or NIE).
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESIdentityCardNumberField
|
||||||
|
>>> f = ESIdentityCardNumberField()
|
||||||
|
>>> f.clean('78699688J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688-J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688 J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688 j')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688T')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for NIF.']
|
||||||
|
>>> f.clean('X0901797J')
|
||||||
|
'X0901797J'
|
||||||
|
>>> f.clean('X-6124387-Q')
|
||||||
|
'X6124387Q'
|
||||||
|
>>> f.clean('X 0012953 G')
|
||||||
|
'X0012953G'
|
||||||
|
>>> f.clean('x-3287690-r')
|
||||||
|
'X3287690R'
|
||||||
|
>>> f.clean('t-03287690r')
|
||||||
|
'T03287690R'
|
||||||
|
>>> f.clean('X-03287690')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('X-03287690-T')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for NIE.']
|
||||||
|
>>> f.clean('B38790911')
|
||||||
|
'B38790911'
|
||||||
|
>>> f.clean('B-3879091A')
|
||||||
|
'B3879091A'
|
||||||
|
>>> f.clean('B 38790917')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for CIF.']
|
||||||
|
>>> f.clean('B 38790911')
|
||||||
|
'B38790911'
|
||||||
|
>>> f.clean('P-3900800-H')
|
||||||
|
'P3900800H'
|
||||||
|
>>> f.clean('P 39008008')
|
||||||
|
'P39008008'
|
||||||
|
>>> f.clean('C-28795565')
|
||||||
|
'C28795565'
|
||||||
|
>>> f.clean('C 2879556E')
|
||||||
|
'C2879556E'
|
||||||
|
>>> f.clean('C28795567')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for CIF.']
|
||||||
|
>>> f.clean('I38790911')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('78699688-2')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ESIdentityCardNumberField(required=False)
|
||||||
|
>>> f.clean('78699688J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688-J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688 J')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688 j')
|
||||||
|
'78699688J'
|
||||||
|
>>> f.clean('78699688T')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for NIF.']
|
||||||
|
>>> f.clean('X0901797J')
|
||||||
|
'X0901797J'
|
||||||
|
>>> f.clean('X-6124387-Q')
|
||||||
|
'X6124387Q'
|
||||||
|
>>> f.clean('X 0012953 G')
|
||||||
|
'X0012953G'
|
||||||
|
>>> f.clean('x-3287690-r')
|
||||||
|
'X3287690R'
|
||||||
|
>>> f.clean('t-03287690r')
|
||||||
|
'T03287690R'
|
||||||
|
>>> f.clean('X-03287690')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('X-03287690-T')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for NIE.']
|
||||||
|
>>> f.clean('B38790911')
|
||||||
|
'B38790911'
|
||||||
|
>>> f.clean('B-3879091A')
|
||||||
|
'B3879091A'
|
||||||
|
>>> f.clean('B 38790917')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for CIF.']
|
||||||
|
>>> f.clean('B 38790911')
|
||||||
|
'B38790911'
|
||||||
|
>>> f.clean('P-3900800-H')
|
||||||
|
'P3900800H'
|
||||||
|
>>> f.clean('P 39008008')
|
||||||
|
'P39008008'
|
||||||
|
>>> f.clean('C-28795565')
|
||||||
|
'C28795565'
|
||||||
|
>>> f.clean('C 2879556E')
|
||||||
|
'C2879556E'
|
||||||
|
>>> f.clean('C28795567')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for CIF.']
|
||||||
|
>>> f.clean('I38790911')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('78699688-2')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid NIF, NIE, or CIF.']
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ESCCCField ##############################################################
|
||||||
|
|
||||||
|
ESCCCField validates that data is a spanish bank account number (codigo cuenta cliente).
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESCCCField
|
||||||
|
>>> f = ESCCCField()
|
||||||
|
>>> f.clean('20770338793100254321')
|
||||||
|
'20770338793100254321'
|
||||||
|
>>> f.clean('2077 0338 79 3100254321')
|
||||||
|
'2077 0338 79 3100254321'
|
||||||
|
>>> f.clean('2077-0338-79-3100254321')
|
||||||
|
'2077-0338-79-3100254321'
|
||||||
|
>>> f.clean('2077.0338.79.3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.']
|
||||||
|
>>> f.clean('2077-0338-78-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for bank account number.']
|
||||||
|
>>> f.clean('2077-0338-89-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for bank account number.']
|
||||||
|
>>> f.clean('2077-03-3879-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ESCCCField(required=False)
|
||||||
|
>>> f.clean('20770338793100254321')
|
||||||
|
'20770338793100254321'
|
||||||
|
>>> f.clean('2077 0338 79 3100254321')
|
||||||
|
'2077 0338 79 3100254321'
|
||||||
|
>>> f.clean('2077-0338-79-3100254321')
|
||||||
|
'2077-0338-79-3100254321'
|
||||||
|
>>> f.clean('2077.0338.79.3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.']
|
||||||
|
>>> f.clean('2077-0338-78-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for bank account number.']
|
||||||
|
>>> f.clean('2077-0338-89-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid checksum for bank account number.']
|
||||||
|
>>> f.clean('2077-03-3879-3100254321')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Please enter a valid bank account number in format XXXX-XXXX-XX-XXXXXXXXXX.']
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ESRegionSelect ##############################################################
|
||||||
|
|
||||||
|
ESRegionSelect is a Select widget that uses a list of Spain regions as its choices.
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESRegionSelect
|
||||||
|
>>> w = ESRegionSelect()
|
||||||
|
>>> w.render('regions', 'CT')
|
||||||
|
u'<select name="regions">\n<option value="AN">Andalusia</option>\n<option value="AR">Aragon</option>\n<option value="O">Principality of Asturias</option>\n<option value="IB">Balearic Islands</option>\n<option value="PV">Basque Country</option>\n<option value="CN">Canary Islands</option>\n<option value="S">Cantabria</option>\n<option value="CM">Castile-La Mancha</option>\n<option value="CL">Castile and Leon</option>\n<option value="CT" selected="selected">Catalonia</option>\n<option value="EX">Extremadura</option>\n<option value="GA">Galicia</option>\n<option value="LO">La Rioja</option>\n<option value="M">Madrid</option>\n<option value="MU">Region of Murcia</option>\n<option value="NA">Foral Community of Navarre</option>\n<option value="VC">Valencian Community</option>\n</select>'
|
||||||
|
|
||||||
|
# ESProvincenSelect ##############################################################
|
||||||
|
|
||||||
|
ESProvinceSelect is a Select widget that uses a list of Spain provinces as its choices.
|
||||||
|
>>> from django.contrib.localflavor.es.forms import ESProvinceSelect
|
||||||
|
>>> w = ESProvinceSelect()
|
||||||
|
>>> w.render('provinces', '08')
|
||||||
|
u'<select name="provinces">\n<option value="01">Arava</option>\n<option value="02">Albacete</option>\n<option value="03">Alacant</option>\n<option value="04">Almeria</option>\n<option value="05">Avila</option>\n<option value="06">Badajoz</option>\n<option value="07">Illes Balears</option>\n<option value="08" selected="selected">Barcelona</option>\n<option value="09">Burgos</option>\n<option value="10">Caceres</option>\n<option value="11">Cadiz</option>\n<option value="12">Castello</option>\n<option value="13">Ciudad Real</option>\n<option value="14">Cordoba</option>\n<option value="15">A Coruna</option>\n<option value="16">Cuenca</option>\n<option value="17">Girona</option>\n<option value="18">Granada</option>\n<option value="19">Guadalajara</option>\n<option value="20">Guipuzkoa</option>\n<option value="21">Huelva</option>\n<option value="22">Huesca</option>\n<option value="23">Jaen</option>\n<option value="24">Leon</option>\n<option value="25">Lleida</option>\n<option value="26">La Rioja</option>\n<option value="27">Lugo</option>\n<option value="28">Madrid</option>\n<option value="29">Malaga</option>\n<option value="30">Murcia</option>\n<option value="31">Navarre</option>\n<option value="32">Ourense</option>\n<option value="33">Asturias</option>\n<option value="34">Palencia</option>\n<option value="35">Las Palmas</option>\n<option value="36">Pontevedra</option>\n<option value="37">Salamanca</option>\n<option value="38">Santa Cruz de Tenerife</option>\n<option value="39">Cantabria</option>\n<option value="40">Segovia</option>\n<option value="41">Seville</option>\n<option value="42">Soria</option>\n<option value="43">Tarragona</option>\n<option value="44">Teruel</option>\n<option value="45">Toledo</option>\n<option value="46">Valencia</option>\n<option value="47">Valladolid</option>\n<option value="48">Bizkaia</option>\n<option value="49">Zamora</option>\n<option value="50">Zaragoza</option>\n<option value="51">Ceuta</option>\n<option value="52">Melilla</option>\n</select>'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
@ -35,10 +35,14 @@ u'41-403'
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
|
ValidationError: [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
|
||||||
>>> f.clean('43-34-234-323')
|
>>> f.clean('64-62-414-124')
|
||||||
u'43-34-234-323'
|
u'6462414124'
|
||||||
>>> f.clean('433-344-24-23')
|
>>> f.clean('646-241-41-24')
|
||||||
u'433-344-24-23'
|
u'6462414124'
|
||||||
|
>>> f.clean('646-241-41-23')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Wrong checksum for the Tax Number (NIP).']
|
||||||
|
|
||||||
# PLNationalIdentificationNumberField ############################################
|
# PLNationalIdentificationNumberField ############################################
|
||||||
|
|
||||||
@ -58,4 +62,20 @@ ValidationError: [u'National Identification Number consists of 11 digits.']
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'National Identification Number consists of 11 digits.']
|
ValidationError: [u'National Identification Number consists of 11 digits.']
|
||||||
|
|
||||||
|
# PLNationalBusinessRegisterField ################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.pl.forms import PLNationalBusinessRegisterField
|
||||||
|
>>> f = PLNationalBusinessRegisterField()
|
||||||
|
>>> f.clean('590096454')
|
||||||
|
u'590096454'
|
||||||
|
>>> f.clean('590096453')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Wrong checksum for the National Business Register Number (REGON).']
|
||||||
|
>>> f.clean('590096')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'National Business Register Number (REGON) consists of 7 or 9 digits.']
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class BoundaryModel(models.Model):
|
class BoundaryModel(models.Model):
|
||||||
positive_integer = models.PositiveIntegerField(null=True, blank=True)
|
positive_integer = models.PositiveIntegerField(null=True, blank=True)
|
||||||
|
|
||||||
|
class Defaults(models.Model):
|
||||||
|
name = models.CharField(max_length=256, default='class default value')
|
||||||
|
def_date = models.DateField(default = datetime.date(1980, 1, 1))
|
||||||
|
value = models.IntegerField(default=42)
|
||||||
|
|
||||||
__test__ = {'API_TESTS': """
|
__test__ = {'API_TESTS': """
|
||||||
>>> from django.newforms import form_for_model
|
>>> from django.newforms import form_for_model, form_for_instance
|
||||||
|
|
||||||
# Boundary conditions on a PostitiveIntegerField #########################
|
# Boundary conditions on a PostitiveIntegerField #########################
|
||||||
>>> BoundaryForm = form_for_model(BoundaryModel)
|
>>> BoundaryForm = form_for_model(BoundaryModel)
|
||||||
@ -18,4 +25,25 @@ True
|
|||||||
>>> f.is_valid()
|
>>> f.is_valid()
|
||||||
False
|
False
|
||||||
|
|
||||||
|
# Formfield initial values ########
|
||||||
|
If the model has default values for some fields, they are used as the formfield
|
||||||
|
initial values.
|
||||||
|
>>> DefaultsForm = form_for_model(Defaults)
|
||||||
|
>>> DefaultsForm().fields['name'].initial
|
||||||
|
u'class default value'
|
||||||
|
>>> DefaultsForm().fields['def_date'].initial
|
||||||
|
datetime.date(1980, 1, 1)
|
||||||
|
>>> DefaultsForm().fields['value'].initial
|
||||||
|
42
|
||||||
|
|
||||||
|
In form_for_instance(), the initial values come from the instance's values, not
|
||||||
|
the model's defaults.
|
||||||
|
>>> foo_instance = Defaults(name=u'instance value', def_date = datetime.date(1969, 4, 4), value = 12)
|
||||||
|
>>> InstanceForm = form_for_instance(foo_instance)
|
||||||
|
>>> InstanceForm().fields['name'].initial
|
||||||
|
u'instance value'
|
||||||
|
>>> InstanceForm().fields['def_date'].initial
|
||||||
|
datetime.date(1969, 4, 4)
|
||||||
|
>>> InstanceForm().fields['value'].initial
|
||||||
|
12
|
||||||
"""}
|
"""}
|
@ -9,6 +9,7 @@ from localflavor.ca import tests as localflavor_ca_tests
|
|||||||
from localflavor.ch import tests as localflavor_ch_tests
|
from localflavor.ch import tests as localflavor_ch_tests
|
||||||
from localflavor.cl import tests as localflavor_cl_tests
|
from localflavor.cl import tests as localflavor_cl_tests
|
||||||
from localflavor.de import tests as localflavor_de_tests
|
from localflavor.de import tests as localflavor_de_tests
|
||||||
|
from localflavor.es import tests as localflavor_es_tests
|
||||||
from localflavor.fi import tests as localflavor_fi_tests
|
from localflavor.fi import tests as localflavor_fi_tests
|
||||||
from localflavor.fr import tests as localflavor_fr_tests
|
from localflavor.fr import tests as localflavor_fr_tests
|
||||||
from localflavor.generic import tests as localflavor_generic_tests
|
from localflavor.generic import tests as localflavor_generic_tests
|
||||||
@ -35,6 +36,7 @@ __test__ = {
|
|||||||
'localflavor_ch_tests': localflavor_ch_tests,
|
'localflavor_ch_tests': localflavor_ch_tests,
|
||||||
'localflavor_cl_tests': localflavor_cl_tests,
|
'localflavor_cl_tests': localflavor_cl_tests,
|
||||||
'localflavor_de_tests': localflavor_de_tests,
|
'localflavor_de_tests': localflavor_de_tests,
|
||||||
|
'localflavor_es_tests': localflavor_es_tests,
|
||||||
'localflavor_fi_tests': localflavor_fi_tests,
|
'localflavor_fi_tests': localflavor_fi_tests,
|
||||||
'localflavor_fr_tests': localflavor_fr_tests,
|
'localflavor_fr_tests': localflavor_fr_tests,
|
||||||
'localflavor_generic_tests': localflavor_generic_tests,
|
'localflavor_generic_tests': localflavor_generic_tests,
|
||||||
|
@ -276,6 +276,12 @@ u'<input type="checkbox" name="greeting" />'
|
|||||||
>>> w.render('greeting', None)
|
>>> w.render('greeting', None)
|
||||||
u'<input type="checkbox" name="greeting" />'
|
u'<input type="checkbox" name="greeting" />'
|
||||||
|
|
||||||
|
The CheckboxInput widget will return False if the key is not found in the data
|
||||||
|
dictionary (because HTML form submission doesn't send any result for unchecked
|
||||||
|
checkboxes).
|
||||||
|
>>> w.value_from_datadict({}, {}, 'testing')
|
||||||
|
False
|
||||||
|
|
||||||
# Select Widget ###############################################################
|
# Select Widget ###############################################################
|
||||||
|
|
||||||
>>> w = Select()
|
>>> w = Select()
|
||||||
@ -845,4 +851,21 @@ included on both widgets.
|
|||||||
>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
|
>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
|
||||||
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
|
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
|
||||||
u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />'
|
u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />'
|
||||||
|
|
||||||
|
# DateTimeInput ###############################################################
|
||||||
|
|
||||||
|
>>> w = DateTimeInput()
|
||||||
|
>>> w.render('date', None)
|
||||||
|
u'<input type="text" name="date" />'
|
||||||
|
>>> d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
|
||||||
|
>>> print d
|
||||||
|
2007-09-17 12:51:34.482548
|
||||||
|
|
||||||
|
The microseconds are trimmed on display, by default.
|
||||||
|
>>> w.render('date', d)
|
||||||
|
u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
|
||||||
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34))
|
||||||
|
u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
|
||||||
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||||
|
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
|
||||||
"""
|
"""
|
||||||
|
57
tests/regressiontests/i18n/misc.py
Normal file
57
tests/regressiontests/i18n/misc.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
tests = """
|
||||||
|
>>> from django.utils.translation.trans_real import parse_accept_lang_header
|
||||||
|
>>> p = parse_accept_lang_header
|
||||||
|
|
||||||
|
Good headers.
|
||||||
|
>>> p('de')
|
||||||
|
[('de', 1.0)]
|
||||||
|
>>> p('en-AU')
|
||||||
|
[('en-AU', 1.0)]
|
||||||
|
>>> p('*;q=1.00')
|
||||||
|
[('*', 1.0)]
|
||||||
|
>>> p('en-AU;q=0.123')
|
||||||
|
[('en-AU', 0.123)]
|
||||||
|
>>> p('en-au;q=0.1')
|
||||||
|
[('en-au', 0.10000000000000001)]
|
||||||
|
>>> p('en-au;q=1.0')
|
||||||
|
[('en-au', 1.0)]
|
||||||
|
>>> p('da, en-gb;q=0.25, en;q=0.5')
|
||||||
|
[('da', 1.0), ('en', 0.5), ('en-gb', 0.25)]
|
||||||
|
>>> p('en-au-xx')
|
||||||
|
[('en-au-xx', 1.0)]
|
||||||
|
>>> p('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125')
|
||||||
|
[('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)]
|
||||||
|
>>> p('*')
|
||||||
|
[('*', 1.0)]
|
||||||
|
>>> p('de;q=0.')
|
||||||
|
[('de', 1.0)]
|
||||||
|
>>> p('')
|
||||||
|
[]
|
||||||
|
|
||||||
|
Bad headers; should always return [].
|
||||||
|
>>> p('en-gb;q=1.0000')
|
||||||
|
[]
|
||||||
|
>>> p('en;q=0.1234')
|
||||||
|
[]
|
||||||
|
>>> p('en;q=.2')
|
||||||
|
[]
|
||||||
|
>>> p('abcdefghi-au')
|
||||||
|
[]
|
||||||
|
>>> p('**')
|
||||||
|
[]
|
||||||
|
>>> p('en,,gb')
|
||||||
|
[]
|
||||||
|
>>> p('en-au;q=0.1.0')
|
||||||
|
[]
|
||||||
|
>>> p('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZ,en')
|
||||||
|
[]
|
||||||
|
>>> p('da, en-gb;q=0.8, en;q=0.7,#')
|
||||||
|
[]
|
||||||
|
>>> p('de;q=2.0')
|
||||||
|
[]
|
||||||
|
>>> p('de;q=0.a')
|
||||||
|
[]
|
||||||
|
>>> p('')
|
||||||
|
[]
|
||||||
|
|
||||||
|
"""
|
@ -1,6 +1,7 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
import misc
|
||||||
|
|
||||||
ur"""
|
regressions = ur"""
|
||||||
Format string interpolation should work with *_lazy objects.
|
Format string interpolation should work with *_lazy objects.
|
||||||
|
|
||||||
>>> from django.utils.translation import ugettext_lazy, activate, deactivate, gettext_lazy
|
>>> from django.utils.translation import ugettext_lazy, activate, deactivate, gettext_lazy
|
||||||
@ -39,3 +40,8 @@ unicode(string_concat(...)) should not raise a TypeError - #4796
|
|||||||
>>> unicode(django.utils.translation.string_concat("dja", "ngo"))
|
>>> unicode(django.utils.translation.string_concat("dja", "ngo"))
|
||||||
u'django'
|
u'django'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
__test__ = {
|
||||||
|
'regressions': regressions,
|
||||||
|
'misc': misc.tests,
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@ from datetime import datetime, timedelta
|
|||||||
from django import template
|
from django import template
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.template.loaders import app_directories, filesystem
|
from django.template.loaders import app_directories, filesystem
|
||||||
from django.utils.translation import activate, deactivate, install, ugettext as _
|
from django.utils.translation import activate, deactivate, ugettext as _
|
||||||
from django.utils.tzinfo import LocalTimezone
|
from django.utils.tzinfo import LocalTimezone
|
||||||
|
|
||||||
from unicode import unicode_tests
|
from unicode import unicode_tests
|
||||||
@ -341,7 +341,10 @@ class Templates(unittest.TestCase):
|
|||||||
'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
|
'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
|
||||||
'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
|
'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
|
||||||
'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'),
|
'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'),
|
||||||
'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError),
|
'firstof06': ('{% firstof a b c %}', {'b':0,'c':3}, '3'),
|
||||||
|
'firstof07': ('{% firstof a b "c" %}', {'a':0}, 'c'),
|
||||||
|
'firstof08': ('{% firstof a b "c and d" %}', {'a':0,'b':0}, 'c and d'),
|
||||||
|
'firstof09': ('{% firstof %}', {}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
### FOR TAG ###############################################################
|
### FOR TAG ###############################################################
|
||||||
'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
|
'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
|
||||||
@ -802,6 +805,20 @@ class Templates(unittest.TestCase):
|
|||||||
'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
|
'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail02' : ('{% url no_such_view %}', {}, ''),
|
'url-fail02' : ('{% url no_such_view %}', {}, ''),
|
||||||
'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
|
'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
|
||||||
|
|
||||||
|
### CACHE TAG ######################################################
|
||||||
|
'cache01' : ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
|
||||||
|
'cache02' : ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
|
||||||
|
'cache03' : ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
|
||||||
|
'cache04' : ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
|
||||||
|
'cache05' : ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
|
||||||
|
'cache06' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
|
||||||
|
'cache07' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'),
|
||||||
|
|
||||||
|
# Raise exception if we dont have at least 2 args, first one integer.
|
||||||
|
'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
|
'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
|
'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Register our custom template loader.
|
# Register our custom template loader.
|
||||||
@ -827,8 +844,6 @@ class Templates(unittest.TestCase):
|
|||||||
expected_invalid_str = 'INVALID'
|
expected_invalid_str = 'INVALID'
|
||||||
|
|
||||||
for name, vals in tests:
|
for name, vals in tests:
|
||||||
install()
|
|
||||||
|
|
||||||
if isinstance(vals[2], tuple):
|
if isinstance(vals[2], tuple):
|
||||||
normal_string_result = vals[2][0]
|
normal_string_result = vals[2][0]
|
||||||
invalid_string_result = vals[2][1]
|
invalid_string_result = vals[2][1]
|
||||||
|
@ -20,8 +20,12 @@ friends'
|
|||||||
>>> from django.utils.http import urlquote, urlquote_plus
|
>>> from django.utils.http import urlquote, urlquote_plus
|
||||||
>>> urlquote(u'Paris & Orl\xe9ans')
|
>>> urlquote(u'Paris & Orl\xe9ans')
|
||||||
u'Paris%20%26%20Orl%C3%A9ans'
|
u'Paris%20%26%20Orl%C3%A9ans'
|
||||||
|
>>> urlquote(u'Paris & Orl\xe9ans', safe="&")
|
||||||
|
u'Paris%20&%20Orl%C3%A9ans'
|
||||||
>>> urlquote_plus(u'Paris & Orl\xe9ans')
|
>>> urlquote_plus(u'Paris & Orl\xe9ans')
|
||||||
u'Paris+%26+Orl%C3%A9ans'
|
u'Paris+%26+Orl%C3%A9ans'
|
||||||
|
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
|
||||||
|
u'Paris+&+Orl%C3%A9ans'
|
||||||
|
|
||||||
### iri_to_uri ###########################################################
|
### iri_to_uri ###########################################################
|
||||||
>>> from django.utils.encoding import iri_to_uri
|
>>> from django.utils.encoding import iri_to_uri
|
||||||
|
@ -4,7 +4,7 @@ Tests for django.utils.
|
|||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from django.utils import html
|
from django.utils import html, checksums
|
||||||
|
|
||||||
from timesince import timesince_tests
|
from timesince import timesince_tests
|
||||||
|
|
||||||
@ -116,6 +116,32 @@ class TestUtilsHtml(TestCase):
|
|||||||
for value, output in items:
|
for value, output in items:
|
||||||
self.check_output(f, value, output)
|
self.check_output(f, value, output)
|
||||||
|
|
||||||
|
class TestUtilsChecksums(TestCase):
|
||||||
|
|
||||||
|
def check_output(self, function, value, output=None):
|
||||||
|
"""
|
||||||
|
Check that function(value) equals output. If output is None,
|
||||||
|
check that function(value) equals value.
|
||||||
|
"""
|
||||||
|
if output is None:
|
||||||
|
output = value
|
||||||
|
self.assertEqual(function(value), output)
|
||||||
|
|
||||||
|
def test_luhn(self):
|
||||||
|
f = checksums.luhn
|
||||||
|
items = (
|
||||||
|
(4111111111111111, True), ('4111111111111111', True),
|
||||||
|
(4222222222222, True), (378734493671000, True),
|
||||||
|
(5424000000000015, True), (5555555555554444, True),
|
||||||
|
(1008, True), ('0000001008', True), ('000000001008', True),
|
||||||
|
(4012888888881881, True), (1234567890123456789012345678909, True),
|
||||||
|
(4111111111211111, False), (42222222222224, False),
|
||||||
|
(100, False), ('100', False), ('0000100', False),
|
||||||
|
('abc', False), (None, False), (object(), False),
|
||||||
|
)
|
||||||
|
for value, output in items:
|
||||||
|
self.check_output(f, value, output)
|
||||||
|
|
||||||
__test__ = {
|
__test__ = {
|
||||||
'timesince_tests': timesince_tests,
|
'timesince_tests': timesince_tests,
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
old_root_urlconf = settings.ROOT_URLCONF
|
old_root_urlconf = settings.ROOT_URLCONF
|
||||||
old_template_dirs = settings.TEMPLATE_DIRS
|
old_template_dirs = settings.TEMPLATE_DIRS
|
||||||
old_use_i18n = settings.USE_I18N
|
old_use_i18n = settings.USE_I18N
|
||||||
|
old_language_code = settings.LANGUAGE_CODE
|
||||||
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
||||||
|
|
||||||
# Redirect some settings for the duration of these tests.
|
# Redirect some settings for the duration of these tests.
|
||||||
@ -100,6 +101,7 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
settings.ROOT_URLCONF = 'urls'
|
settings.ROOT_URLCONF = 'urls'
|
||||||
settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
||||||
settings.USE_I18N = True
|
settings.USE_I18N = True
|
||||||
|
settings.LANGUAGE_CODE = 'en'
|
||||||
settings.MIDDLEWARE_CLASSES = (
|
settings.MIDDLEWARE_CLASSES = (
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
@ -151,6 +153,7 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
settings.ROOT_URLCONF = old_root_urlconf
|
settings.ROOT_URLCONF = old_root_urlconf
|
||||||
settings.TEMPLATE_DIRS = old_template_dirs
|
settings.TEMPLATE_DIRS = old_template_dirs
|
||||||
settings.USE_I18N = old_use_i18n
|
settings.USE_I18N = old_use_i18n
|
||||||
|
settings.LANGUAGE_CODE = old_language_code
|
||||||
settings.MIDDLEWARE_CLASSES = old_middleware_classes
|
settings.MIDDLEWARE_CLASSES = old_middleware_classes
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user