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
10
AUTHORS
10
AUTHORS
@ -49,7 +49,8 @@ answer newbie questions, and generally made Django that much better:
|
||||
andy@jadedplanet.net
|
||||
Fabrice Aneche <akh@nobugware.com>
|
||||
ant9000@netwise.it
|
||||
Florian Apolloner
|
||||
Florian Apolloner
|
||||
arien <regexbot@gmail.com>
|
||||
David Ascher <http://ascher.ca/>
|
||||
david@kazserve.org
|
||||
Arthur <avandorp@gmail.com>
|
||||
@ -169,6 +170,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Nagy Károly <charlie@rendszergazda.com>
|
||||
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
||||
Ian G. Kelly <ian.g.kelly@gmail.com>
|
||||
Thomas Kerpe <thomas@kerpe.net>
|
||||
Ben Khoo <khoobks@westnet.com.au>
|
||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||
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/>
|
||||
mccutchen@gmail.com
|
||||
michael.mcewan@gmail.com
|
||||
michal@plovarna.cz
|
||||
mikko@sorl.net
|
||||
Slawek Mikula <slawek dot mikula at gmail dot com>
|
||||
mitakummaa@gmail.com
|
||||
@ -256,13 +259,14 @@ answer newbie questions, and generally made Django that much better:
|
||||
Brian Ray <http://brianray.chipy.org/>
|
||||
remco@diji.biz
|
||||
rhettg@gmail.com
|
||||
ricardojbarrios@gmail.com
|
||||
Matt Riggott
|
||||
Henrique Romano <onaiort@gmail.com>
|
||||
Armin Ronacher
|
||||
Brian Rosner <brosner@gmail.com>
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
ryankanno
|
||||
Manuel Saelices <msaelices@yaco.es>
|
||||
Manuel Saelices <msaelices@yaco.es>
|
||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||
David Schein
|
||||
@ -270,6 +274,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
serbaut@gmail.com
|
||||
John Shaffer <jshaffer2112@gmail.com>
|
||||
Pete Shinners <pete@shinners.org>
|
||||
jason.sidabras@gmail.com
|
||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||
SmileyChris <smileychris@gmail.com>
|
||||
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>
|
||||
Maciej Wiśniowski <pigletto@gmail.com>
|
||||
wojtek
|
||||
Jason Yan <tailofthesun@gmail.com>
|
||||
ye7cakf02@sneakemail.com
|
||||
ymasuda@ethercube.com
|
||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||
|
@ -140,13 +140,3 @@ class UserSettingsHolder(object):
|
||||
|
||||
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'
|
||||
|
||||
# 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'
|
||||
|
||||
# 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_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_PATH = '/' # The path of the session cookie.
|
||||
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_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 ""
|
||||
"Project-Id-Version: Django Javascript 1.0\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"
|
||||
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
||||
"Language-Team: Django-I18N <django-i18n@googlegroups.com>\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"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
@ -44,8 +44,8 @@ msgstr "Seleccione los items a agregar y haga click en "
|
||||
msgid "Clear all"
|
||||
msgstr "Eliminar todos"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
@ -53,14 +53,14 @@ msgstr ""
|
||||
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Setiembre Octubre "
|
||||
"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
|
||||
msgid "S M T W T F 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:72
|
||||
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"
|
||||
"Report-Msgid-Bugs-To: \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"
|
||||
"Language-Team: Hrvatski jezik\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -28,7 +28,7 @@ msgstr "Unos za ovo polje je obavezan."
|
||||
#, python-format
|
||||
msgid "Ensure your text is less than %s character."
|
||||
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."
|
||||
|
||||
#: oldforms/__init__.py:413
|
||||
@ -398,62 +398,62 @@ msgstr "URL %s ne prikazuje ispravnu sliku."
|
||||
#: core/validators.py:196
|
||||
#, python-format
|
||||
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
|
||||
#, python-format
|
||||
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
|
||||
msgid "A valid URL is required."
|
||||
msgstr ""
|
||||
msgstr "Ispravan URL je obavezan."
|
||||
|
||||
#: core/validators.py:222
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Valid HTML is required. Specific errors are:\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
msgstr "Ispravan HTML je obavezan. Pogreške:<br> %s"
|
||||
|
||||
#: core/validators.py:229
|
||||
#, python-format
|
||||
msgid "Badly formed XML: %s"
|
||||
msgstr ""
|
||||
msgstr "Loše formatiran XML: %s"
|
||||
|
||||
#: core/validators.py:246
|
||||
#, python-format
|
||||
msgid "Invalid URL: %s"
|
||||
msgstr ""
|
||||
msgstr "Neispravan URL: %s"
|
||||
|
||||
#: core/validators.py:251 core/validators.py:253
|
||||
#, python-format
|
||||
msgid "The URL %s is a broken link."
|
||||
msgstr ""
|
||||
msgstr "URL %s je neispravan (broken) link."
|
||||
|
||||
#: core/validators.py:259
|
||||
msgid "Enter a valid U.S. state abbreviation."
|
||||
msgstr ""
|
||||
msgstr "Enter a valid U.S. state abbreviation."
|
||||
|
||||
#: core/validators.py:273
|
||||
#, python-format
|
||||
msgid "Watch your mouth! The word %s is not allowed here."
|
||||
msgid_plural "Watch your mouth! The words %s are not allowed here."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "Pazite na izražavanje! Riječ %s nije dopuštena."
|
||||
msgstr[1] "Pazite na izražavanje! Riječi %s nisu dopuštene."
|
||||
|
||||
#: core/validators.py:280
|
||||
#, python-format
|
||||
msgid "This field must match the '%s' field."
|
||||
msgstr ""
|
||||
msgstr "Ovo polje mora biti jednako %s polju."
|
||||
|
||||
#: core/validators.py:299
|
||||
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
|
||||
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
|
||||
#, python-format
|
||||
@ -463,7 +463,7 @@ msgstr ""
|
||||
#: core/validators.py:340
|
||||
#, python-format
|
||||
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
|
||||
msgid "Duplicate values are not allowed."
|
||||
@ -471,28 +471,27 @@ msgstr ""
|
||||
|
||||
#: core/validators.py:374
|
||||
#, python-format
|
||||
#, fuzzy
|
||||
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
|
||||
#, python-format
|
||||
msgid "This value must be at least %s."
|
||||
msgstr ""
|
||||
msgstr "Vrijednost mora biti bar %s."
|
||||
|
||||
#: core/validators.py:378
|
||||
#, python-format
|
||||
msgid "This value must be no more than %s."
|
||||
msgstr ""
|
||||
msgstr "Vrijednost ne može biti veća od %s."
|
||||
|
||||
#: core/validators.py:414
|
||||
#, python-format
|
||||
msgid "This value must be a power of %s."
|
||||
msgstr ""
|
||||
msgstr "Ova vrijednost na kvadrat mora biti %s."
|
||||
|
||||
#: core/validators.py:424
|
||||
msgid "Please enter a valid decimal number."
|
||||
msgstr ""
|
||||
msgstr "Molim unesite ispravan decimalni broj."
|
||||
|
||||
#: core/validators.py:431
|
||||
#, python-format
|
||||
@ -1879,7 +1878,6 @@ msgid "Documentation bookmarklets"
|
||||
msgstr ""
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:9
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"\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"
|
||||
msgstr ""
|
||||
"\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
|
||||
msgid "Documentation for this page"
|
||||
msgstr ""
|
||||
msgstr "Dokumentacija za ovu stranicu"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:20
|
||||
msgid ""
|
||||
"Jumps you from any page to the documentation for the view that generates "
|
||||
"that page."
|
||||
msgstr ""
|
||||
msgstr "Preusmjeri te sa bilo koje stranice na dokumentaciju za taj prikaz (view) koji generira stranicu."
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:22
|
||||
msgid "Show object ID"
|
||||
msgstr ""
|
||||
msgstr "Prikaži ID objekta"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:23
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Shows the content-type and unique ID for pages that represent a single "
|
||||
"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
|
||||
msgid "Edit this object (current window)"
|
||||
msgstr ""
|
||||
msgstr "Uredi objekt (u trenutno prozoru)"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:26
|
||||
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
|
||||
msgid "Edit this object (new window)"
|
||||
msgstr ""
|
||||
msgstr "Uredi objekt (novi prozor)"
|
||||
|
||||
#: contrib/admin/templates/admin_doc/bookmarklets.html:29
|
||||
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
|
||||
msgid "python model class name"
|
||||
msgstr ""
|
||||
msgstr "ime klase (class) python modela"
|
||||
|
||||
#: contrib/contenttypes/models.py:40
|
||||
msgid "content type"
|
||||
msgstr ""
|
||||
msgstr "tip sadržaja"
|
||||
|
||||
#: contrib/contenttypes/models.py:41
|
||||
msgid "content types"
|
||||
msgstr ""
|
||||
msgstr "tipovi sadržaja"
|
||||
|
||||
#: contrib/auth/views.py:41
|
||||
msgid "Logged out"
|
||||
msgstr ""
|
||||
msgstr "Niste logirani"
|
||||
|
||||
#: contrib/auth/models.py:53 contrib/auth/models.py:73
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
msgstr "ime"
|
||||
|
||||
#: contrib/auth/models.py:55
|
||||
msgid "codename"
|
||||
msgstr ""
|
||||
msgstr "kodno ime"
|
||||
|
||||
#: contrib/auth/models.py:58
|
||||
msgid "permission"
|
||||
msgstr ""
|
||||
msgstr "privilegija"
|
||||
|
||||
#: contrib/auth/models.py:59 contrib/auth/models.py:74
|
||||
msgid "permissions"
|
||||
msgstr ""
|
||||
msgstr "privilegije"
|
||||
|
||||
#: contrib/auth/models.py:77
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
msgstr "grupa"
|
||||
|
||||
#: contrib/auth/models.py:78 contrib/auth/models.py:121
|
||||
msgid "groups"
|
||||
msgstr ""
|
||||
msgstr "grupe"
|
||||
|
||||
#: contrib/auth/models.py:111
|
||||
msgid "username"
|
||||
msgstr ""
|
||||
msgstr "korisničko ime"
|
||||
|
||||
#: contrib/auth/models.py:111
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
|
||||
"digits and underscores)."
|
||||
msgstr "i."
|
||||
msgstr "Obavezno 30 alfanumeričkih znakova ili manje (slova, brojevi i povlaka)."
|
||||
|
||||
#: contrib/auth/models.py:112
|
||||
msgid "first name"
|
||||
msgstr ""
|
||||
msgstr "ime"
|
||||
|
||||
#: contrib/auth/models.py:113
|
||||
msgid "last name"
|
||||
msgstr ""
|
||||
msgstr "prezime"
|
||||
|
||||
#: contrib/auth/models.py:114
|
||||
msgid "e-mail address"
|
||||
msgstr ""
|
||||
msgstr "e-mail adresa"
|
||||
|
||||
#: contrib/auth/models.py:115
|
||||
msgid "password"
|
||||
@ -2207,7 +2208,7 @@ msgstr ""
|
||||
|
||||
#: contrib/localflavor/de/de_states.py:17
|
||||
msgid "Saxony"
|
||||
msgstr ""
|
||||
msgstr "Saxony"
|
||||
|
||||
#: contrib/localflavor/de/de_states.py:18
|
||||
msgid "Saxony-Anhalt"
|
||||
@ -2899,306 +2900,305 @@ msgstr ""
|
||||
|
||||
#: contrib/localflavor/sk/sk_districts.py:85
|
||||
msgid "Ziar nad Hronom"
|
||||
msgstr ""
|
||||
msgstr "Ziar nad Hronom"
|
||||
|
||||
#: contrib/localflavor/sk/sk_districts.py:86
|
||||
msgid "Zilina"
|
||||
msgstr ""
|
||||
msgstr "Zilina"
|
||||
|
||||
#: contrib/localflavor/sk/forms.py:32
|
||||
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
|
||||
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
|
||||
msgid "Enter valid a Chilean RUT"
|
||||
msgstr ""
|
||||
msgstr "Unesi ispravan čileanski RUT"
|
||||
|
||||
#: contrib/localflavor/fi/forms.py:40 contrib/localflavor/fi/forms.py:45
|
||||
msgid "Enter a valid Finnish social security number."
|
||||
msgstr ""
|
||||
msgstr "Unesi ispravan finski broj socijalnog osiguranja."
|
||||
|
||||
#: contrib/sessions/models.py:68
|
||||
msgid "session key"
|
||||
msgstr ""
|
||||
msgstr "session ključ (key)"
|
||||
|
||||
#: contrib/sessions/models.py:69
|
||||
msgid "session data"
|
||||
msgstr ""
|
||||
msgstr "session podaci"
|
||||
|
||||
#: contrib/sessions/models.py:70
|
||||
msgid "expire date"
|
||||
msgstr ""
|
||||
msgstr "ističe datuma"
|
||||
|
||||
#: contrib/sessions/models.py:74
|
||||
msgid "session"
|
||||
msgstr ""
|
||||
msgstr "session"
|
||||
|
||||
#: contrib/sessions/models.py:75
|
||||
msgid "sessions"
|
||||
msgstr ""
|
||||
msgstr "sessions"
|
||||
|
||||
#: contrib/flatpages/models.py:8
|
||||
#, fuzzy
|
||||
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
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
msgstr "naslov"
|
||||
|
||||
#: contrib/flatpages/models.py:10
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
msgstr "sadržaj"
|
||||
|
||||
#: contrib/flatpages/models.py:11
|
||||
msgid "enable comments"
|
||||
msgstr ""
|
||||
msgstr "uključi komentare"
|
||||
|
||||
#: contrib/flatpages/models.py:12
|
||||
msgid "template name"
|
||||
msgstr ""
|
||||
msgstr "ime template-a"
|
||||
|
||||
#: contrib/flatpages/models.py:13
|
||||
msgid ""
|
||||
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system "
|
||||
"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
|
||||
msgid "registration required"
|
||||
msgstr ""
|
||||
msgstr "registracija obavezna"
|
||||
|
||||
#: contrib/flatpages/models.py:14
|
||||
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
|
||||
msgid "flat page"
|
||||
msgstr ""
|
||||
msgstr "statična stranica"
|
||||
|
||||
#: contrib/flatpages/models.py:19
|
||||
msgid "flat pages"
|
||||
msgstr ""
|
||||
msgstr "statične stranice"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Monday"
|
||||
msgstr ""
|
||||
msgstr "Ponedjeljak"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Tuesday"
|
||||
msgstr ""
|
||||
msgstr "Utorak"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Wednesday"
|
||||
msgstr ""
|
||||
msgstr "Srijeda"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Thursday"
|
||||
msgstr ""
|
||||
msgstr "Četvrtak"
|
||||
|
||||
#: utils/dates.py:6
|
||||
msgid "Friday"
|
||||
msgstr ""
|
||||
msgstr "Petak"
|
||||
|
||||
#: utils/dates.py:7
|
||||
msgid "Saturday"
|
||||
msgstr ""
|
||||
msgstr "Subota"
|
||||
|
||||
#: utils/dates.py:7
|
||||
msgid "Sunday"
|
||||
msgstr ""
|
||||
msgstr "Nedjelja"
|
||||
|
||||
#: utils/dates.py:10
|
||||
msgid "Mon"
|
||||
msgstr ""
|
||||
msgstr "Pon"
|
||||
|
||||
#: utils/dates.py:10
|
||||
msgid "Tue"
|
||||
msgstr ""
|
||||
msgstr "Uto"
|
||||
|
||||
#: utils/dates.py:10
|
||||
msgid "Wed"
|
||||
msgstr ""
|
||||
msgstr "Sri"
|
||||
|
||||
#: utils/dates.py:10
|
||||
msgid "Thu"
|
||||
msgstr ""
|
||||
msgstr "Čet"
|
||||
|
||||
#: utils/dates.py:10
|
||||
msgid "Fri"
|
||||
msgstr ""
|
||||
msgstr "Pet"
|
||||
|
||||
#: utils/dates.py:11
|
||||
msgid "Sat"
|
||||
msgstr ""
|
||||
msgstr "Sub"
|
||||
|
||||
#: utils/dates.py:11
|
||||
msgid "Sun"
|
||||
msgstr ""
|
||||
msgstr "Ned"
|
||||
|
||||
#: utils/dates.py:18
|
||||
msgid "January"
|
||||
msgstr ""
|
||||
msgstr "Siječanj"
|
||||
|
||||
#: utils/dates.py:18
|
||||
msgid "February"
|
||||
msgstr ""
|
||||
msgstr "Veljača"
|
||||
|
||||
#: utils/dates.py:18 utils/dates.py:31
|
||||
msgid "March"
|
||||
msgstr ""
|
||||
msgstr "Ožujak"
|
||||
|
||||
#: utils/dates.py:18 utils/dates.py:31
|
||||
msgid "April"
|
||||
msgstr ""
|
||||
msgstr "Travanj"
|
||||
|
||||
#: utils/dates.py:18 utils/dates.py:31
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
msgstr "Svibanj"
|
||||
|
||||
#: utils/dates.py:18 utils/dates.py:31
|
||||
msgid "June"
|
||||
msgstr ""
|
||||
msgstr "Lipanj"
|
||||
|
||||
#: utils/dates.py:19 utils/dates.py:31
|
||||
msgid "July"
|
||||
msgstr ""
|
||||
msgstr "Srpanj"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "August"
|
||||
msgstr ""
|
||||
msgstr "Kolovoz"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "September"
|
||||
msgstr ""
|
||||
msgstr "Rujan"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "October"
|
||||
msgstr ""
|
||||
msgstr "Listopad"
|
||||
|
||||
#: utils/dates.py:19
|
||||
msgid "November"
|
||||
msgstr ""
|
||||
msgstr "Studeni"
|
||||
|
||||
#: utils/dates.py:20
|
||||
msgid "December"
|
||||
msgstr ""
|
||||
msgstr "Prosinac"
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "jan"
|
||||
msgstr ""
|
||||
msgstr "sij."
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "feb"
|
||||
msgstr ""
|
||||
msgstr "velj."
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "mar"
|
||||
msgstr ""
|
||||
msgstr "ožu."
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "apr"
|
||||
msgstr ""
|
||||
msgstr "tra."
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "may"
|
||||
msgstr ""
|
||||
msgstr "svi."
|
||||
|
||||
#: utils/dates.py:23
|
||||
msgid "jun"
|
||||
msgstr ""
|
||||
msgstr "lip."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "jul"
|
||||
msgstr ""
|
||||
msgstr "srp."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "aug"
|
||||
msgstr ""
|
||||
msgstr "kol."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "sep"
|
||||
msgstr ""
|
||||
msgstr "ruj."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "oct"
|
||||
msgstr ""
|
||||
msgstr "lis."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "nov"
|
||||
msgstr ""
|
||||
msgstr "stu."
|
||||
|
||||
#: utils/dates.py:24
|
||||
msgid "dec"
|
||||
msgstr ""
|
||||
msgstr "pro."
|
||||
|
||||
#: utils/dates.py:31
|
||||
msgid "Jan."
|
||||
msgstr ""
|
||||
msgstr "Sij."
|
||||
|
||||
#: utils/dates.py:31
|
||||
msgid "Feb."
|
||||
msgstr ""
|
||||
msgstr "Velj."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Aug."
|
||||
msgstr ""
|
||||
msgstr "Kol."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Sept."
|
||||
msgstr ""
|
||||
msgstr "Ruj."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Oct."
|
||||
msgstr ""
|
||||
msgstr "Lis."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Nov."
|
||||
msgstr ""
|
||||
msgstr "Stu."
|
||||
|
||||
#: utils/dates.py:32
|
||||
msgid "Dec."
|
||||
msgstr ""
|
||||
msgstr "Pro."
|
||||
|
||||
#: utils/timesince.py:12
|
||||
msgid "year"
|
||||
msgid_plural "years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "godina"
|
||||
msgstr[1] "godina"
|
||||
|
||||
#: utils/timesince.py:13
|
||||
msgid "month"
|
||||
msgid_plural "months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "mjesec"
|
||||
msgstr[1] "mjesec"
|
||||
|
||||
#: utils/timesince.py:14
|
||||
msgid "week"
|
||||
msgid_plural "weeks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "tjedan"
|
||||
msgstr[1] "tjedan"
|
||||
|
||||
#: utils/timesince.py:15
|
||||
msgid "day"
|
||||
msgid_plural "days"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "dan"
|
||||
msgstr[1] "dan"
|
||||
|
||||
#: utils/timesince.py:16
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "sati"
|
||||
msgstr[1] "sati"
|
||||
|
||||
#: utils/timesince.py:17
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "minute"
|
||||
msgstr[1] "minuta"
|
||||
|
||||
#: utils/timesince.py:39
|
||||
#, python-format
|
||||
@ -3228,7 +3228,7 @@ msgstr ""
|
||||
|
||||
#: utils/dateformat.py:97
|
||||
msgid "midnight"
|
||||
msgstr ""
|
||||
msgstr "ponoć"
|
||||
|
||||
#: utils/dateformat.py:99
|
||||
msgid "noon"
|
||||
@ -3256,7 +3256,7 @@ msgstr ""
|
||||
|
||||
#: template/defaultfilters.py:485
|
||||
msgid "yes,no,maybe"
|
||||
msgstr ""
|
||||
msgstr "da,ne,možda"
|
||||
|
||||
#: template/defaultfilters.py:514
|
||||
#, python-format
|
||||
|
@ -45,7 +45,14 @@ var UKRAINIAN_MAP = {
|
||||
}
|
||||
var CZECH_MAP = {
|
||||
'č':'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()
|
||||
@ -56,6 +63,7 @@ ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
|
||||
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
||||
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
|
||||
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
||||
ALL_DOWNCODE_MAPS[7]=POLISH_MAP
|
||||
|
||||
var Downcoder = new Object();
|
||||
Downcoder.Initialize = function()
|
||||
|
@ -4,7 +4,7 @@ from django.contrib.syndication.feeds import Feed
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
class LatestFreeCommentsFeed(Feed):
|
||||
"Feed of latest comments on the current site."
|
||||
"""Feed of latest free comments on the current site."""
|
||||
|
||||
comments_class = FreeComment
|
||||
|
||||
@ -30,7 +30,7 @@ class LatestFreeCommentsFeed(Feed):
|
||||
return self.get_query_set()[:40]
|
||||
|
||||
class LatestCommentsFeed(LatestFreeCommentsFeed):
|
||||
"""Feed of latest free comments on the current site"""
|
||||
"""Feed of latest comments on the current site."""
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from django.newforms import ValidationError
|
||||
from django.newforms.fields import Select, RegexField
|
||||
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.
|
||||
"""
|
||||
|
||||
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):
|
||||
super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
|
||||
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.'))
|
||||
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):
|
||||
"""
|
||||
A form field that validates as Polish Tax Number (NIP).
|
||||
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):
|
||||
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,
|
||||
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):
|
||||
"""
|
||||
|
@ -48,6 +48,7 @@ class SessionBase(object):
|
||||
return self._session.get(key, default)
|
||||
|
||||
def pop(self, key, *args):
|
||||
self.modified = self.modified or key in self._session
|
||||
return self._session.pop(key, *args)
|
||||
|
||||
def set_test_cookie(self):
|
||||
|
@ -31,7 +31,7 @@ class SessionMiddleware(object):
|
||||
else:
|
||||
max_age = settings.SESSION_COOKIE_AGE
|
||||
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
|
||||
|
||||
|
||||
# Fixed length date must have '-' separation in the format
|
||||
# DD-MMM-YYYY for compliance with Netscape cookie standard
|
||||
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
|
||||
@ -39,8 +39,10 @@ class SessionMiddleware(object):
|
||||
|
||||
# Save the seesion data and refresh the client cookie.
|
||||
request.session.save()
|
||||
response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key,
|
||||
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
secure=settings.SESSION_COOKIE_SECURE or None)
|
||||
|
||||
response.set_cookie(settings.SESSION_COOKIE_NAME,
|
||||
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)
|
||||
|
||||
return response
|
||||
|
@ -3,6 +3,7 @@ r"""
|
||||
>>> 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.file import SessionStore as FileSession
|
||||
>>> from django.contrib.sessions.backends.base import SessionBase
|
||||
|
||||
>>> db_session = DatabaseSession()
|
||||
>>> db_session.modified
|
||||
@ -52,6 +53,28 @@ True
|
||||
>>> cache_session.delete(cache_session.session_key)
|
||||
>>> cache_session.exists(cache_session.session_key)
|
||||
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__':
|
||||
|
@ -89,6 +89,7 @@ class Feed(object):
|
||||
categories = self.__get_dynamic_attr('categories', obj),
|
||||
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
||||
feed_guid = self.__get_dynamic_attr('feed_guid', obj),
|
||||
ttl = self.__get_dynamic_attr('ttl', obj),
|
||||
)
|
||||
|
||||
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
|
||||
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):
|
||||
"""
|
||||
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]))
|
||||
|
||||
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:
|
||||
timeout = self.default_timeout
|
||||
cursor = connection.cursor()
|
||||
@ -50,7 +56,7 @@ class CacheClass(BaseCache):
|
||||
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
|
||||
cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
|
||||
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])
|
||||
else:
|
||||
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):
|
||||
pass
|
||||
|
||||
def add(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def get(self, key, default=None):
|
||||
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._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):
|
||||
fname = self._key_to_file(key)
|
||||
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)
|
||||
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):
|
||||
should_delete = False
|
||||
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)
|
||||
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):
|
||||
val = self._cache.get(smart_str(key))
|
||||
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):
|
||||
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):
|
||||
now = time.time()
|
||||
exp = self._expire_info.get(key)
|
||||
|
@ -14,7 +14,7 @@ import os
|
||||
class ModPythonRequest(http.HttpRequest):
|
||||
def __init__(self, req):
|
||||
self._req = req
|
||||
self.path = force_unicode(req.uri, errors='ignore')
|
||||
self.path = force_unicode(req.uri)
|
||||
|
||||
def __repr__(self):
|
||||
# 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)
|
||||
|
||||
class ModPythonHandler(BaseHandler):
|
||||
request_class = ModPythonRequest
|
||||
|
||||
def __call__(self, req):
|
||||
# mod_python fakes the environ, and thus doesn't process SetEnv. This fixes that
|
||||
os.environ.update(req.subprocess_env)
|
||||
@ -150,13 +152,16 @@ class ModPythonHandler(BaseHandler):
|
||||
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
request = ModPythonRequest(req)
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
response = middleware_method(request, response)
|
||||
try:
|
||||
request = self.request_class(req)
|
||||
except UnicodeDecodeError:
|
||||
response = http.HttpResponseBadRequest()
|
||||
else:
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
response = middleware_method(request, response)
|
||||
finally:
|
||||
dispatcher.send(signal=signals.request_finished)
|
||||
|
||||
|
@ -75,7 +75,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
|
||||
class WSGIRequest(http.HttpRequest):
|
||||
def __init__(self, environ):
|
||||
self.environ = environ
|
||||
self.path = force_unicode(environ['PATH_INFO'], errors='ignore')
|
||||
self.path = force_unicode(environ['PATH_INFO'])
|
||||
self.META = environ
|
||||
self.method = environ['REQUEST_METHOD'].upper()
|
||||
|
||||
@ -165,7 +165,9 @@ class WSGIRequest(http.HttpRequest):
|
||||
content_length = int(self.environ.get('CONTENT_LENGTH', 0))
|
||||
except ValueError: # if CONTENT_LENGTH was empty string or not an integer
|
||||
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()
|
||||
buf.close()
|
||||
return self._raw_post_data
|
||||
@ -179,6 +181,7 @@ class WSGIRequest(http.HttpRequest):
|
||||
|
||||
class WSGIHandler(BaseHandler):
|
||||
initLock = Lock()
|
||||
request_class = WSGIRequest
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
from django.conf import settings
|
||||
@ -194,13 +197,16 @@ class WSGIHandler(BaseHandler):
|
||||
|
||||
dispatcher.send(signal=signals.request_started)
|
||||
try:
|
||||
request = WSGIRequest(environ)
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
response = middleware_method(request, response)
|
||||
try:
|
||||
request = self.request_class(environ)
|
||||
except UnicodeDecodeError:
|
||||
response = http.HttpResponseBadRequest()
|
||||
else:
|
||||
response = self.get_response(request)
|
||||
|
||||
# Apply response middleware
|
||||
for middleware_method in self._response_middleware:
|
||||
response = middleware_method(request, response)
|
||||
finally:
|
||||
dispatcher.send(signal=signals.request_finished)
|
||||
|
||||
|
@ -73,7 +73,7 @@ class SafeMIMEText(MIMEText):
|
||||
if '\n' in val or '\r' in val:
|
||||
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
||||
try:
|
||||
val = str(force_unicode(val))
|
||||
val = force_unicode(val).encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
if name.lower() in ('to', 'from', 'cc'):
|
||||
result = []
|
||||
@ -92,7 +92,7 @@ class SafeMIMEMultipart(MIMEMultipart):
|
||||
if '\n' in val or '\r' in val:
|
||||
raise BadHeaderError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
|
||||
try:
|
||||
val = str(force_unicode(val))
|
||||
val = force_unicode(val).encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
if name.lower() in ('to', 'from', 'cc'):
|
||||
result = []
|
||||
|
@ -1,31 +1,35 @@
|
||||
import django
|
||||
from django.core.management.base import BaseCommand, CommandError, handle_default_options
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
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.
|
||||
get_version = django.get_version
|
||||
|
||||
# A cache of loaded commands, so that call_command
|
||||
# A cache of loaded commands, so that call_command
|
||||
# doesn't have to reload every time it is called
|
||||
_commands = None
|
||||
|
||||
def find_commands(management_dir):
|
||||
"""
|
||||
Given a path to a management directory, return a list of all the command names
|
||||
that are available. Returns an empty list if no commands are defined.
|
||||
Given a path to a management directory, returns a list of all the command
|
||||
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:
|
||||
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:
|
||||
return []
|
||||
|
||||
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.
|
||||
|
||||
Raises ImportError if the management module cannot be found for any reason.
|
||||
@ -36,23 +40,23 @@ def find_management_module(app_name):
|
||||
path = None
|
||||
while parts:
|
||||
part = parts.pop()
|
||||
f,path,descr = find_module(part, path and [path] or None)
|
||||
f, path, descr = find_module(part, path and [path] or None)
|
||||
return path
|
||||
|
||||
|
||||
def load_command_class(app_name, name):
|
||||
"""
|
||||
Given a command name and an application name, returns the Command
|
||||
Given a command name and an application name, returns the Command
|
||||
class instance. All errors raised by the importation process
|
||||
(ImportError, AttributeError) are allowed to propagate.
|
||||
"""
|
||||
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
|
||||
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
|
||||
{}, {}, ['Command']), 'Command')()
|
||||
|
||||
def get_commands(load_user_commands=True, project_directory=None):
|
||||
"""
|
||||
Returns a dictionary of commands against the application in which
|
||||
those commands can be found. This works by looking for a
|
||||
management.commands package in django.core, and in each installed
|
||||
those commands can be found. This works by looking for a
|
||||
management.commands package in django.core, and in each installed
|
||||
application -- if a commands package exists, all commands in that
|
||||
package are registered.
|
||||
|
||||
@ -62,38 +66,38 @@ def get_commands(load_user_commands=True, project_directory=None):
|
||||
startapp command will be modified to use that directory.
|
||||
|
||||
The dictionary is in the format {command_name: app_name}. Key-value
|
||||
pairs from this dictionary can then be used in calls to
|
||||
pairs from this dictionary can then be used in calls to
|
||||
load_command_class(app_name, command_name)
|
||||
|
||||
|
||||
If a specific version of a command must be loaded (e.g., with the
|
||||
startapp command), the instantiated module can be placed in the
|
||||
dictionary in place of the application name.
|
||||
|
||||
|
||||
The dictionary is cached on the first call, and reused on subsequent
|
||||
calls.
|
||||
"""
|
||||
global _commands
|
||||
if _commands is None:
|
||||
_commands = dict([(name, 'django.core')
|
||||
_commands = dict([(name, 'django.core')
|
||||
for name in find_commands(__path__[0])])
|
||||
if load_user_commands:
|
||||
# Get commands from all installed apps
|
||||
# Get commands from all installed apps.
|
||||
from django.conf import settings
|
||||
for app_name in settings.INSTALLED_APPS:
|
||||
try:
|
||||
path = find_management_module(app_name)
|
||||
_commands.update(dict([(name, app_name)
|
||||
_commands.update(dict([(name, app_name)
|
||||
for name in find_commands(path)]))
|
||||
except ImportError:
|
||||
pass # No management module - ignore this app
|
||||
|
||||
|
||||
if project_directory:
|
||||
# Remove the "startproject" command from self.commands, because
|
||||
# that's a django-admin.py command, not a manage.py command.
|
||||
del _commands['startproject']
|
||||
|
||||
# Override the startapp command so that it always uses the
|
||||
# project_directory, not the current working directory
|
||||
# project_directory, not the current working directory
|
||||
# (which is default).
|
||||
from django.core.management.commands.startapp import ProjectCommand
|
||||
_commands['startapp'] = ProjectCommand(project_directory)
|
||||
@ -113,7 +117,7 @@ def call_command(name, *args, **options):
|
||||
"""
|
||||
try:
|
||||
app_name = get_commands()[name]
|
||||
if isinstance(app_name, BaseCommand):
|
||||
if isinstance(app_name, BaseCommand):
|
||||
# If the command is already loaded, use it directly.
|
||||
klass = app_name
|
||||
else:
|
||||
@ -121,16 +125,16 @@ def call_command(name, *args, **options):
|
||||
except KeyError:
|
||||
raise CommandError, "Unknown command: %r" % name
|
||||
return klass.execute(*args, **options)
|
||||
|
||||
class LaxOptionParser(OptionParser):
|
||||
|
||||
class LaxOptionParser(OptionParser):
|
||||
"""
|
||||
An option parser that doesn't raise any errors on unknown options.
|
||||
|
||||
|
||||
This is needed because the --settings and --pythonpath options affect
|
||||
the commands (and thus the options) that are available to the user.
|
||||
the commands (and thus the options) that are available to the user.
|
||||
"""
|
||||
def error(self, msg):
|
||||
pass
|
||||
def error(self, msg):
|
||||
pass
|
||||
|
||||
class ManagementUtility(object):
|
||||
"""
|
||||
@ -144,16 +148,19 @@ class ManagementUtility(object):
|
||||
self.prog_name = os.path.basename(self.argv[0])
|
||||
self.project_directory = None
|
||||
self.user_commands = False
|
||||
|
||||
|
||||
def main_help_text(self):
|
||||
"""
|
||||
Returns the script's main help text, as a string.
|
||||
"""
|
||||
usage = ['%s <subcommand> [options] [args]' % self.prog_name]
|
||||
usage.append('Django command line tool, version %s' % django.get_version())
|
||||
usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name)
|
||||
usage.append('Django command line tool,'
|
||||
' version %s' % django.get_version())
|
||||
usage.append("Type '%s help <subcommand>' for help on a specific"
|
||||
" subcommand." % self.prog_name)
|
||||
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()
|
||||
for cmd in commands:
|
||||
usage.append(' %s' % cmd)
|
||||
@ -166,33 +173,35 @@ class ManagementUtility(object):
|
||||
django-admin.py or manage.py) if it can't be found.
|
||||
"""
|
||||
try:
|
||||
app_name = get_commands(self.user_commands, self.project_directory)[subcommand]
|
||||
if isinstance(app_name, BaseCommand):
|
||||
app_name = get_commands(self.user_commands,
|
||||
self.project_directory)[subcommand]
|
||||
if isinstance(app_name, BaseCommand):
|
||||
# If the command is already loaded, use it directly.
|
||||
klass = app_name
|
||||
else:
|
||||
klass = load_command_class(app_name, subcommand)
|
||||
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)
|
||||
return klass
|
||||
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
Given the command-line arguments, this figures out which subcommand is
|
||||
being run, creates a parser appropriate to that command, and runs it.
|
||||
"""
|
||||
# Preprocess options to extract --settings and --pythonpath. These options
|
||||
# could affect the commands that are available, so they must be processed
|
||||
# early
|
||||
parser = LaxOptionParser(version=get_version(),
|
||||
option_list=BaseCommand.option_list)
|
||||
# Preprocess options to extract --settings and --pythonpath.
|
||||
# These options could affect the commands that are available, so they
|
||||
# must be processed early.
|
||||
parser = LaxOptionParser(version=get_version(),
|
||||
option_list=BaseCommand.option_list)
|
||||
try:
|
||||
options, args = parser.parse_args(self.argv)
|
||||
options, args = parser.parse_args(self.argv)
|
||||
handle_default_options(options)
|
||||
except:
|
||||
except:
|
||||
pass # Ignore any option errors at this point.
|
||||
|
||||
|
||||
try:
|
||||
subcommand = self.argv[1]
|
||||
except IndexError:
|
||||
@ -208,7 +217,8 @@ class ManagementUtility(object):
|
||||
# Special-cases: We want 'django-admin.py --version' and
|
||||
# 'django-admin.py --help' to work, for backwards compatibility.
|
||||
elif self.argv[1:] == ['--version']:
|
||||
print django.get_version()
|
||||
# LaxOptionParser already takes care of printing the version.
|
||||
pass
|
||||
elif self.argv[1:] == ['--help']:
|
||||
sys.stderr.write(self.main_help_text() + '\n')
|
||||
else:
|
||||
@ -227,10 +237,10 @@ class ProjectManagementUtility(ManagementUtility):
|
||||
super(ProjectManagementUtility, self).__init__(argv)
|
||||
self.project_directory = project_directory
|
||||
self.user_commands = True
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
# 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()
|
||||
|
||||
# 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
|
||||
|
||||
def execute_from_command_line(argv=None):
|
||||
|
@ -35,6 +35,8 @@ def get_validation_errors(outfile, app=None):
|
||||
for f in opts.fields:
|
||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
|
||||
if 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):
|
||||
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
||||
if isinstance(f, models.DecimalField):
|
||||
|
@ -249,8 +249,9 @@ class RegexURLResolver(object):
|
||||
except AttributeError:
|
||||
try:
|
||||
self._urlconf_module = __import__(self.urlconf_name, {}, {}, [''])
|
||||
except ValueError, e:
|
||||
# Invalid urlconf_name, such as "foo.bar." (note trailing period)
|
||||
except Exception, e:
|
||||
# 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)
|
||||
return self._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')
|
||||
|
||||
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):
|
||||
"""
|
||||
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.postgresql.operations import DatabaseOperations
|
||||
from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
|
||||
try:
|
||||
import psycopg2 as Database
|
||||
import psycopg2.extensions
|
||||
@ -21,6 +21,13 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
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):
|
||||
features = DatabaseFeatures()
|
||||
ops = DatabaseOperations()
|
||||
|
@ -1,7 +1,6 @@
|
||||
import datetime
|
||||
import md5
|
||||
from time import time
|
||||
from django.utils.encoding import smart_unicode, force_unicode
|
||||
|
||||
try:
|
||||
import decimal
|
||||
@ -11,7 +10,7 @@ except ImportError:
|
||||
class CursorDebugWrapper(object):
|
||||
def __init__(self, cursor, db):
|
||||
self.cursor = cursor
|
||||
self.db = db
|
||||
self.db = db # Instance of a BaseDatabaseWrapper subclass
|
||||
|
||||
def execute(self, sql, params=()):
|
||||
start = time()
|
||||
@ -19,8 +18,9 @@ class CursorDebugWrapper(object):
|
||||
return self.cursor.execute(sql, params)
|
||||
finally:
|
||||
stop = time()
|
||||
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
|
||||
self.db.queries.append({
|
||||
'sql': smart_unicode(sql) % convert_args(params),
|
||||
'sql': sql,
|
||||
'time': "%.3f" % (stop - start),
|
||||
})
|
||||
|
||||
@ -31,7 +31,7 @@ class CursorDebugWrapper(object):
|
||||
finally:
|
||||
stop = time()
|
||||
self.db.queries.append({
|
||||
'sql': 'MANY: ' + sql + ' ' + smart_unicode(tuple(param_list)),
|
||||
'sql': '%s times: %s' % (len(param_list), sql),
|
||||
'time': "%.3f" % (stop - start),
|
||||
})
|
||||
|
||||
@ -41,16 +41,6 @@ class CursorDebugWrapper(object):
|
||||
else:
|
||||
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 #
|
||||
###############################################
|
||||
|
@ -395,6 +395,8 @@ class Field(object):
|
||||
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
|
||||
if self.choices:
|
||||
defaults['widget'] = forms.Select(choices=self.get_choices())
|
||||
if self.has_default():
|
||||
defaults['initial'] = self.get_default()
|
||||
defaults.update(kwargs)
|
||||
return form_class(**defaults)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Refactored "safe reference" from dispatcher.py"""
|
||||
import weakref, traceback
|
||||
from django.utils.functional import curry
|
||||
|
||||
def safeRef(target, onDelete = None):
|
||||
"""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.
|
||||
# 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,)
|
||||
reference = BoundMethodWeakref(
|
||||
reference = get_bound_method_weakref(
|
||||
target=target,
|
||||
onDelete=onDelete
|
||||
)
|
||||
@ -163,3 +164,75 @@ class BoundMethodWeakref(object):
|
||||
if function is not None:
|
||||
return function.__get__(target)
|
||||
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:
|
||||
self._container = [content]
|
||||
self._is_string = True
|
||||
self._headers = {'content-type': content_type}
|
||||
self.cookies = SimpleCookie()
|
||||
if 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):
|
||||
"Full HTTP message, including headers"
|
||||
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
|
||||
|
||||
def __setitem__(self, header, value):
|
||||
self._headers[header.lower()] = value
|
||||
self._headers[header.lower()] = (header, value)
|
||||
|
||||
def __delitem__(self, header):
|
||||
try:
|
||||
@ -282,19 +286,19 @@ class HttpResponse(object):
|
||||
pass
|
||||
|
||||
def __getitem__(self, header):
|
||||
return self._headers[header.lower()]
|
||||
return self._headers[header.lower()][1]
|
||||
|
||||
def has_header(self, header):
|
||||
"Case-insensitive check for a header"
|
||||
return self._headers.has_key(header.lower())
|
||||
|
||||
__contains__ = has_header
|
||||
|
||||
|
||||
def items(self):
|
||||
return self._headers.items()
|
||||
|
||||
return self._headers.values()
|
||||
|
||||
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):
|
||||
self.cookies[key] = value
|
||||
@ -304,17 +308,13 @@ class HttpResponse(object):
|
||||
self.cookies[key][var.replace('_', '-')] = val
|
||||
|
||||
def delete_cookie(self, key, path='/', domain=None):
|
||||
self.cookies[key] = ''
|
||||
if path is not None:
|
||||
self.cookies[key]['path'] = path
|
||||
if domain is not None:
|
||||
self.cookies[key]['domain'] = domain
|
||||
self.cookies[key]['expires'] = 0
|
||||
self.cookies[key]['max-age'] = 0
|
||||
self.set_cookie(key, max_age=0, path=path, domain=domain,
|
||||
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
||||
|
||||
def _get_content(self):
|
||||
content = smart_str(''.join(self._container), self._charset)
|
||||
return content
|
||||
if self.has_header('Content-Encoding'):
|
||||
return ''.join(self._container)
|
||||
return smart_str(''.join(self._container), self._charset)
|
||||
|
||||
def _set_content(self, value):
|
||||
self._container = [value]
|
||||
|
@ -1,8 +1,10 @@
|
||||
import md5
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django import http
|
||||
from django.core.mail import mail_managers
|
||||
import md5
|
||||
import re
|
||||
from django.utils.http import urlquote
|
||||
|
||||
class CommonMiddleware(object):
|
||||
"""
|
||||
@ -46,9 +48,9 @@ class CommonMiddleware(object):
|
||||
if new_url != old_url:
|
||||
# Redirect
|
||||
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:
|
||||
newurl = new_url[1]
|
||||
newurl = urlquote(new_url[1])
|
||||
if request.GET:
|
||||
newurl += '?' + request.GET.urlencode()
|
||||
return http.HttpResponsePermanentRedirect(newurl)
|
||||
|
@ -17,10 +17,11 @@ class GZipMiddleware(object):
|
||||
return response
|
||||
|
||||
patch_vary_headers(response, ('Accept-Encoding',))
|
||||
|
||||
|
||||
# Avoid gzipping if we've already got a content-encoding or if the
|
||||
# content-type is Javascript (silly IE...)
|
||||
is_js = "javascript" in response.get('Content-Type', '').lower()
|
||||
# content-type is Javascript and the user's browser is IE.
|
||||
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:
|
||||
return response
|
||||
|
||||
|
@ -11,7 +11,7 @@ from django.utils.translation import ugettext
|
||||
from django.utils.encoding import StrAndUnicode, smart_unicode
|
||||
|
||||
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:
|
||||
from decimal import Decimal, DecimalException
|
||||
@ -284,6 +284,8 @@ DEFAULT_DATETIME_INPUT_FORMATS = (
|
||||
)
|
||||
|
||||
class DateTimeField(Field):
|
||||
widget = DateTimeInput
|
||||
|
||||
def __init__(self, input_formats=None, *args, **kwargs):
|
||||
super(DateTimeField, self).__init__(*args, **kwargs)
|
||||
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
|
||||
@ -300,6 +302,12 @@ class DateTimeField(Field):
|
||||
return value
|
||||
if isinstance(value, datetime.date):
|
||||
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:
|
||||
try:
|
||||
return datetime.datetime(*time.strptime(value, format)[:6])
|
||||
|
@ -19,7 +19,7 @@ from util import flatatt
|
||||
__all__ = (
|
||||
'Widget', 'TextInput', 'PasswordInput',
|
||||
'HiddenInput', 'MultipleHiddenInput',
|
||||
'FileInput', 'Textarea', 'CheckboxInput',
|
||||
'FileInput', 'DateTimeInput', 'Textarea', 'CheckboxInput',
|
||||
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
|
||||
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
|
||||
)
|
||||
@ -133,7 +133,7 @@ class FileInput(Input):
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
return super(FileInput, self).render(name, None, attrs=attrs)
|
||||
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
"File widgets take data from FILES, not POST"
|
||||
return files.get(name, None)
|
||||
@ -151,6 +151,22 @@ class Textarea(Widget):
|
||||
final_attrs = self.build_attrs(attrs, name=name)
|
||||
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):
|
||||
def __init__(self, attrs=None, check_test=bool):
|
||||
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.
|
||||
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):
|
||||
def __init__(self, attrs=None, choices=()):
|
||||
super(Select, self).__init__(attrs)
|
||||
@ -425,5 +448,5 @@ class SplitDateTimeWidget(MultiWidget):
|
||||
|
||||
def decompress(self, value):
|
||||
if value:
|
||||
return [value.date(), value.time()]
|
||||
return [value.date(), value.time().replace(microsecond=0)]
|
||||
return [None, None]
|
||||
|
@ -517,8 +517,14 @@ def firstof(parser, token):
|
||||
{% endif %}{% endif %}{% endif %}
|
||||
|
||||
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:
|
||||
raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
|
||||
return FirstOfNode(bits)
|
||||
@ -675,7 +681,7 @@ def do_if(parser, token):
|
||||
{% if athlete_list and coach_list or cheerleader_list %}
|
||||
|
||||
If you need to combine ``and`` and ``or`` to do advanced logic, just use
|
||||
nested if tags. For example:
|
||||
nested if tags. For example::
|
||||
|
||||
{% if athlete_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 TemplateSyntaxError, TokenParser, Library
|
||||
from django.template import TOKEN_TEXT, TOKEN_VAR
|
||||
@ -68,9 +70,11 @@ class BlockTranslateNode(Node):
|
||||
count = self.counter.resolve(context)
|
||||
context[self.countervar] = count
|
||||
plural = self.render_token_list(self.plural)
|
||||
result = translation.ungettext(singular, plural, count) % context
|
||||
result = translation.ungettext(singular, plural, count)
|
||||
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()
|
||||
return result
|
||||
|
||||
|
@ -6,6 +6,7 @@ from django.core.management import call_command
|
||||
from django.dispatch import dispatcher
|
||||
from django.test import signals
|
||||
from django.template import Template
|
||||
from django.utils.translation import deactivate
|
||||
|
||||
# The prefix to put on the default database name when creating
|
||||
# the test database.
|
||||
@ -43,7 +44,7 @@ def setup_test_environment():
|
||||
|
||||
- Installing the instrumented test renderer
|
||||
- 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.render = instrumented_test_render
|
||||
@ -53,6 +54,8 @@ def setup_test_environment():
|
||||
|
||||
mail.outbox = []
|
||||
|
||||
deactivate()
|
||||
|
||||
def teardown_test_environment():
|
||||
"""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
|
@ -42,22 +42,32 @@ class MergeDict(object):
|
||||
if key in dict:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
__contains__ = has_key
|
||||
|
||||
def copy(self):
|
||||
""" returns a copy of this object"""
|
||||
"""Returns a copy of this object."""
|
||||
return self.__copy__()
|
||||
|
||||
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):
|
||||
if data is None: data = {}
|
||||
if data is None:
|
||||
data = {}
|
||||
dict.__init__(self, data)
|
||||
if isinstance(data, dict):
|
||||
self.keyOrder = data.keys()
|
||||
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):
|
||||
dict.__setitem__(self, key, value)
|
||||
@ -72,6 +82,20 @@ class SortedDict(dict):
|
||||
for k in self.keyOrder:
|
||||
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):
|
||||
return zip(self.keyOrder, self.values())
|
||||
|
||||
@ -102,20 +126,21 @@ class SortedDict(dict):
|
||||
return dict.setdefault(self, key, default)
|
||||
|
||||
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]]
|
||||
|
||||
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:
|
||||
n = self.keyOrder.index(key)
|
||||
del self.keyOrder[n]
|
||||
if n < index: index -= 1
|
||||
if n < index:
|
||||
index -= 1
|
||||
self.keyOrder.insert(index, key)
|
||||
dict.__setitem__(self, key, value)
|
||||
|
||||
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.
|
||||
obj = self.__class__(self)
|
||||
obj.keyOrder = self.keyOrder
|
||||
@ -133,7 +158,8 @@ class MultiValueDictKeyError(KeyError):
|
||||
|
||||
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['name']
|
||||
@ -176,15 +202,17 @@ class MultiValueDict(dict):
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
import copy
|
||||
if memo is None: memo = {}
|
||||
if memo is None:
|
||||
memo = {}
|
||||
result = self.__class__()
|
||||
memo[id(self)] = result
|
||||
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
|
||||
|
||||
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:
|
||||
val = self[key]
|
||||
except KeyError:
|
||||
@ -194,7 +222,7 @@ class MultiValueDict(dict):
|
||||
return val
|
||||
|
||||
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:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
@ -214,7 +242,7 @@ class MultiValueDict(dict):
|
||||
return self.getlist(key)
|
||||
|
||||
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, [])
|
||||
dict.__setitem__(self, key, self.getlist(key) + [value])
|
||||
|
||||
@ -226,19 +254,22 @@ class MultiValueDict(dict):
|
||||
return [(key, self[key]) for key in self.keys()]
|
||||
|
||||
def lists(self):
|
||||
"Returns a list of (key, list) pairs."
|
||||
"""Returns a list of (key, list) pairs."""
|
||||
return dict.items(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()]
|
||||
|
||||
def copy(self):
|
||||
"Returns a copy of this object."
|
||||
"""Returns a copy of this object."""
|
||||
return self.__deepcopy__()
|
||||
|
||||
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:
|
||||
raise TypeError, "update expected at most 1 arguments, got %d" % len(args)
|
||||
if args:
|
||||
@ -299,4 +330,3 @@ class FileDict(dict):
|
||||
d = dict(self, content='<omitted>')
|
||||
return dict.__repr__(d)
|
||||
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 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
|
||||
if not isinstance(s, basestring,):
|
||||
if hasattr(s, '__unicode__'):
|
||||
|
@ -45,7 +45,7 @@ class SyndicationFeed(object):
|
||||
"Base class for all syndication feeds. Subclasses should provide write()"
|
||||
def __init__(self, title, link, description, language=None, author_email=None,
|
||||
author_name=None, author_link=None, subtitle=None, categories=None,
|
||||
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)
|
||||
if categories:
|
||||
categories = [force_unicode(c) for c in categories]
|
||||
@ -62,12 +62,13 @@ class SyndicationFeed(object):
|
||||
'feed_url': iri_to_uri(feed_url),
|
||||
'feed_copyright': to_unicode(feed_copyright),
|
||||
'id': feed_guid or link,
|
||||
'ttl': ttl,
|
||||
}
|
||||
self.items = []
|
||||
|
||||
def add_item(self, title, link, description, author_email=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
|
||||
objects except pubdate, which is a datetime.datetime object, and
|
||||
@ -89,6 +90,7 @@ class SyndicationFeed(object):
|
||||
'enclosure': enclosure,
|
||||
'categories': categories or (),
|
||||
'item_copyright': to_unicode(item_copyright),
|
||||
'ttl': ttl,
|
||||
})
|
||||
|
||||
def num_items(self):
|
||||
@ -146,6 +148,8 @@ class RssFeed(SyndicationFeed):
|
||||
if self.feed['feed_copyright'] is not None:
|
||||
handler.addQuickElement(u"copyright", self.feed['feed_copyright'])
|
||||
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.endChannelElement(handler)
|
||||
handler.endElement(u"rss")
|
||||
@ -190,6 +194,8 @@ class Rss201rev2Feed(RssFeed):
|
||||
handler.addQuickElement(u"comments", item['comments'])
|
||||
if item['unique_id'] is not None:
|
||||
handler.addQuickElement(u"guid", item['unique_id'])
|
||||
if item['ttl'] is not None:
|
||||
handler.addQuickElement(u"ttl", item['ttl'])
|
||||
|
||||
# Enclosure.
|
||||
if item['enclosure'] is not None:
|
||||
|
@ -53,7 +53,11 @@ def lazy(func, *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."
|
||||
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):
|
||||
# Builds a wrapper around some magic method and registers that magic
|
||||
@ -72,14 +76,8 @@ def lazy(func, *resultclasses):
|
||||
def __unicode_cast(self):
|
||||
return self.__func(*self.__args, **self.__kw)
|
||||
|
||||
def __str__(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))
|
||||
else:
|
||||
return Promise.__str__(self)
|
||||
def __str_cast(self):
|
||||
return str(self.__func(*self.__args, **self.__kw))
|
||||
|
||||
def __cmp__(self, rhs):
|
||||
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
|
||||
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)
|
||||
|
||||
def urlquote_plus(url, safe=''):
|
||||
|
@ -8,7 +8,7 @@ __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
|
||||
'ngettext_lazy', 'string_concat', 'activate', 'deactivate',
|
||||
'get_language', 'get_language_bidi', 'get_date_formats',
|
||||
'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']
|
||||
|
||||
# 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):
|
||||
return real_get_language_from_request(request)
|
||||
|
||||
def install():
|
||||
return real_install()
|
||||
|
||||
def templatize(src):
|
||||
return real_templatize(src)
|
||||
|
||||
|
@ -14,7 +14,7 @@ def ungettext(singular, plural, number):
|
||||
return force_unicode(ngettext(singular, plural, number))
|
||||
|
||||
activate = lambda x: None
|
||||
deactivate = deactivate_all = install = lambda: None
|
||||
deactivate = deactivate_all = lambda: None
|
||||
get_language = lambda: settings.LANGUAGE_CODE
|
||||
get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI
|
||||
get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT)
|
||||
|
@ -1,8 +1,12 @@
|
||||
"Translation helper functions"
|
||||
|
||||
import os, re, sys
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import gettext as gettext_module
|
||||
from cStringIO import StringIO
|
||||
|
||||
from django.utils.encoding import force_unicode
|
||||
|
||||
try:
|
||||
@ -25,15 +29,25 @@ _active = {}
|
||||
# The default translation is based on the settings file.
|
||||
_default = None
|
||||
|
||||
# This is a cache for accept-header to translation object mappings to prevent
|
||||
# the accept parser to run multiple times for one user.
|
||||
# This is a cache for normalised accept-header languages to prevent multiple
|
||||
# file lookups when checking the same locale on repeated requests.
|
||||
_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)."
|
||||
p = language.find('-')
|
||||
if p >= 0:
|
||||
return language[:p].lower()+'_'+language[p+1:].upper()
|
||||
if to_lower:
|
||||
return language[:p].lower()+'_'+language[p+1:].lower()
|
||||
else:
|
||||
return language[:p].lower()+'_'+language[p+1:].upper()
|
||||
else:
|
||||
return language.lower()
|
||||
|
||||
@ -249,8 +263,10 @@ def catalog():
|
||||
|
||||
def do_translate(message, translation_function):
|
||||
"""
|
||||
Translate 'message' using the given 'translation_function' name -- which
|
||||
will be either gettext or ugettext.
|
||||
Translates 'message' using the given 'translation_function' name -- which
|
||||
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
|
||||
t = _active.get(currentThread(), None)
|
||||
@ -262,12 +278,6 @@ def do_translate(message, translation_function):
|
||||
return getattr(_default, translation_function)(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')
|
||||
|
||||
def ugettext(message):
|
||||
@ -338,46 +348,40 @@ def get_language_from_request(request):
|
||||
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
||||
return lang_code
|
||||
|
||||
lang_code = request.COOKIES.get('django_language', None)
|
||||
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
|
||||
lang_code = request.COOKIES.get('django_language')
|
||||
if lang_code and lang_code in supported and check_for_language(lang_code):
|
||||
return lang_code
|
||||
|
||||
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None)
|
||||
if accept is not None:
|
||||
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
|
||||
for lang, unused in parse_accept_lang_header(accept):
|
||||
if lang == '*':
|
||||
break
|
||||
|
||||
t = _accepted.get(accept, None)
|
||||
if t is not None:
|
||||
return t
|
||||
# We have a very restricted form for our language files (no encoding
|
||||
# specifier, since they all must be UTF-8 and only one possible
|
||||
# language each time. So we avoid the overhead of gettext.find() and
|
||||
# look up the MO file manually.
|
||||
|
||||
def _parsed(el):
|
||||
p = el.find(';q=')
|
||||
if p >= 0:
|
||||
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)
|
||||
normalized = locale.locale_alias.get(to_locale(lang, True))
|
||||
if not normalized:
|
||||
continue
|
||||
|
||||
langs = [_parsed(el) for el in accept.split(',')]
|
||||
langs.sort(lambda a,b: -1*cmp(a[2], b[2]))
|
||||
# Remove the default encoding from locale_alias
|
||||
normalized = normalized.split('.')[0]
|
||||
|
||||
for lang, mainlang, order in langs:
|
||||
if lang in supported or mainlang in supported:
|
||||
langfile = gettext_module.find('django', globalpath, [to_locale(lang)])
|
||||
if langfile:
|
||||
# reconstruct the actual language from the language
|
||||
# filename, because otherwise we might incorrectly
|
||||
# report de_DE if we only have de available, but
|
||||
# did find de_DE because of language normalization
|
||||
lang = langfile[len(globalpath):].split(os.path.sep)[1]
|
||||
_accepted[accept] = lang
|
||||
return lang
|
||||
if normalized in _accepted:
|
||||
# We've seen this locale before and have an MO file for it, so no
|
||||
# need to check again.
|
||||
return _accepted[normalized]
|
||||
|
||||
for lang in (normalized, normalized.split('_')[0]):
|
||||
if lang not in supported:
|
||||
continue
|
||||
langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
|
||||
'django.mo')
|
||||
if os.path.exists(langfile):
|
||||
_accepted[normalized] = lang
|
||||
return lang
|
||||
|
||||
return settings.LANGUAGE_CODE
|
||||
|
||||
@ -414,13 +418,6 @@ def get_partial_date_formats():
|
||||
month_day_format = settings.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')
|
||||
def blankout(src, char):
|
||||
"""
|
||||
@ -516,3 +513,23 @@ def templatize(src):
|
||||
out.write(blankout(t.contents, 'X'))
|
||||
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:
|
||||
return None, [], None, []
|
||||
|
||||
encoding=None
|
||||
encoding = 'ascii'
|
||||
for line in source[:2]:
|
||||
# File coding may be specified (and may not be UTF-8). Match
|
||||
# pattern from PEP-263 (http://www.python.org/dev/peps/pep-0263/)
|
||||
# File coding may be specified. Match pattern from PEP-263
|
||||
# (http://www.python.org/dev/peps/pep-0263/)
|
||||
match = re.search(r'coding[:=]\s*([-\w.]+)', line)
|
||||
if match:
|
||||
encoding = match.group(1)
|
||||
break
|
||||
if encoding:
|
||||
source = [unicode(sline, encoding) for sline in source]
|
||||
source = [unicode(sline, encoding, 'replace') for sline in source]
|
||||
|
||||
lower_bound = max(0, lineno - context_lines)
|
||||
upper_bound = lineno + context_lines
|
||||
|
@ -28,21 +28,21 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
|
||||
.. admonition:: Using the authentication handler with Apache 2.2
|
||||
|
||||
If you're using Apache 2.2, you'll need to take a couple extra steps.
|
||||
|
||||
|
||||
You'll need to ensure that ``mod_auth_basic`` and ``mod_authz_user``
|
||||
are loaded. These might be compiled statically into Apache, or you might
|
||||
need to use ``LoadModule`` to load them dynamically (as shown in the
|
||||
example at the bottom of this note).
|
||||
|
||||
|
||||
You'll also need to insert configuration directives that prevent Apache
|
||||
from trying to use other authentication modules. Depending on which other
|
||||
authentication modules you have loaded, you might need one or more of
|
||||
the following directives::
|
||||
|
||||
|
||||
AuthBasicAuthoritative Off
|
||||
AuthDefaultAuthoritative Off
|
||||
AuthzLDAPAuthoritative Off
|
||||
@ -51,18 +51,18 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||
AuthzGroupFileAuthoritative Off
|
||||
AuthzOwnerAuthoritative Off
|
||||
AuthzUserAuthoritative Off
|
||||
|
||||
|
||||
A complete configuration, with differences between Apache 2.0 and
|
||||
Apache 2.2 marked in bold, would look something like:
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
||||
**LoadModule auth_basic_module modules/mod_auth_basic.so**
|
||||
**LoadModule authz_user_module modules/mod_authz_user.so**
|
||||
|
||||
|
||||
...
|
||||
|
||||
<Location /exmaple/>
|
||||
|
||||
<Location /example/>
|
||||
AuthType Basic
|
||||
AuthName "example.com"
|
||||
**AuthBasicAuthoritative Off**
|
||||
@ -71,7 +71,7 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
|
||||
By default, the authentication handler will limit access to the ``/example/``
|
||||
location to users marked as staff members. You can use a set of
|
||||
``PythonOption`` directives to modify this behavior:
|
||||
|
@ -119,8 +119,8 @@ in your database that is in the proper format that Django's database-cache
|
||||
system expects.
|
||||
|
||||
Once you've created that database table, set your ``CACHE_BACKEND`` setting to
|
||||
``"db://tablename/"``, where ``tablename`` is the name of the database table.
|
||||
In this example, the cache table's name is ``my_cache_table``:
|
||||
``"db://tablename"``, where ``tablename`` is the name of the database table.
|
||||
In this example, the cache table's name is ``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',
|
||||
)
|
||||
|
||||
(The order of ``MIDDLEWARE_CLASSES`` matters. See "Order of MIDDLEWARE_CLASSES"
|
||||
(The order of ``MIDDLEWARE_CLASSES`` matters. See `Order of MIDDLEWARE_CLASSES`_
|
||||
below.)
|
||||
|
||||
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
|
||||
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
|
||||
=======================
|
||||
|
||||
@ -326,6 +356,15 @@ get() can take a ``default`` argument::
|
||||
>>> cache.get('my_key', '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()
|
||||
returns a dictionary with all the keys you asked for that actually exist in the
|
||||
cache (and haven't expired)::
|
||||
@ -524,7 +563,7 @@ the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
|
||||
``max_age`` in a ``cache_control`` decorator, the decorator will take
|
||||
precedence, and the header values will be merged correctly.)
|
||||
|
||||
If you want to use headers to disable caching altogether,
|
||||
If you want to use headers to disable caching altogether,
|
||||
``django.views.decorators.never_cache`` is a view decorator that adds
|
||||
headers to ensure the response won't be cached by browsers or other caches. Example::
|
||||
|
||||
@ -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
|
||||
adds something to the ``Vary`` response header when it can.
|
||||
|
||||
Put the ``CacheMiddleware`` after any middlewares that might add something to
|
||||
the ``Vary`` header. The following middlewares do so:
|
||||
Put the ``CacheMiddleware`` *before* any other middleware that might add
|
||||
something to the ``Vary`` header (response middleware is applied in reverse
|
||||
order). The following middleware modules do so:
|
||||
|
||||
* ``SessionMiddleware`` adds ``Cookie``
|
||||
* ``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`_.
|
||||
|
||||
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 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
|
||||
.. _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
|
||||
.. _pep8.py: http://svn.browsershots.org/trunk/devtools/pep8/pep8.py
|
||||
.. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n
|
||||
.. _`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``
|
||||
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
|
||||
|
||||
Creating your database
|
||||
|
@ -741,22 +741,25 @@ Customized actions
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
If you want to add an action of your own to ``manage.py``, you can.
|
||||
Simply add a ``management/commands`` directory to your application.
|
||||
Each python module in that directory will be discovered and registered as
|
||||
Applications can register their own actions with ``manage.py``. For example,
|
||||
you might want to add a ``manage.py`` action for a Django app that you're
|
||||
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``::
|
||||
|
||||
/fancy_blog
|
||||
blog/
|
||||
__init__.py
|
||||
models.py
|
||||
/management
|
||||
management/
|
||||
__init__.py
|
||||
/commands
|
||||
commands/
|
||||
__init__.py
|
||||
explode.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``.
|
||||
|
||||
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 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
|
||||
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.
|
||||
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.
|
||||
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``
|
||||
object. If it returns ``None``, Django will continue processing this request,
|
||||
executing any other middleware and, then, the appropriate view. If it returns
|
||||
an ``HttpResponse`` object, Django won't bother calling ANY other middleware or
|
||||
the appropriate view; it'll return that ``HttpResponse``.
|
||||
an ``HttpResponse`` object, Django won't bother calling ANY other request,
|
||||
view or exception middleware, or the appropriate view; it'll return that
|
||||
``HttpResponse``. Response middleware is always called on every response.
|
||||
|
||||
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``,
|
||||
Django will continue processing this request, executing any other
|
||||
``process_view()`` middleware and, then, the appropriate view. If it returns an
|
||||
``HttpResponse`` object, Django won't bother calling ANY other middleware or
|
||||
the appropriate view; it'll return that ``HttpResponse``.
|
||||
``HttpResponse`` object, Django won't bother calling ANY other request, view
|
||||
or exception middleware, or the appropriate view; it'll return that
|
||||
``HttpResponse``. Response middleware is always called on every response.
|
||||
|
||||
process_response
|
||||
----------------
|
||||
@ -236,7 +238,8 @@ Guidelines
|
||||
|
||||
* Feel free to look at Django's available middleware for examples. 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
|
||||
other people, contribute to the community! Let us know, and we'll
|
||||
|
@ -149,7 +149,7 @@ and in Django's validation.
|
||||
Django veterans: Note that the argument is now called ``max_length`` to
|
||||
provide consistency throughout Django. There is full legacy support for
|
||||
the old ``maxlength`` argument, but ``max_length`` is preferred.
|
||||
|
||||
|
||||
``CommaSeparatedIntegerField``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -678,7 +678,9 @@ set.
|
||||
|
||||
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``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
@ -1584,8 +1586,8 @@ Finally, note that in order to use ``list_display_links``, you must define
|
||||
|
||||
Set ``list_filter`` to activate filters in the right sidebar of the change list
|
||||
page of the admin. This should be a list of field names, and each specified
|
||||
field should be either a ``BooleanField``, ``CharField``, ``DateField``,
|
||||
``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
|
||||
field should be either a ``BooleanField``, ``CharField``, ``DateField``,
|
||||
``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
|
||||
|
||||
This example, taken from the ``django.contrib.auth.models.User`` model, shows
|
||||
how both ``list_display`` and ``list_filter`` work::
|
||||
|
@ -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
|
||||
path.
|
||||
|
||||
.. caution::
|
||||
.. note::
|
||||
|
||||
If you're using Windows, remember that the path will contain backslashes.
|
||||
This string is passed through Python's string parser twice, so you need to
|
||||
escape each backslash **twice**::
|
||||
If you're using Windows, it is still recommended that you use forward
|
||||
slashes in the pathnames, even though Windows normally uses backslashes
|
||||
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.
|
||||
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)
|
||||
message = forms.CharField()
|
||||
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
|
||||
fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
|
||||
@ -860,6 +860,23 @@ classes::
|
||||
<li>Instrument: <input type="text" name="instrument" /></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
|
||||
======
|
||||
|
||||
@ -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.')
|
||||
... message = forms.CharField()
|
||||
... 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)
|
||||
>>> print f.as_table()
|
||||
<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``
|
||||
* Empty value: ``None``
|
||||
* Empty value: ``False``
|
||||
* 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``
|
||||
~~~~~~~~~~~~~
|
||||
@ -1132,7 +1160,8 @@ For each field, we describe the default widget used if you don't specify
|
||||
* Default widget: ``TextInput``
|
||||
* Empty value: ``''`` (an empty string)
|
||||
* 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``.
|
||||
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``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Default widget: ``TextInput``
|
||||
* Default widget: ``DateTimeInput``
|
||||
* Empty value: ``None``
|
||||
* Normalizes to: A Python ``datetime.datetime`` object.
|
||||
* 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', # '10/25/06'
|
||||
|
||||
**New in Django development version:** The ``DateTimeField`` used to use a
|
||||
``TextInput`` widget by default. This has now changed.
|
||||
|
||||
``DecimalField``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1508,7 +1540,7 @@ like so::
|
||||
subject = forms.CharField(max_length=100)
|
||||
message = forms.CharField()
|
||||
senders = MultiEmailField()
|
||||
cc_myself = forms.BooleanField()
|
||||
cc_myself = forms.BooleanField(required=False)
|
||||
|
||||
Widgets
|
||||
=======
|
||||
@ -1529,6 +1561,7 @@ commonly used groups of widgets:
|
||||
``MultipleHiddenInput`` Multiple ``<input type='hidden' ...``
|
||||
instances.
|
||||
``FileInput`` ``<input type='file' ...``
|
||||
``DateTimeInput`` ``<input type='text' ...``
|
||||
``Textarea`` ``<textarea>...</textarea>``
|
||||
``CheckboxInput`` ``<input type='checkbox' ...``
|
||||
``Select`` ``<select><option ...``
|
||||
@ -1542,6 +1575,9 @@ commonly used groups of widgets:
|
||||
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
|
||||
------------------
|
||||
|
||||
@ -2033,7 +2069,7 @@ have a ``Message`` model that holds each contact submission. Something like::
|
||||
subject = models.CharField(max_length=100)
|
||||
message = models.TextField()
|
||||
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
|
||||
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
|
||||
---------
|
||||
|
||||
Default: ``()`` (Empty list)
|
||||
Default: ``()`` (Empty tuple)
|
||||
|
||||
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.
|
||||
@ -475,7 +475,7 @@ FIXTURE_DIRS
|
||||
Default: ``()`` (Empty tuple)
|
||||
|
||||
List of locations of the fixture data files, in search order. Note that
|
||||
these paths should use Unix-style forward slashes, even on Windows. See
|
||||
these paths should use Unix-style forward slashes, even on Windows. See
|
||||
`Testing Django Applications`_.
|
||||
|
||||
.. _Testing Django Applications: ../testing/
|
||||
@ -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
|
||||
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
|
||||
------------------
|
||||
|
||||
@ -720,8 +731,8 @@ SERIALIZATION_MODULES
|
||||
|
||||
Default: Not defined.
|
||||
|
||||
A dictionary of modules containing serializer definitions (provided as
|
||||
strings), keyed by a string identifier for that serialization type. For
|
||||
A dictionary of modules containing serializer definitions (provided as
|
||||
strings), keyed by a string identifier for that serialization type. For
|
||||
example, to define a YAML serializer, use::
|
||||
|
||||
SERIALIZATION_MODULES = { 'yaml' : 'path.to.yaml_serializer' }
|
||||
@ -743,10 +754,10 @@ Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
|
||||
See the `session docs`_ for more details.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
@ -773,6 +784,18 @@ Default: ``'sessionid'``
|
||||
The name of the cookie to use for sessions. This can be whatever you want.
|
||||
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
|
||||
---------------------
|
||||
|
||||
|
@ -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.
|
||||
|
||||
# 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
|
||||
# for them in this order.
|
||||
|
||||
|
@ -2,13 +2,35 @@
|
||||
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
|
||||
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_
|
||||
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/
|
||||
.. _CheetahTemplate: http://www.cheetahtemplate.org/
|
||||
.. _your own extensions: ../templates_python/#extending-the-template-system
|
||||
|
||||
Templates
|
||||
=========
|
||||
@ -377,7 +399,7 @@ loop::
|
||||
...
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
Outside of a loop, give the values a unique name the first time you call it,
|
||||
then use that name each successive time through::
|
||||
|
||||
@ -385,16 +407,16 @@ then use that name each successive time through::
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
|
||||
You can use any number of values, separated by spaces. Values enclosed in
|
||||
single (') or double quotes (") are treated as string literals, while values
|
||||
without quotes are assumed to refer to context variables.
|
||||
You can use any number of values, separated by spaces. Values enclosed in
|
||||
single (') or double quotes (") are treated as string literals, while values
|
||||
without quotes are assumed to refer to context variables.
|
||||
|
||||
You can also separate values with commas::
|
||||
|
||||
{% cycle row1,row2,row3 %}
|
||||
|
||||
In this syntax, each value will be interpreted as literal text. The
|
||||
comma-based syntax exists for backwards-compatibility, and should not be
|
||||
|
||||
In this syntax, each value will be interpreted as literal text. The
|
||||
comma-based syntax exists for backwards-compatibility, and should not be
|
||||
used for new projects.
|
||||
|
||||
debug
|
||||
@ -454,6 +476,11 @@ This is equivalent to::
|
||||
{{ var3 }}
|
||||
{% 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
|
||||
~~~
|
||||
|
||||
@ -472,13 +499,13 @@ You can loop over a list in reverse by using ``{% for obj in list reversed %}``.
|
||||
If you need to loop over a list of lists, you can unpack the values
|
||||
in eachs sub-list into a set of known names. For example, if your context contains
|
||||
a list of (x,y) coordinates called ``points``, you could use the following
|
||||
to output the list of points::
|
||||
to output the list of points::
|
||||
|
||||
{% for x, y in points %}
|
||||
There is a point at {{ x }},{{ y }}
|
||||
{% endfor %}
|
||||
|
||||
This can also be useful if you need to access the items in a dictionary.
|
||||
|
||||
This can also be useful if you need to access the items in a dictionary.
|
||||
For example, if your context contained a dictionary ``data``, the following
|
||||
would display the keys and values of the dictionary::
|
||||
|
||||
@ -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`_.
|
||||
|
||||
.. _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
|
||||
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
|
||||
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')
|
||||
choices2 = models.CharField(max_length=10, choices=[(1,2,3),(1,2,3)])
|
||||
index = models.CharField(max_length=10, db_index='bad')
|
||||
field_ = models.CharField(max_length=10)
|
||||
|
||||
class Target(models.Model):
|
||||
tgt_safe = models.CharField(max_length=10)
|
||||
@ -47,7 +48,7 @@ class Target2(models.Model):
|
||||
|
||||
class Clash3(models.Model):
|
||||
src_safe = models.CharField(max_length=10, core=True)
|
||||
|
||||
|
||||
foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt')
|
||||
foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt')
|
||||
|
||||
@ -76,7 +77,7 @@ class ValidM2M(models.Model):
|
||||
# on self don't require a related accessor, so many potential
|
||||
# clashes are avoided.
|
||||
validm2m_set = models.ManyToManyField("ValidM2M")
|
||||
|
||||
|
||||
m2m_1 = models.ManyToManyField("ValidM2M", related_name='id')
|
||||
m2m_2 = models.ManyToManyField("ValidM2M", related_name='src_safe')
|
||||
|
||||
@ -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: "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 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'.
|
||||
|
@ -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.contenttypes.models import ContentType
|
||||
|
||||
@ -28,10 +33,10 @@ False
|
||||
# reloading user to purge the _perm_cache
|
||||
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test'])
|
||||
>>> user.get_group_permissions()
|
||||
set([])
|
||||
>>> user.get_all_permissions() == set([u'auth.test'])
|
||||
True
|
||||
>>> user.get_group_permissions() == set([])
|
||||
True
|
||||
>>> user.has_module_perms("Group")
|
||||
False
|
||||
>>> user.has_module_perms("auth")
|
||||
@ -43,8 +48,8 @@ True
|
||||
>>> user.user_permissions.add(perm)
|
||||
>>> user.save()
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test2', u'auth.test', u'auth.test3'])
|
||||
>>> user.get_all_permissions() == set([u'auth.test2', u'auth.test', u'auth.test3'])
|
||||
True
|
||||
>>> user.has_perm('test')
|
||||
False
|
||||
>>> user.has_perm('auth.test')
|
||||
@ -57,10 +62,11 @@ True
|
||||
>>> group.save()
|
||||
>>> user.groups.add(group)
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
|
||||
>>> user.get_group_permissions()
|
||||
set([u'auth.test_group'])
|
||||
>>> exp = set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
|
||||
>>> user.get_all_permissions() == exp
|
||||
True
|
||||
>>> user.get_group_permissions() == set([u'auth.test_group'])
|
||||
True
|
||||
>>> user.has_perms(['auth.test3', 'auth.test_group'])
|
||||
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")
|
||||
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):
|
||||
# get with non-existent keys
|
||||
self.assertEqual(cache.get("does_not_exist"), None)
|
||||
|
@ -54,6 +54,17 @@
|
||||
True
|
||||
>>> print repr(d)
|
||||
{'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
|
||||
>>> 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,11 +35,15 @@ u'41-403'
|
||||
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.']
|
||||
>>> f.clean('43-34-234-323')
|
||||
u'43-34-234-323'
|
||||
>>> f.clean('433-344-24-23')
|
||||
u'433-344-24-23'
|
||||
|
||||
>>> f.clean('64-62-414-124')
|
||||
u'6462414124'
|
||||
>>> f.clean('646-241-41-24')
|
||||
u'6462414124'
|
||||
>>> f.clean('646-241-41-23')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Wrong checksum for the Tax Number (NIP).']
|
||||
|
||||
# PLNationalIdentificationNumberField ############################################
|
||||
|
||||
>>> from django.contrib.localflavor.pl.forms import PLNationalIdentificationNumberField
|
||||
@ -58,4 +62,20 @@ ValidationError: [u'National Identification Number consists of 11 digits.']
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
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,21 +1,49 @@
|
||||
import datetime
|
||||
|
||||
from django.db import models
|
||||
|
||||
class BoundaryModel(models.Model):
|
||||
class BoundaryModel(models.Model):
|
||||
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': """
|
||||
>>> from django.newforms import form_for_model
|
||||
>>> from django.newforms import form_for_model, form_for_instance
|
||||
|
||||
# Boundary conditions on a PostitiveIntegerField #########################
|
||||
>>> BoundaryForm = form_for_model(BoundaryModel)
|
||||
>>> f = BoundaryForm({'positive_integer':100})
|
||||
>>> f.is_valid()
|
||||
>>> BoundaryForm = form_for_model(BoundaryModel)
|
||||
>>> f = BoundaryForm({'positive_integer':100})
|
||||
>>> f.is_valid()
|
||||
True
|
||||
>>> f = BoundaryForm({'positive_integer':0})
|
||||
>>> f.is_valid()
|
||||
>>> f = BoundaryForm({'positive_integer':0})
|
||||
>>> f.is_valid()
|
||||
True
|
||||
>>> f = BoundaryForm({'positive_integer':-100})
|
||||
>>> f.is_valid()
|
||||
>>> f = BoundaryForm({'positive_integer':-100})
|
||||
>>> f.is_valid()
|
||||
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.cl import tests as localflavor_cl_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.fr import tests as localflavor_fr_tests
|
||||
from localflavor.generic import tests as localflavor_generic_tests
|
||||
@ -35,6 +36,7 @@ __test__ = {
|
||||
'localflavor_ch_tests': localflavor_ch_tests,
|
||||
'localflavor_cl_tests': localflavor_cl_tests,
|
||||
'localflavor_de_tests': localflavor_de_tests,
|
||||
'localflavor_es_tests': localflavor_es_tests,
|
||||
'localflavor_fi_tests': localflavor_fi_tests,
|
||||
'localflavor_fr_tests': localflavor_fr_tests,
|
||||
'localflavor_generic_tests': localflavor_generic_tests,
|
||||
|
@ -276,6 +276,12 @@ u'<input type="checkbox" name="greeting" />'
|
||||
>>> w.render('greeting', None)
|
||||
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 ###############################################################
|
||||
|
||||
>>> w = Select()
|
||||
@ -845,4 +851,21 @@ included on both widgets.
|
||||
>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
|
||||
>>> 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" />'
|
||||
|
||||
# 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
|
||||
import misc
|
||||
|
||||
ur"""
|
||||
regressions = ur"""
|
||||
Format string interpolation should work with *_lazy objects.
|
||||
|
||||
>>> 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"))
|
||||
u'django'
|
||||
"""
|
||||
|
||||
__test__ = {
|
||||
'regressions': regressions,
|
||||
'misc': misc.tests,
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ from datetime import datetime, timedelta
|
||||
from django import template
|
||||
from django.template import loader
|
||||
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 unicode import unicode_tests
|
||||
@ -341,7 +341,10 @@ class Templates(unittest.TestCase):
|
||||
'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
|
||||
'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
|
||||
'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-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-fail02' : ('{% url no_such_view %}', {}, ''),
|
||||
'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.
|
||||
@ -827,8 +844,6 @@ class Templates(unittest.TestCase):
|
||||
expected_invalid_str = 'INVALID'
|
||||
|
||||
for name, vals in tests:
|
||||
install()
|
||||
|
||||
if isinstance(vals[2], tuple):
|
||||
normal_string_result = vals[2][0]
|
||||
invalid_string_result = vals[2][1]
|
||||
|
@ -20,8 +20,12 @@ friends'
|
||||
>>> from django.utils.http import urlquote, urlquote_plus
|
||||
>>> urlquote(u'Paris & Orl\xe9ans')
|
||||
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')
|
||||
u'Paris+%26+Orl%C3%A9ans'
|
||||
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
|
||||
u'Paris+&+Orl%C3%A9ans'
|
||||
|
||||
### iri_to_uri ###########################################################
|
||||
>>> from django.utils.encoding import iri_to_uri
|
||||
|
@ -4,7 +4,7 @@ Tests for django.utils.
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from django.utils import html
|
||||
from django.utils import html, checksums
|
||||
|
||||
from timesince import timesince_tests
|
||||
|
||||
@ -116,6 +116,32 @@ class TestUtilsHtml(TestCase):
|
||||
for value, output in items:
|
||||
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__ = {
|
||||
'timesince_tests': timesince_tests,
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ def django_tests(verbosity, interactive, test_labels):
|
||||
old_root_urlconf = settings.ROOT_URLCONF
|
||||
old_template_dirs = settings.TEMPLATE_DIRS
|
||||
old_use_i18n = settings.USE_I18N
|
||||
old_language_code = settings.LANGUAGE_CODE
|
||||
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
||||
|
||||
# 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.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
||||
settings.USE_I18N = True
|
||||
settings.LANGUAGE_CODE = 'en'
|
||||
settings.MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
@ -151,6 +153,7 @@ def django_tests(verbosity, interactive, test_labels):
|
||||
settings.ROOT_URLCONF = old_root_urlconf
|
||||
settings.TEMPLATE_DIRS = old_template_dirs
|
||||
settings.USE_I18N = old_use_i18n
|
||||
settings.LANGUAGE_CODE = old_language_code
|
||||
settings.MIDDLEWARE_CLASSES = old_middleware_classes
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
x
Reference in New Issue
Block a user