1
0
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:
Justin Bronn 2007-10-26 20:47:20 +00:00
parent f66ee9d006
commit 4ffbddf92d
93 changed files with 11032 additions and 7945 deletions

View File

@ -50,6 +50,7 @@ answer newbie questions, and generally made Django that much better:
Fabrice Aneche <akh@nobugware.com>
ant9000@netwise.it
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,6 +259,7 @@ 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
@ -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>

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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"

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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()

View File

@ -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

View 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')),
)

View 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')),
)

View 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)

View File

@ -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):
"""

View File

@ -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):

View File

@ -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

View File

@ -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__':

View File

@ -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:

View File

@ -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

View File

@ -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)])

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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 = []

View File

@ -1,10 +1,11 @@
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
@ -14,18 +15,21 @@ _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,7 +40,7 @@ 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):
@ -77,7 +81,7 @@ def get_commands(load_user_commands=True, project_directory=None):
_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:
@ -130,7 +134,7 @@ class LaxOptionParser(OptionParser):
the commands (and thus the options) that are available to the user.
"""
def error(self, msg):
pass
pass
class ManagementUtility(object):
"""
@ -150,10 +154,13 @@ class ManagementUtility(object):
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,14 +173,16 @@ 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]
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
@ -182,9 +191,9 @@ class ManagementUtility(object):
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
# 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:
@ -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:
@ -230,7 +240,7 @@ class ProjectManagementUtility(ManagementUtility):
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):

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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 #
###############################################

View File

@ -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)

View File

@ -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)

View File

@ -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,7 +286,7 @@ 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"
@ -291,10 +295,10 @@ class HttpResponse(object):
__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]

View File

@ -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)

View File

@ -19,8 +19,9 @@ class GZipMiddleware(object):
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

View File

@ -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])

View File

@ -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',
)
@ -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]

View File

@ -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 %}

View 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)

View File

@ -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

View File

@ -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
View 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

View File

@ -46,18 +46,28 @@ class MergeDict(object):
__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)

View File

@ -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__'):

View File

@ -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:

View File

@ -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:

View File

@ -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=''):

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -62,7 +62,7 @@ with the standard ``Auth*`` and ``Require`` directives::
...
<Location /exmaple/>
<Location /example/>
AuthType Basic
AuthName "example.com"
**AuthBasicAuthoritative Off**

View File

@ -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)::
@ -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``

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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`_.

View File

@ -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

View File

@ -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``
~~~~~~~~~~~~~~~~~~~

View File

@ -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.

View File

@ -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

View File

@ -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.
@ -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
------------------
@ -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
---------------------

View File

@ -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.

View File

@ -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
=========
@ -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
~~~
@ -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/

View File

@ -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

View File

@ -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)
@ -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'.

View File

@ -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
"""
"""}

View File

@ -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)

View File

@ -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((

View 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>'
"""

View File

@ -35,10 +35,14 @@ 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 ############################################
@ -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.']
"""

View File

@ -1,10 +1,17 @@
import datetime
from django.db import models
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)
@ -18,4 +25,25 @@ True
>>> 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
"""}

View File

@ -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,

View File

@ -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" />'
"""

View 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('')
[]
"""

View File

@ -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,
}

View File

@ -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]

View File

@ -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

View File

@ -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,
}

View File

@ -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__":