mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
[soc2009/model-validation] Merged to trunk at r12070
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@12073 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a7c320fea7
commit
ffd5564a87
6
AUTHORS
6
AUTHORS
@ -28,9 +28,11 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
|
|
||||||
ajs <adi@sieker.info>
|
ajs <adi@sieker.info>
|
||||||
alang@bright-green.com
|
alang@bright-green.com
|
||||||
|
Alcides Fonseca
|
||||||
Andi Albrecht <albrecht.andi@gmail.com>
|
Andi Albrecht <albrecht.andi@gmail.com>
|
||||||
Marty Alchin <gulopine@gamemusic.org>
|
Marty Alchin <gulopine@gamemusic.org>
|
||||||
Ahmad Alhashemi <trans@ahmadh.com>
|
Ahmad Alhashemi <trans@ahmadh.com>
|
||||||
|
Ahmad Al-Ibrahim
|
||||||
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
|
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
|
||||||
AgarFu <heaven@croasanaso.sytes.net>
|
AgarFu <heaven@croasanaso.sytes.net>
|
||||||
Dagur Páll Ammendrup <dagurp@gmail.com>
|
Dagur Páll Ammendrup <dagurp@gmail.com>
|
||||||
@ -188,6 +190,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Simon Greenhill <dev@simon.net.nz>
|
Simon Greenhill <dev@simon.net.nz>
|
||||||
Owen Griffiths
|
Owen Griffiths
|
||||||
Espen Grindhaug <http://grindhaug.org/>
|
Espen Grindhaug <http://grindhaug.org/>
|
||||||
|
Janos Guljas
|
||||||
Thomas Güttler <hv@tbz-pariv.de>
|
Thomas Güttler <hv@tbz-pariv.de>
|
||||||
Horst Gutmann <zerok@zerokspot.com>
|
Horst Gutmann <zerok@zerokspot.com>
|
||||||
Scot Hacker <shacker@birdhouse.org>
|
Scot Hacker <shacker@birdhouse.org>
|
||||||
@ -195,6 +198,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
hambaloney
|
hambaloney
|
||||||
Brian Harring <ferringb@gmail.com>
|
Brian Harring <ferringb@gmail.com>
|
||||||
Brant Harris
|
Brant Harris
|
||||||
|
Ronny Haryanto <http://ronny.haryan.to/>
|
||||||
Hawkeye
|
Hawkeye
|
||||||
Joe Heck <http://www.rhonabwy.com/wp/>
|
Joe Heck <http://www.rhonabwy.com/wp/>
|
||||||
Joel Heenan <joelh-django@planetjoel.com>
|
Joel Heenan <joelh-django@planetjoel.com>
|
||||||
@ -384,6 +388,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Rozza <ross.lawley@gmail.com>
|
Rozza <ross.lawley@gmail.com>
|
||||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||||
ryankanno
|
ryankanno
|
||||||
|
Gonzalo Saavedra <gonzalosaavedra@gmail.com>
|
||||||
Manuel Saelices <msaelices@yaco.es>
|
Manuel Saelices <msaelices@yaco.es>
|
||||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||||
@ -482,6 +487,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
ymasuda@ethercube.com
|
ymasuda@ethercube.com
|
||||||
Jesse Young <adunar@gmail.com>
|
Jesse Young <adunar@gmail.com>
|
||||||
Mykola Zamkovoi <nickzam@gmail.com>
|
Mykola Zamkovoi <nickzam@gmail.com>
|
||||||
|
zegor
|
||||||
Gasper Zejn <zejn@kiberpipa.org>
|
Gasper Zejn <zejn@kiberpipa.org>
|
||||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||||
Cheng Zhang
|
Cheng Zhang
|
||||||
|
@ -84,6 +84,7 @@ LANGUAGES = (
|
|||||||
('sk', gettext_noop('Slovak')),
|
('sk', gettext_noop('Slovak')),
|
||||||
('sl', gettext_noop('Slovenian')),
|
('sl', gettext_noop('Slovenian')),
|
||||||
('sr', gettext_noop('Serbian')),
|
('sr', gettext_noop('Serbian')),
|
||||||
|
('sr-latn', gettext_noop('Serbian Latin')),
|
||||||
('sv', gettext_noop('Swedish')),
|
('sv', gettext_noop('Swedish')),
|
||||||
('ta', gettext_noop('Tamil')),
|
('ta', gettext_noop('Tamil')),
|
||||||
('te', gettext_noop('Telugu')),
|
('te', gettext_noop('Telugu')),
|
||||||
|
@ -2,17 +2,40 @@
|
|||||||
# This file is distributed under the same license as the Django package.
|
# This file is distributed under the same license as the Django package.
|
||||||
#
|
#
|
||||||
|
|
||||||
DATE_FORMAT = 'd F Y'
|
DATE_FORMAT = 'd F Y' # 25 Ottobre 2006
|
||||||
TIME_FORMAT = 'H.i.s'
|
TIME_FORMAT = 'H:i:s' # 14:30:59
|
||||||
# DATETIME_FORMAT =
|
DATETIME_FORMAT = 'w d F Y H:i:s' # Mercoledì 25 Ottobre 2006 14:30:59
|
||||||
YEAR_MONTH_FORMAT = 'F Y'
|
YEAR_MONTH_FORMAT = 'F Y' # Ottobre 2006
|
||||||
MONTH_DAY_FORMAT = 'j F'
|
MONTH_DAY_FORMAT = 'j/F' # 10/2006
|
||||||
SHORT_DATE_FORMAT = 'd/M/Y'
|
SHORT_DATE_FORMAT = 'd/M/Y' # 25/12/2009
|
||||||
# SHORT_DATETIME_FORMAT =
|
SHORT_DATETIME_FORMAT = 'd/M/Y H:i:s' # 25/10/2009 14:30:59
|
||||||
# FIRST_DAY_OF_WEEK =
|
FIRST_DAY_OF_WEEK = 1 # Lunedì
|
||||||
# DATE_INPUT_FORMATS =
|
DATE_INPUT_FORMATS = (
|
||||||
# TIME_INPUT_FORMATS =
|
'%Y-%m-%d', '%Y/%m/%d', # '2008-10-25', '2008/10/25'
|
||||||
# DATETIME_INPUT_FORMATS =
|
'%d-%m-%Y', '%d/%m/%Y', # '25-10-2006', '25/10/2006'
|
||||||
|
'%d-%m-%y', '%d/%m/%y', # '25-10-06', '25/10/06'
|
||||||
|
)
|
||||||
|
TIME_INPUT_FORMATS = (
|
||||||
|
'%H:%M:%S', # '14:30:59'
|
||||||
|
'%H:%M', # '14:30'
|
||||||
|
)
|
||||||
|
DATETIME_INPUT_FORMATS = (
|
||||||
|
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
|
||||||
|
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
|
||||||
|
'%Y-%m-%d', # '2006-10-25'
|
||||||
|
'%d-%m-%Y %H:%M:%S', # '25-10-2006 14:30:59'
|
||||||
|
'%d-%m-%Y %H:%M', # '25-10-2006 14:30'
|
||||||
|
'%d-%m-%Y', # '25-10-2006'
|
||||||
|
'%d-%m-%y %H:%M:%S', # '25-10-06 14:30:59'
|
||||||
|
'%d-%m-%y %H:%M', # '25-10-06 14:30'
|
||||||
|
'%d-%m-%y', # '25-10-06'
|
||||||
|
'%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59'
|
||||||
|
'%d/%m/%Y %H:%M', # '25/10/2006 14:30'
|
||||||
|
'%d/%m/%Y', # '25/10/2006'
|
||||||
|
'%d/%m/%y %H:%M:%S', # '25/10/06 14:30:59'
|
||||||
|
'%d/%m/%y %H:%M', # '25/10/06 14:30'
|
||||||
|
'%d/%m/%y', # '25/10/06'
|
||||||
|
)
|
||||||
DECIMAL_SEPARATOR = ','
|
DECIMAL_SEPARATOR = ','
|
||||||
THOUSAND_SEPARATOR = '.'
|
THOUSAND_SEPARATOR = '.'
|
||||||
# NUMBER_GROUPING =
|
NUMBER_GROUPING = 3
|
||||||
|
@ -14,19 +14,19 @@ DATE_INPUT_FORMATS = (
|
|||||||
'%j. %B %Y', '%j %B %Y', # '25. oktober 2006', '25 oktober 2006'
|
'%j. %B %Y', '%j %B %Y', # '25. oktober 2006', '25 oktober 2006'
|
||||||
)
|
)
|
||||||
TIME_INPUT_FORMATS = (
|
TIME_INPUT_FORMATS = (
|
||||||
'%H:%i:%S', # '14:30:59'
|
'%H:%M:%S', # '14:30:59'
|
||||||
'%H:%i', # '14:30'
|
'%H:%M', # '14:30'
|
||||||
)
|
)
|
||||||
DATETIME_INPUT_FORMATS = (
|
DATETIME_INPUT_FORMATS = (
|
||||||
'%Y-%m-%d %H:%i:%S', # '2006-10-25 14:30:59'
|
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
|
||||||
'%Y-%m-%d %H:%i', # '2006-10-25 14:30'
|
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
|
||||||
'%Y-%m-%d', # '2006-10-25'
|
'%Y-%m-%d', # '2006-10-25'
|
||||||
'%Y-%m-%j', # '2006-10-25'
|
'%Y-%m-%j', # '2006-10-25'
|
||||||
'%j.%m.%Y %H:%i:%S', # '25.10.2006 14:30:59'
|
'%j.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
|
||||||
'%j.%m.%Y %H:%i', # '25.10.2006 14:30'
|
'%j.%m.%Y %H:%M', # '25.10.2006 14:30'
|
||||||
'%j.%m.%Y', # '25.10.2006'
|
'%j.%m.%Y', # '25.10.2006'
|
||||||
'%j.%m.%y %H:%i:%S', # '25.10.06 14:30:59'
|
'%j.%m.%y %H:%M:%S', # '25.10.06 14:30:59'
|
||||||
'%j.%m.%y %H:%i', # '25.10.06 14:30'
|
'%j.%m.%y %H:%M', # '25.10.06 14:30'
|
||||||
'%j.%m.%y', # '25.10.06'
|
'%j.%m.%y', # '25.10.06'
|
||||||
)
|
)
|
||||||
DECIMAL_SEPARATOR = ','
|
DECIMAL_SEPARATOR = ','
|
||||||
|
@ -5,7 +5,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2009-12-23 12:55+0100\n"
|
"POT-Creation-Date: 2009-12-30 08:54+0100\n"
|
||||||
"PO-Revision-Date: 2008-02-25 15:53+0100\n"
|
"PO-Revision-Date: 2008-02-25 15:53+0100\n"
|
||||||
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
|
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -223,7 +223,7 @@ msgstr "chiński tradycyjny"
|
|||||||
msgid "Successfully deleted %(count)d %(items)s."
|
msgid "Successfully deleted %(count)d %(items)s."
|
||||||
msgstr "Usunięto %(count)d %(items)s."
|
msgstr "Usunięto %(count)d %(items)s."
|
||||||
|
|
||||||
#: contrib/admin/actions.py:67 contrib/admin/options.py:1073
|
#: contrib/admin/actions.py:67 contrib/admin/options.py:1075
|
||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "Jesteś pewien?"
|
msgstr "Jesteś pewien?"
|
||||||
|
|
||||||
@ -314,94 +314,94 @@ msgstr "logi"
|
|||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr "brak"
|
msgstr "brak"
|
||||||
|
|
||||||
#: contrib/admin/options.py:540
|
#: contrib/admin/options.py:554
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %s."
|
msgid "Changed %s."
|
||||||
msgstr "Zmieniono %s"
|
msgstr "Zmieniono %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:540 contrib/admin/options.py:550
|
#: contrib/admin/options.py:554 contrib/admin/options.py:564
|
||||||
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:385
|
#: contrib/comments/templates/comments/preview.html:16 forms/models.py:385
|
||||||
#: forms/models.py:598
|
#: forms/models.py:598
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr "i"
|
msgstr "i"
|
||||||
|
|
||||||
#: contrib/admin/options.py:545
|
#: contrib/admin/options.py:559
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Added %(name)s \"%(object)s\"."
|
msgid "Added %(name)s \"%(object)s\"."
|
||||||
msgstr "Dodano %(name)s \"%(object)s\"."
|
msgstr "Dodano %(name)s \"%(object)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:549
|
#: contrib/admin/options.py:563
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
msgid "Changed %(list)s for %(name)s \"%(object)s\"."
|
||||||
msgstr "Zmieniono %(list)s w %(name)s \"%(object)s\"."
|
msgstr "Zmieniono %(list)s w %(name)s \"%(object)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:554
|
#: contrib/admin/options.py:568
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleted %(name)s \"%(object)s\"."
|
msgid "Deleted %(name)s \"%(object)s\"."
|
||||||
msgstr "Usunięto %(name)s \"%(object)s\"."
|
msgstr "Usunięto %(name)s \"%(object)s\"."
|
||||||
|
|
||||||
#: contrib/admin/options.py:558
|
#: contrib/admin/options.py:572
|
||||||
msgid "No fields changed."
|
msgid "No fields changed."
|
||||||
msgstr "Żadne pole nie zmienione."
|
msgstr "Żadne pole nie zmienione."
|
||||||
|
|
||||||
#: contrib/admin/options.py:620 contrib/auth/admin.py:68
|
#: contrib/admin/options.py:634 contrib/auth/admin.py:68
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
||||||
msgstr "%(name)s \"%(obj)s\" dodany pomyślnie."
|
msgstr "%(name)s \"%(obj)s\" dodany pomyślnie."
|
||||||
|
|
||||||
#: contrib/admin/options.py:624 contrib/admin/options.py:657
|
#: contrib/admin/options.py:638 contrib/admin/options.py:671
|
||||||
#: contrib/auth/admin.py:77
|
#: contrib/auth/admin.py:77
|
||||||
msgid "You may edit it again below."
|
msgid "You may edit it again below."
|
||||||
msgstr "Możesz ponownie edytować wpis poniżej."
|
msgstr "Możesz ponownie edytować wpis poniżej."
|
||||||
|
|
||||||
#: contrib/admin/options.py:634 contrib/admin/options.py:667
|
#: contrib/admin/options.py:648 contrib/admin/options.py:681
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You may add another %s below."
|
msgid "You may add another %s below."
|
||||||
msgstr "Możesz dodać nowy wpis %s poniżej."
|
msgstr "Możesz dodać nowy wpis %s poniżej."
|
||||||
|
|
||||||
#: contrib/admin/options.py:655
|
#: contrib/admin/options.py:669
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
||||||
msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
|
msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
|
||||||
|
|
||||||
#: contrib/admin/options.py:663
|
#: contrib/admin/options.py:677
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
|
"%(name)s \"%(obj)s\" dodane pomyślnie. Możesz edytować ponownie wpis poniżej."
|
||||||
|
|
||||||
#: contrib/admin/options.py:714
|
#: contrib/admin/options.py:728
|
||||||
msgid ""
|
msgid ""
|
||||||
"Items must be selected in order to perform actions on them. No items have "
|
"Items must be selected in order to perform actions on them. No items have "
|
||||||
"been changed."
|
"been changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wykonanie akcji wymaga wybrania obiektów. Żaden obiekt nie został zmieniony."
|
"Wykonanie akcji wymaga wybrania obiektów. Żaden obiekt nie został zmieniony."
|
||||||
|
|
||||||
#: contrib/admin/options.py:728
|
#: contrib/admin/options.py:742
|
||||||
msgid "No action selected."
|
msgid "No action selected."
|
||||||
msgstr "Nie wybrano akcji."
|
msgstr "Nie wybrano akcji."
|
||||||
|
|
||||||
#: contrib/admin/options.py:808
|
#: contrib/admin/options.py:822
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Add %s"
|
msgid "Add %s"
|
||||||
msgstr "Dodaj %s"
|
msgstr "Dodaj %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:840 contrib/admin/options.py:1051
|
#: contrib/admin/options.py:848 contrib/admin/options.py:1053
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s object with primary key %(key)r does not exist."
|
msgid "%(name)s object with primary key %(key)r does not exist."
|
||||||
msgstr "Obiekt %(name)s o kluczu głównym %(key)r nie istnieje."
|
msgstr "Obiekt %(name)s o kluczu głównym %(key)r nie istnieje."
|
||||||
|
|
||||||
#: contrib/admin/options.py:905
|
#: contrib/admin/options.py:913
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change %s"
|
msgid "Change %s"
|
||||||
msgstr "Zmień %s"
|
msgstr "Zmień %s"
|
||||||
|
|
||||||
#: contrib/admin/options.py:950
|
#: contrib/admin/options.py:958
|
||||||
msgid "Database error"
|
msgid "Database error"
|
||||||
msgstr "Błąd bazy danych"
|
msgstr "Błąd bazy danych"
|
||||||
|
|
||||||
#: contrib/admin/options.py:986
|
#: contrib/admin/options.py:994
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(count)s %(name)s was changed successfully."
|
msgid "%(count)s %(name)s was changed successfully."
|
||||||
msgid_plural "%(count)s %(name)s were changed successfully."
|
msgid_plural "%(count)s %(name)s were changed successfully."
|
||||||
@ -409,12 +409,12 @@ msgstr[0] "%(count)s %(name)s został pomyślnie zmieniony."
|
|||||||
msgstr[1] "%(count)s %(name)s zostały pomyślnie zmienione."
|
msgstr[1] "%(count)s %(name)s zostały pomyślnie zmienione."
|
||||||
msgstr[2] "%(count)s %(name)s zostało pomyślnie zmienionych."
|
msgstr[2] "%(count)s %(name)s zostało pomyślnie zmienionych."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1066
|
#: contrib/admin/options.py:1068
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
||||||
msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
|
msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
|
||||||
|
|
||||||
#: contrib/admin/options.py:1103
|
#: contrib/admin/options.py:1105
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change history: %s"
|
msgid "Change history: %s"
|
||||||
msgstr "Historia zmian: %s"
|
msgstr "Historia zmian: %s"
|
||||||
@ -546,9 +546,8 @@ msgid ""
|
|||||||
"There's been an error. It's been reported to the site administrators via e-"
|
"There's been an error. It's been reported to the site administrators via e-"
|
||||||
"mail and should be fixed shortly. Thanks for your patience."
|
"mail and should be fixed shortly. Thanks for your patience."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wystąpił niespodziewany błąd. Raport został wysłany e-mailem "
|
"Wystąpił niespodziewany błąd. Został on zgłoszony e-mailem administratorowi "
|
||||||
"administratorowi strony i powinien zostać wkrótce naprawiony. Dziękujemy za "
|
"strony i powinien zostać wkrótce naprawiony. Dziękujemy za cierpliwość."
|
||||||
"cierpliwość."
|
|
||||||
|
|
||||||
#: contrib/admin/templates/admin/actions.html:4
|
#: contrib/admin/templates/admin/actions.html:4
|
||||||
msgid "Run the selected action"
|
msgid "Run the selected action"
|
||||||
|
@ -44,7 +44,7 @@ var DateTimeShortcuts = {
|
|||||||
var shortcuts_span = document.createElement('span');
|
var shortcuts_span = document.createElement('span');
|
||||||
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
|
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
|
||||||
var now_link = document.createElement('a');
|
var now_link = document.createElement('a');
|
||||||
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().getHourMinuteSecond());");
|
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||||
now_link.appendChild(document.createTextNode(gettext('Now')));
|
now_link.appendChild(document.createTextNode(gettext('Now')));
|
||||||
var clock_link = document.createElement('a');
|
var clock_link = document.createElement('a');
|
||||||
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
|
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
|
||||||
@ -80,10 +80,10 @@ var DateTimeShortcuts = {
|
|||||||
quickElement('h2', clock_box, gettext('Choose a time'));
|
quickElement('h2', clock_box, gettext('Choose a time'));
|
||||||
time_list = quickElement('ul', clock_box, '');
|
time_list = quickElement('ul', clock_box, '');
|
||||||
time_list.className = 'timelist';
|
time_list.className = 'timelist';
|
||||||
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().getHourMinuteSecond());")
|
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||||
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '00:00:00');")
|
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||||
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '06:00:00');")
|
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||||
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '12:00:00');")
|
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||||
|
|
||||||
cancel_p = quickElement('p', clock_box, '');
|
cancel_p = quickElement('p', clock_box, '');
|
||||||
cancel_p.className = 'calendar-cancel';
|
cancel_p.className = 'calendar-cancel';
|
||||||
@ -195,20 +195,19 @@ var DateTimeShortcuts = {
|
|||||||
openCalendar: function(num) {
|
openCalendar: function(num) {
|
||||||
var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
|
var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
|
||||||
var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
|
var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
|
||||||
var inp = DateTimeShortcuts.calendarInputs[num];
|
var inp = DateTimeShortcuts.calendarInputs[num];
|
||||||
|
|
||||||
// Determine if the current value in the input has a valid date.
|
// Determine if the current value in the input has a valid date.
|
||||||
// If so, draw the calendar with that date's year and month.
|
// If so, draw the calendar with that date's year and month.
|
||||||
if (inp.value) {
|
if (inp.value) {
|
||||||
var date_parts = inp.value.split('-');
|
var date_parts = inp.value.split('-');
|
||||||
var year = date_parts[0];
|
var year = date_parts[0];
|
||||||
var month = parseFloat(date_parts[1]);
|
var month = parseFloat(date_parts[1]);
|
||||||
if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
|
if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
|
||||||
DateTimeShortcuts.calendars[num].drawDate(month, year);
|
DateTimeShortcuts.calendars[num].drawDate(month, year);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Recalculate the clockbox position
|
// Recalculate the clockbox position
|
||||||
// is it left-to-right or right-to-left layout ?
|
// is it left-to-right or right-to-left layout ?
|
||||||
if (getStyle(document.body,'direction')!='rtl') {
|
if (getStyle(document.body,'direction')!='rtl') {
|
||||||
@ -237,12 +236,19 @@ var DateTimeShortcuts = {
|
|||||||
DateTimeShortcuts.calendars[num].drawNextMonth();
|
DateTimeShortcuts.calendars[num].drawNextMonth();
|
||||||
},
|
},
|
||||||
handleCalendarCallback: function(num) {
|
handleCalendarCallback: function(num) {
|
||||||
return "function(y, m, d) { DateTimeShortcuts.calendarInputs["+num+"].value = y+'-'+(m<10?'0':'')+m+'-'+(d<10?'0':'')+d; document.getElementById(DateTimeShortcuts.calendarDivName1+"+num+").style.display='none';}";
|
format = gettext('DATE_INPUT_FORMATS');
|
||||||
|
// the format needs to be escaped a little
|
||||||
|
format = format.replace('\\', '\\\\');
|
||||||
|
format = format.replace('\r', '\\r');
|
||||||
|
format = format.replace('\n', '\\n');
|
||||||
|
format = format.replace('\t', '\\t');
|
||||||
|
format = format.replace("'", "\\'");
|
||||||
|
return "function(y, m, d) { DateTimeShortcuts.calendarInputs["+num+"].value = new Date(y, m-1, d).strftime('"+format+"');document.getElementById(DateTimeShortcuts.calendarDivName1+"+num+").style.display='none';}";
|
||||||
},
|
},
|
||||||
handleCalendarQuickLink: function(num, offset) {
|
handleCalendarQuickLink: function(num, offset) {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
d.setDate(d.getDate() + offset)
|
d.setDate(d.getDate() + offset)
|
||||||
DateTimeShortcuts.calendarInputs[num].value = d.getISODate();
|
DateTimeShortcuts.calendarInputs[num].value = d.strftime(gettext('DATE_INPUT_FORMATS'));
|
||||||
DateTimeShortcuts.dismissCalendar(num);
|
DateTimeShortcuts.dismissCalendar(num);
|
||||||
},
|
},
|
||||||
cancelEventPropagation: function(e) {
|
cancelEventPropagation: function(e) {
|
||||||
|
@ -115,6 +115,10 @@ Date.prototype.getCorrectYear = function() {
|
|||||||
return (y < 38) ? y + 2000 : y + 1900;
|
return (y < 38) ? y + 2000 : y + 1900;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Date.prototype.getTwelveHours = function() {
|
||||||
|
return (this.getHours() <= 12) ? this.getHours() : 24 - this.getHours();
|
||||||
|
}
|
||||||
|
|
||||||
Date.prototype.getTwoDigitMonth = function() {
|
Date.prototype.getTwoDigitMonth = function() {
|
||||||
return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1);
|
return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1);
|
||||||
}
|
}
|
||||||
@ -123,6 +127,10 @@ Date.prototype.getTwoDigitDate = function() {
|
|||||||
return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
|
return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Date.prototype.getTwoDigitTwelveHour = function() {
|
||||||
|
return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
|
||||||
|
}
|
||||||
|
|
||||||
Date.prototype.getTwoDigitHour = function() {
|
Date.prototype.getTwoDigitHour = function() {
|
||||||
return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
|
return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
|
||||||
}
|
}
|
||||||
@ -147,6 +155,37 @@ Date.prototype.getHourMinuteSecond = function() {
|
|||||||
return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
|
return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Date.prototype.strftime = function(format) {
|
||||||
|
var fields = {
|
||||||
|
c: this.toString(),
|
||||||
|
d: this.getTwoDigitDate(),
|
||||||
|
H: this.getTwoDigitHour(),
|
||||||
|
I: this.getTwoDigitTwelveHour(),
|
||||||
|
m: this.getTwoDigitMonth(),
|
||||||
|
M: this.getTwoDigitMinute(),
|
||||||
|
p: (this.getHours() >= 12) ? 'PM' : 'AM',
|
||||||
|
S: this.getTwoDigitSecond(),
|
||||||
|
w: '0' + this.getDay(),
|
||||||
|
x: this.toLocaleDateString(),
|
||||||
|
X: this.toLocaleTimeString(),
|
||||||
|
y: ('' + this.getFullYear()).substr(2, 4),
|
||||||
|
Y: '' + this.getFullYear(),
|
||||||
|
'%' : '%'
|
||||||
|
};
|
||||||
|
var result = '', i = 0;
|
||||||
|
while (i < format.length) {
|
||||||
|
if (format[i] === '%') {
|
||||||
|
result = result + fields[format[i + 1]];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = result + format[i];
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// String object extensions
|
// String object extensions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -8,7 +8,7 @@ from django.contrib.admin import helpers
|
|||||||
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
|
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.views.decorators.csrf import csrf_protect
|
from django.views.decorators.csrf import csrf_protect
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied, ValidationError
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models.fields import BLANK_CHOICE_DASH
|
from django.db.models.fields import BLANK_CHOICE_DASH
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
@ -368,6 +368,20 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
from django.contrib.admin.views.main import ChangeList
|
from django.contrib.admin.views.main import ChangeList
|
||||||
return ChangeList
|
return ChangeList
|
||||||
|
|
||||||
|
def get_object(self, request, object_id):
|
||||||
|
"""
|
||||||
|
Returns an instance matching the primary key provided. ``None`` is
|
||||||
|
returned if no match is found (or the object_id failed validation
|
||||||
|
against the primary key field).
|
||||||
|
"""
|
||||||
|
queryset = self.queryset(request)
|
||||||
|
model = queryset.model
|
||||||
|
try:
|
||||||
|
object_id = model._meta.pk.to_python(object_id)
|
||||||
|
return queryset.get(pk=object_id)
|
||||||
|
except (model.DoesNotExist, ValidationError):
|
||||||
|
return None
|
||||||
|
|
||||||
def get_changelist_form(self, request, **kwargs):
|
def get_changelist_form(self, request, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for use in the Formset on the changelist page.
|
Returns a Form class for use in the Formset on the changelist page.
|
||||||
@ -829,13 +843,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
model = self.model
|
model = self.model
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
|
|
||||||
try:
|
obj = self.get_object(request, unquote(object_id))
|
||||||
obj = self.queryset(request).get(pk=unquote(object_id))
|
|
||||||
except model.DoesNotExist:
|
|
||||||
# Don't raise Http404 just yet, because we haven't checked
|
|
||||||
# permissions yet. We don't want an unauthenticated user to be able
|
|
||||||
# to determine whether a given object exists.
|
|
||||||
obj = None
|
|
||||||
|
|
||||||
if not self.has_change_permission(request, obj):
|
if not self.has_change_permission(request, obj):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
@ -1040,13 +1048,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
app_label = opts.app_label
|
app_label = opts.app_label
|
||||||
|
|
||||||
try:
|
obj = self.get_object(request, unquote(object_id))
|
||||||
obj = self.queryset(request).get(pk=unquote(object_id))
|
|
||||||
except self.model.DoesNotExist:
|
|
||||||
# Don't raise Http404 just yet, because we haven't checked
|
|
||||||
# permissions yet. We don't want an unauthenticated user to be able
|
|
||||||
# to determine whether a given object exists.
|
|
||||||
obj = None
|
|
||||||
|
|
||||||
if not self.has_delete_permission(request, obj):
|
if not self.has_delete_permission(request, obj):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
@ -247,8 +247,8 @@ def date_hierarchy(cl):
|
|||||||
return {
|
return {
|
||||||
'show': True,
|
'show': True,
|
||||||
'choices': [{
|
'choices': [{
|
||||||
'link': link({year_field: year.year}),
|
'link': link({year_field: str(year.year)}),
|
||||||
'title': year.year
|
'title': str(year.year),
|
||||||
} for year in years]
|
} for year in years]
|
||||||
}
|
}
|
||||||
date_hierarchy = register.inclusion_tag('admin/date_hierarchy.html')(date_hierarchy)
|
date_hierarchy = register.inclusion_tag('admin/date_hierarchy.html')(date_hierarchy)
|
||||||
|
@ -252,8 +252,7 @@ def lookup_field(name, obj, model_admin=None):
|
|||||||
|
|
||||||
def label_for_field(name, model, model_admin):
|
def label_for_field(name, model, model_admin):
|
||||||
try:
|
try:
|
||||||
model._meta.get_field_by_name(name)[0]
|
return model._meta.get_field_by_name(name)[0].verbose_name
|
||||||
return name
|
|
||||||
except models.FieldDoesNotExist:
|
except models.FieldDoesNotExist:
|
||||||
if name == "__unicode__":
|
if name == "__unicode__":
|
||||||
return force_unicode(model._meta.verbose_name)
|
return force_unicode(model._meta.verbose_name)
|
||||||
|
@ -41,21 +41,21 @@ class FilteredSelectMultiple(forms.SelectMultiple):
|
|||||||
(name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
|
(name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
|
||||||
return mark_safe(u''.join(output))
|
return mark_safe(u''.join(output))
|
||||||
|
|
||||||
class AdminDateWidget(forms.TextInput):
|
class AdminDateWidget(forms.DateTimeInput):
|
||||||
class Media:
|
class Media:
|
||||||
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
||||||
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
||||||
|
|
||||||
def __init__(self, attrs={}):
|
def __init__(self, attrs={}, format=None):
|
||||||
super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
|
super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'}, format=format)
|
||||||
|
|
||||||
class AdminTimeWidget(forms.TextInput):
|
class AdminTimeWidget(forms.TimeInput):
|
||||||
class Media:
|
class Media:
|
||||||
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
||||||
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
||||||
|
|
||||||
def __init__(self, attrs={}):
|
def __init__(self, attrs={}, format=None):
|
||||||
super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
|
super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'}, format=format)
|
||||||
|
|
||||||
class AdminSplitDateTime(forms.SplitDateTimeWidget):
|
class AdminSplitDateTime(forms.SplitDateTimeWidget):
|
||||||
"""
|
"""
|
||||||
|
@ -218,22 +218,26 @@ class User(models.Model):
|
|||||||
permissions = set()
|
permissions = set()
|
||||||
for backend in auth.get_backends():
|
for backend in auth.get_backends():
|
||||||
if hasattr(backend, "get_group_permissions"):
|
if hasattr(backend, "get_group_permissions"):
|
||||||
if obj is not None and backend.supports_object_permissions:
|
if obj is not None:
|
||||||
group_permissions = backend.get_group_permissions(self, obj)
|
if backend.supports_object_permissions:
|
||||||
|
permissions.update(
|
||||||
|
backend.get_group_permissions(self, obj)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
group_permissions = backend.get_group_permissions(self)
|
permissions.update(backend.get_group_permissions(self))
|
||||||
permissions.update(group_permissions)
|
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
def get_all_permissions(self, obj=None):
|
def get_all_permissions(self, obj=None):
|
||||||
permissions = set()
|
permissions = set()
|
||||||
for backend in auth.get_backends():
|
for backend in auth.get_backends():
|
||||||
if hasattr(backend, "get_all_permissions"):
|
if hasattr(backend, "get_all_permissions"):
|
||||||
if obj is not None and backend.supports_object_permissions:
|
if obj is not None:
|
||||||
all_permissions = backend.get_all_permissions(self, obj)
|
if backend.supports_object_permissions:
|
||||||
|
permissions.update(
|
||||||
|
backend.get_all_permissions(self, obj)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
all_permissions = backend.get_all_permissions(self)
|
permissions.update(backend.get_all_permissions(self))
|
||||||
permissions.update(all_permissions)
|
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
def has_perm(self, perm, obj=None):
|
def has_perm(self, perm, obj=None):
|
||||||
@ -255,9 +259,10 @@ class User(models.Model):
|
|||||||
# Otherwise we need to check the backends.
|
# Otherwise we need to check the backends.
|
||||||
for backend in auth.get_backends():
|
for backend in auth.get_backends():
|
||||||
if hasattr(backend, "has_perm"):
|
if hasattr(backend, "has_perm"):
|
||||||
if obj is not None and backend.supports_object_permissions:
|
if obj is not None:
|
||||||
if backend.has_perm(self, perm, obj):
|
if (backend.supports_object_permissions and
|
||||||
return True
|
backend.has_perm(self, perm, obj)):
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
if backend.has_perm(self, perm):
|
if backend.has_perm(self, perm):
|
||||||
return True
|
return True
|
||||||
|
@ -69,6 +69,21 @@ class BackendTest(TestCase):
|
|||||||
self.assertEqual(user.has_perm('test'), False)
|
self.assertEqual(user.has_perm('test'), False)
|
||||||
self.assertEqual(user.has_perms(['auth.test2', 'auth.test3']), False)
|
self.assertEqual(user.has_perms(['auth.test2', 'auth.test3']), False)
|
||||||
|
|
||||||
|
def test_has_no_object_perm(self):
|
||||||
|
"""Regressiontest for #12462"""
|
||||||
|
user = User.objects.get(username='test')
|
||||||
|
content_type=ContentType.objects.get_for_model(Group)
|
||||||
|
perm = Permission.objects.create(name='test', content_type=content_type, codename='test')
|
||||||
|
user.user_permissions.add(perm)
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
self.assertEqual(user.has_perm('auth.test', 'object'), False)
|
||||||
|
self.assertEqual(user.get_all_permissions('object'), set([]))
|
||||||
|
self.assertEqual(user.has_perm('auth.test'), True)
|
||||||
|
self.assertEqual(user.get_all_permissions(), set(['auth.test']))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestObj(object):
|
class TestObj(object):
|
||||||
pass
|
pass
|
||||||
|
@ -158,7 +158,7 @@ class EasyInstanceField(object):
|
|||||||
if isinstance(self.field, models.DateTimeField):
|
if isinstance(self.field, models.DateTimeField):
|
||||||
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
|
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
|
||||||
elif isinstance(self.field, models.TimeField):
|
elif isinstance(self.field, models.TimeField):
|
||||||
objs = capfirst(formats.date_format(self.raw_value, 'TIME_FORMAT'))
|
objs = capfirst(formats.time_format(self.raw_value, 'TIME_FORMAT'))
|
||||||
else:
|
else:
|
||||||
objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
|
objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
|
||||||
else:
|
else:
|
||||||
|
@ -37,7 +37,7 @@ class CalendarPlugin(DatabrowsePlugin):
|
|||||||
return [mark_safe(u'%s%s/%s/%s/%s/%s/' % (
|
return [mark_safe(u'%s%s/%s/%s/%s/%s/' % (
|
||||||
easy_instance_field.model.url(),
|
easy_instance_field.model.url(),
|
||||||
plugin_name, easy_instance_field.field.name,
|
plugin_name, easy_instance_field.field.name,
|
||||||
d.year,
|
str(d.year),
|
||||||
datetime_safe.new_date(d).strftime('%b').lower(),
|
datetime_safe.new_date(d).strftime('%b').lower(),
|
||||||
d.day))]
|
d.day))]
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../../">Calendars</a> / <a href="../../../">By {{ field.verbose_name }}</a> / <a href="../../">{{ day.year }}</a> / <a href="../">{{ day|date:"F" }}</a> / {{ day.day }}</div>
|
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../../">Calendars</a> / <a href="../../../">By {{ field.verbose_name }}</a> / <a href="../../">{{ day|date:"Y" }}</a> / <a href="../">{{ day|date:"F" }}</a> / {{ day|date:"d" }}</div>
|
||||||
|
|
||||||
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
|
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for year in date_list %}
|
{% for year in date_list %}
|
||||||
<li class="{% cycle 'odd' 'even' %}"><a href="{{ year.year }}/">{{ year.year }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ year|date:"Y" }}/">{{ year|date:"Y" }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../">Calendars</a> / <a href="../../">By {{ field.verbose_name }}</a> / <a href="../">{{ month.year }}</a> / {{ month|date:"F" }}</div>
|
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../">Calendars</a> / <a href="../../">By {{ field.verbose_name }}</a> / <a href="../">{{ month|date:"Y" }}</a> / {{ month|date:"F" }}</div>
|
||||||
|
|
||||||
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F Y" }}</h1>
|
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ month|date:"F Y" }}</h1>
|
||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
|
@ -8,8 +8,7 @@ from django.contrib.gis.db.backends.postgis.adapter import PostGISAdapter
|
|||||||
from django.contrib.gis.geometry.backend import Geometry
|
from django.contrib.gis.geometry.backend import Geometry
|
||||||
from django.contrib.gis.measure import Distance
|
from django.contrib.gis.measure import Distance
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db.backends.postgresql.operations import DatabaseOperations
|
from django.db.backends.postgresql_psycopg2.base import Database, DatabaseOperations
|
||||||
from django.db.backends.postgresql_psycopg2.base import Database
|
|
||||||
|
|
||||||
#### Classes used in constructing PostGIS spatial SQL ####
|
#### Classes used in constructing PostGIS spatial SQL ####
|
||||||
class PostGISOperator(SpatialOperation):
|
class PostGISOperator(SpatialOperation):
|
||||||
@ -404,11 +403,12 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
|||||||
"""
|
"""
|
||||||
cursor = self.connection._cursor()
|
cursor = self.connection._cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute('SELECT %s()' % func)
|
try:
|
||||||
row = cursor.fetchone()
|
cursor.execute('SELECT %s()' % func)
|
||||||
except:
|
row = cursor.fetchone()
|
||||||
# Responsibility of callers to perform error handling.
|
except:
|
||||||
raise
|
# Responsibility of callers to perform error handling.
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return row[0]
|
return row[0]
|
||||||
|
@ -9,7 +9,6 @@ from django.contrib.gis.db.backends.spatialite.client import SpatiaLiteClient
|
|||||||
from django.contrib.gis.db.backends.spatialite.creation import SpatiaLiteCreation
|
from django.contrib.gis.db.backends.spatialite.creation import SpatiaLiteCreation
|
||||||
from django.contrib.gis.db.backends.spatialite.operations import SpatiaLiteOperations
|
from django.contrib.gis.db.backends.spatialite.operations import SpatiaLiteOperations
|
||||||
|
|
||||||
|
|
||||||
class DatabaseWrapper(SqliteDatabaseWrapper):
|
class DatabaseWrapper(SqliteDatabaseWrapper):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# Before we get too far, make sure pysqlite 2.5+ is installed.
|
# Before we get too far, make sure pysqlite 2.5+ is installed.
|
||||||
@ -36,6 +35,7 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
|
|||||||
|
|
||||||
def _cursor(self):
|
def _cursor(self):
|
||||||
if self.connection is None:
|
if self.connection is None:
|
||||||
|
## The following is the same as in django.db.backends.sqlite3.base ##
|
||||||
settings_dict = self.settings_dict
|
settings_dict = self.settings_dict
|
||||||
if not settings_dict['NAME']:
|
if not settings_dict['NAME']:
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
@ -50,7 +50,11 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
|
|||||||
self.connection.create_function("django_extract", 2, _sqlite_extract)
|
self.connection.create_function("django_extract", 2, _sqlite_extract)
|
||||||
self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
|
self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
|
||||||
self.connection.create_function("regexp", 2, _sqlite_regexp)
|
self.connection.create_function("regexp", 2, _sqlite_regexp)
|
||||||
|
connection_created.send(sender=self.__class__)
|
||||||
|
|
||||||
|
## From here on, customized for GeoDjango ##
|
||||||
|
|
||||||
|
# Enabling extension loading on the SQLite connection.
|
||||||
try:
|
try:
|
||||||
self.connection.enable_load_extension(True)
|
self.connection.enable_load_extension(True)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -59,15 +63,14 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
|
|||||||
'the loading of extensions to use SpatiaLite.'
|
'the loading of extensions to use SpatiaLite.'
|
||||||
)
|
)
|
||||||
|
|
||||||
connection_created.send(sender=self.__class__)
|
# Loading the SpatiaLite library extension on the connection, and returning
|
||||||
return self.connection.cursor(factory=SQLiteCursorWrapper)
|
# the created cursor.
|
||||||
|
cur = self.connection.cursor(factory=SQLiteCursorWrapper)
|
||||||
def load_spatialite(self):
|
try:
|
||||||
"""
|
cur.execute("SELECT load_extension(%s)", (self.spatialite_lib,))
|
||||||
Loads the SpatiaLite library.
|
except Exception, msg:
|
||||||
"""
|
raise ImproperlyConfigured('Unable to load the SpatiaLite library extension '
|
||||||
try:
|
'"%s" because: %s' % (self.spatialite_lib, msg))
|
||||||
self._cursor().execute("SELECT load_extension(%s)", (self.spatialite_lib,))
|
return cur
|
||||||
except Exception, msg:
|
else:
|
||||||
raise ImproperlyConfigured('Unable to load the SpatiaLite extension '
|
return self.connection.cursor(factory=SQLiteCursorWrapper)
|
||||||
'"%s" because: %s' % (self.spatialite_lib, msg))
|
|
||||||
|
@ -24,8 +24,7 @@ class SpatiaLiteCreation(DatabaseCreation):
|
|||||||
self.connection.settings_dict["NAME"] = test_database_name
|
self.connection.settings_dict["NAME"] = test_database_name
|
||||||
can_rollback = self._rollback_works()
|
can_rollback = self._rollback_works()
|
||||||
self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
|
self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
|
||||||
# Need to load the SpatiaLite library and initializatin SQL before running `syncdb`.
|
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
|
||||||
self.connection.load_spatialite()
|
|
||||||
self.load_spatialite_sql()
|
self.load_spatialite_sql()
|
||||||
call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
|
call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
|
||||||
|
|
||||||
|
@ -51,8 +51,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
|||||||
name = 'spatialite'
|
name = 'spatialite'
|
||||||
spatialite = True
|
spatialite = True
|
||||||
version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
|
version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
|
||||||
valid_aggregates = dict([(k, None) for k in
|
valid_aggregates = dict([(k, None) for k in ('Extent', 'Union')])
|
||||||
('Extent', 'Union')])
|
|
||||||
|
|
||||||
Adapter = SpatiaLiteAdapter
|
Adapter = SpatiaLiteAdapter
|
||||||
|
|
||||||
@ -112,10 +111,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
|||||||
super(DatabaseOperations, self).__init__()
|
super(DatabaseOperations, self).__init__()
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
||||||
# Load the spatialite library (must be done before getting the
|
# Determine the version of the SpatiaLite library.
|
||||||
# SpatiaLite version).
|
|
||||||
self.connection.load_spatialite()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vtup = self.spatialite_version_tuple()
|
vtup = self.spatialite_version_tuple()
|
||||||
version = vtup[1:]
|
version = vtup[1:]
|
||||||
@ -211,11 +207,12 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
|||||||
"""
|
"""
|
||||||
cursor = self.connection._cursor()
|
cursor = self.connection._cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute('SELECT %s()' % func)
|
try:
|
||||||
row = cursor.fetchone()
|
cursor.execute('SELECT %s()' % func)
|
||||||
except:
|
row = cursor.fetchone()
|
||||||
# TODO: raise helpful exception here.
|
except:
|
||||||
raise
|
# Responsibility of caller to perform error handling.
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return row[0]
|
return row[0]
|
||||||
@ -268,7 +265,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
|||||||
"""
|
"""
|
||||||
Returns the SpatiaLite-specific SQL for the given lookup value
|
Returns the SpatiaLite-specific SQL for the given lookup value
|
||||||
[a tuple of (alias, column, db_type)], lookup type, lookup
|
[a tuple of (alias, column, db_type)], lookup type, lookup
|
||||||
value, and the model field.
|
value, the model field, and the quoting function.
|
||||||
"""
|
"""
|
||||||
alias, col, db_type = lvalue
|
alias, col, db_type = lvalue
|
||||||
|
|
||||||
|
@ -10,7 +10,10 @@ class GeoManager(Manager):
|
|||||||
use_for_related_fields = True
|
use_for_related_fields = True
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return GeoQuerySet(model=self.model)
|
qs = GeoQuerySet(self.model)
|
||||||
|
if self._db is not None:
|
||||||
|
qs = qs.using(self._db)
|
||||||
|
return qs
|
||||||
|
|
||||||
def area(self, *args, **kwargs):
|
def area(self, *args, **kwargs):
|
||||||
return self.get_query_set().area(*args, **kwargs)
|
return self.get_query_set().area(*args, **kwargs)
|
||||||
|
@ -191,8 +191,8 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
|||||||
if self.connection.ops.oracle or getattr(self.query, 'geo_values', False):
|
if self.connection.ops.oracle or getattr(self.query, 'geo_values', False):
|
||||||
# We resolve the rest of the columns if we're on Oracle or if
|
# We resolve the rest of the columns if we're on Oracle or if
|
||||||
# the `geo_values` attribute is defined.
|
# the `geo_values` attribute is defined.
|
||||||
for value, field in izip(row[index_start:], fields):
|
for value, field in map(None, row[index_start:], fields):
|
||||||
values.append(self.query.convert_values(value, field, self.connection))
|
values.append(self.query.convert_values(value, field, connection=self.connection))
|
||||||
else:
|
else:
|
||||||
values.extend(row[index_start:])
|
values.extend(row[index_start:])
|
||||||
return tuple(values)
|
return tuple(values)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Error checking functions for GEOS ctypes prototype functions.
|
Error checking functions for GEOS ctypes prototype functions.
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
from ctypes import c_void_p, string_at, CDLL
|
from ctypes import c_void_p, string_at, CDLL
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOS_VERSION
|
from django.contrib.gis.geos.libgeos import lgeos, GEOS_VERSION
|
||||||
@ -15,8 +16,12 @@ if GEOS_VERSION >= (3, 1, 1):
|
|||||||
free.restype = None
|
free.restype = None
|
||||||
else:
|
else:
|
||||||
# Getting the `free` routine from the C library of the platform.
|
# Getting the `free` routine from the C library of the platform.
|
||||||
# The C library is obtained by passing None into `CDLL`.
|
if os.name == 'nt':
|
||||||
libc = CDLL(None)
|
# On NT, use the MS C library.
|
||||||
|
libc = CDLL('msvcrt')
|
||||||
|
else:
|
||||||
|
# On POSIX platforms C library is obtained by passing None into `CDLL`.
|
||||||
|
libc = CDLL(None)
|
||||||
free = libc.free
|
free = libc.free
|
||||||
|
|
||||||
### ctypes error checking routines ###
|
### ctypes error checking routines ###
|
||||||
|
@ -19,7 +19,6 @@ class RelatedGeoModelTest(unittest.TestCase):
|
|||||||
loc = Location.objects.create(point=Point(lon, lat))
|
loc = Location.objects.create(point=Point(lon, lat))
|
||||||
c = City.objects.create(name=name, state=state, location=loc)
|
c = City.objects.create(name=name, state=state, location=loc)
|
||||||
|
|
||||||
@no_oracle # TODO: Fix select_related() problems w/Oracle and pagination.
|
|
||||||
def test02_select_related(self):
|
def test02_select_related(self):
|
||||||
"Testing `select_related` on geographic models (see #7126)."
|
"Testing `select_related` on geographic models (see #7126)."
|
||||||
qs1 = City.objects.all()
|
qs1 = City.objects.all()
|
||||||
@ -34,7 +33,6 @@ class RelatedGeoModelTest(unittest.TestCase):
|
|||||||
self.assertEqual(Point(lon, lat), c.location.point)
|
self.assertEqual(Point(lon, lat), c.location.point)
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
@no_oracle # Pagination problem is implicated in this test as well.
|
|
||||||
def test03_transform_related(self):
|
def test03_transform_related(self):
|
||||||
"Testing the `transform` GeoQuerySet method on related geographic models."
|
"Testing the `transform` GeoQuerySet method on related geographic models."
|
||||||
# All the transformations are to state plane coordinate systems using
|
# All the transformations are to state plane coordinate systems using
|
||||||
|
0
django/contrib/localflavor/id/__init__.py
Normal file
0
django/contrib/localflavor/id/__init__.py
Normal file
210
django/contrib/localflavor/id/forms.py
Normal file
210
django/contrib/localflavor/id/forms.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
"""
|
||||||
|
ID-specific Form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.forms.fields import Field, Select, EMPTY_VALUES
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.encoding import smart_unicode
|
||||||
|
|
||||||
|
postcode_re = re.compile(r'^[1-9]\d{4}$')
|
||||||
|
phone_re = re.compile(r'^(\+62|0)[2-9]\d{7,10}$')
|
||||||
|
plate_re = re.compile(r'^(?P<prefix>[A-Z]{1,2}) ' + \
|
||||||
|
r'(?P<number>\d{1,5})( (?P<suffix>([A-Z]{1,3}|[1-9][0-9]{,2})))?$')
|
||||||
|
nik_re = re.compile(r'^\d{16}$')
|
||||||
|
|
||||||
|
|
||||||
|
class IDPostCodeField(Field):
|
||||||
|
"""
|
||||||
|
An Indonesian post code field.
|
||||||
|
|
||||||
|
http://id.wikipedia.org/wiki/Kode_pos
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid post code'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(IDPostCodeField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
value = value.strip()
|
||||||
|
if not postcode_re.search(value):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
if int(value) < 10110:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# 1xxx0
|
||||||
|
if value[0] == '1' and value[4] != '0':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
return u'%s' % (value, )
|
||||||
|
|
||||||
|
|
||||||
|
class IDProvinceSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of provinces of Indonesia as its
|
||||||
|
choices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from id_choices import PROVINCE_CHOICES
|
||||||
|
super(IDProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
class IDPhoneNumberField(Field):
|
||||||
|
"""
|
||||||
|
An Indonesian telephone number field.
|
||||||
|
|
||||||
|
http://id.wikipedia.org/wiki/Daftar_kode_telepon_di_Indonesia
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid phone number'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(IDPhoneNumberField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
phone_number = re.sub(r'[\-\s\(\)]', '', smart_unicode(value))
|
||||||
|
|
||||||
|
if phone_re.search(phone_number):
|
||||||
|
return smart_unicode(value)
|
||||||
|
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
|
||||||
|
class IDLicensePlatePrefixSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of vehicle license plate prefix code
|
||||||
|
of Indonesia as its choices.
|
||||||
|
|
||||||
|
http://id.wikipedia.org/wiki/Tanda_Nomor_Kendaraan_Bermotor
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from id_choices import LICENSE_PLATE_PREFIX_CHOICES
|
||||||
|
super(IDLicensePlatePrefixSelect, self).__init__(attrs,
|
||||||
|
choices=LICENSE_PLATE_PREFIX_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
class IDLicensePlateField(Field):
|
||||||
|
"""
|
||||||
|
An Indonesian vehicle license plate field.
|
||||||
|
|
||||||
|
http://id.wikipedia.org/wiki/Tanda_Nomor_Kendaraan_Bermotor
|
||||||
|
|
||||||
|
Plus: "B 12345 12"
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid vehicle license plate number'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(IDLicensePlateField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
plate_number = re.sub(r'\s+', ' ',
|
||||||
|
smart_unicode(value.strip())).upper()
|
||||||
|
|
||||||
|
matches = plate_re.search(plate_number)
|
||||||
|
if matches is None:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# Make sure prefix is in the list of known codes.
|
||||||
|
from id_choices import LICENSE_PLATE_PREFIX_CHOICES
|
||||||
|
prefix = matches.group('prefix')
|
||||||
|
if prefix not in [choice[0] for choice in LICENSE_PLATE_PREFIX_CHOICES]:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# Only Jakarta (prefix B) can have 3 letter suffix.
|
||||||
|
suffix = matches.group('suffix')
|
||||||
|
if suffix is not None and len(suffix) == 3 and prefix != 'B':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# RI plates don't have suffix.
|
||||||
|
if prefix == 'RI' and suffix is not None and suffix != '':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# Number can't be zero.
|
||||||
|
number = matches.group('number')
|
||||||
|
if number == '0':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# CD, CC and B 12345 12
|
||||||
|
if len(number) == 5 or prefix in ('CD', 'CC'):
|
||||||
|
# suffix must be numeric and non-empty
|
||||||
|
if re.match(r'^\d+$', suffix) is None:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
# Known codes range is 12-124
|
||||||
|
if prefix in ('CD', 'CC') and not (12 <= int(number) <= 124):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
if len(number) == 5 and not (12 <= int(suffix) <= 124):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
else:
|
||||||
|
# suffix must be non-numeric
|
||||||
|
if suffix is not None and re.match(r'^[A-Z]{,3}$', suffix) is None:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
return plate_number
|
||||||
|
|
||||||
|
|
||||||
|
class IDNationalIdentityNumberField(Field):
|
||||||
|
"""
|
||||||
|
An Indonesian national identity number (NIK/KTP#) field.
|
||||||
|
|
||||||
|
http://id.wikipedia.org/wiki/Nomor_Induk_Kependudukan
|
||||||
|
|
||||||
|
xx.xxxx.ddmmyy.xxxx - 16 digits (excl. dots)
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid NIK/KTP number'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(IDNationalIdentityNumberField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
value = re.sub(r'[\s.]', '', smart_unicode(value))
|
||||||
|
|
||||||
|
if not nik_re.search(value):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
if int(value) == 0:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
def valid_nik_date(year, month, day):
|
||||||
|
try:
|
||||||
|
t1 = (int(year), int(month), int(day), 0, 0, 0, 0, 0, -1)
|
||||||
|
d = time.mktime(t1)
|
||||||
|
t2 = time.localtime(d)
|
||||||
|
if t1[:3] != t2[:3]:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
except (OverflowError, ValueError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
year = int(value[10:12])
|
||||||
|
month = int(value[8:10])
|
||||||
|
day = int(value[6:8])
|
||||||
|
current_year = time.localtime().tm_year
|
||||||
|
if year < int(str(current_year)[-2:]):
|
||||||
|
if not valid_nik_date(2000 + int(year), month, day):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
elif not valid_nik_date(1900 + int(year), month, day):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
if value[:6] == '000000' or value[12:] == '0000':
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
return '%s.%s.%s.%s' % (value[:2], value[2:6], value[6:12], value[12:])
|
101
django/contrib/localflavor/id/id_choices.py
Normal file
101
django/contrib/localflavor/id/id_choices.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
# Reference: http://id.wikipedia.org/wiki/Daftar_provinsi_Indonesia
|
||||||
|
|
||||||
|
# Indonesia does not have an official Province code standard.
|
||||||
|
# I decided to use unambiguous and consistent (some are common) 3-letter codes.
|
||||||
|
|
||||||
|
PROVINCE_CHOICES = (
|
||||||
|
('BLI', _('Bali')),
|
||||||
|
('BTN', _('Banten')),
|
||||||
|
('BKL', _('Bengkulu')),
|
||||||
|
('DIY', _('Yogyakarta')),
|
||||||
|
('JKT', _('Jakarta')),
|
||||||
|
('GOR', _('Gorontalo')),
|
||||||
|
('JMB', _('Jambi')),
|
||||||
|
('JBR', _('Jawa Barat')),
|
||||||
|
('JTG', _('Jawa Tengah')),
|
||||||
|
('JTM', _('Jawa Timur')),
|
||||||
|
('KBR', _('Kalimantan Barat')),
|
||||||
|
('KSL', _('Kalimantan Selatan')),
|
||||||
|
('KTG', _('Kalimantan Tengah')),
|
||||||
|
('KTM', _('Kalimantan Timur')),
|
||||||
|
('BBL', _('Kepulauan Bangka-Belitung')),
|
||||||
|
('KRI', _('Kepulauan Riau')),
|
||||||
|
('LPG', _('Lampung')),
|
||||||
|
('MLK', _('Maluku')),
|
||||||
|
('MUT', _('Maluku Utara')),
|
||||||
|
('NAD', _('Nanggroe Aceh Darussalam')),
|
||||||
|
('NTB', _('Nusa Tenggara Barat')),
|
||||||
|
('NTT', _('Nusa Tenggara Timur')),
|
||||||
|
('PPA', _('Papua')),
|
||||||
|
('PPB', _('Papua Barat')),
|
||||||
|
('RIU', _('Riau')),
|
||||||
|
('SLB', _('Sulawesi Barat')),
|
||||||
|
('SLS', _('Sulawesi Selatan')),
|
||||||
|
('SLT', _('Sulawesi Tengah')),
|
||||||
|
('SLR', _('Sulawesi Tenggara')),
|
||||||
|
('SLU', _('Sulawesi Utara')),
|
||||||
|
('SMB', _('Sumatera Barat')),
|
||||||
|
('SMS', _('Sumatera Selatan')),
|
||||||
|
('SMU', _('Sumatera Utara')),
|
||||||
|
)
|
||||||
|
|
||||||
|
LICENSE_PLATE_PREFIX_CHOICES = (
|
||||||
|
('A', _('Banten')),
|
||||||
|
('AA', _('Magelang')),
|
||||||
|
('AB', _('Yogyakarta')),
|
||||||
|
('AD', _('Surakarta - Solo')),
|
||||||
|
('AE', _('Madiun')),
|
||||||
|
('AG', _('Kediri')),
|
||||||
|
('B', _('Jakarta')),
|
||||||
|
('BA', _('Sumatera Barat')),
|
||||||
|
('BB', _('Tapanuli')),
|
||||||
|
('BD', _('Bengkulu')),
|
||||||
|
('BE', _('Lampung')),
|
||||||
|
('BG', _('Sumatera Selatan')),
|
||||||
|
('BH', _('Jambi')),
|
||||||
|
('BK', _('Sumatera Utara')),
|
||||||
|
('BL', _('Nanggroe Aceh Darussalam')),
|
||||||
|
('BM', _('Riau')),
|
||||||
|
('BN', _('Kepulauan Bangka Belitung')),
|
||||||
|
('BP', _('Kepulauan Riau')),
|
||||||
|
('CC', _('Corps Consulate')),
|
||||||
|
('CD', _('Corps Diplomatic')),
|
||||||
|
('D', _('Bandung')),
|
||||||
|
('DA', _('Kalimantan Selatan')),
|
||||||
|
('DB', _('Sulawesi Utara Daratan')),
|
||||||
|
('DC', _('Sulawesi Barat')),
|
||||||
|
('DD', _('Sulawesi Selatan')),
|
||||||
|
('DE', _('Maluku')),
|
||||||
|
('DG', _('Maluku Utara')),
|
||||||
|
('DH', _('NTT - Timor')),
|
||||||
|
('DK', _('Bali')),
|
||||||
|
('DL', _('Sulawesi Utara Kepulauan')),
|
||||||
|
('DM', _('Gorontalo')),
|
||||||
|
('DN', _('Sulawesi Tengah')),
|
||||||
|
('DR', _('NTB - Lombok')),
|
||||||
|
('DS', _('Papua dan Papua Barat')),
|
||||||
|
('DT', _('Sulawesi Tenggara')),
|
||||||
|
('E', _('Cirebon')),
|
||||||
|
('EA', _('NTB - Sumbawa')),
|
||||||
|
('EB', _('NTT - Flores')),
|
||||||
|
('ED', _('NTT - Sumba')),
|
||||||
|
('F', _('Bogor')),
|
||||||
|
('G', _('Pekalongan')),
|
||||||
|
('H', _('Semarang')),
|
||||||
|
('K', _('Pati')),
|
||||||
|
('KB', _('Kalimantan Barat')),
|
||||||
|
('KH', _('Kalimantan Tengah')),
|
||||||
|
('KT', _('Kalimantan Timur')),
|
||||||
|
('L', _('Surabaya')),
|
||||||
|
('M', _('Madura')),
|
||||||
|
('N', _('Malang')),
|
||||||
|
('P', _('Jember')),
|
||||||
|
('R', _('Banyumas')),
|
||||||
|
('RI', _('Federal Government')),
|
||||||
|
('S', _('Bojonegoro')),
|
||||||
|
('T', _('Purwakarta')),
|
||||||
|
('W', _('Sidoarjo')),
|
||||||
|
('Z', _('Garut')),
|
||||||
|
)
|
0
django/contrib/localflavor/ie/__init__.py
Normal file
0
django/contrib/localflavor/ie/__init__.py
Normal file
13
django/contrib/localflavor/ie/forms.py
Normal file
13
django/contrib/localflavor/ie/forms.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"""
|
||||||
|
UK-specific Form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.forms.fields import Select
|
||||||
|
|
||||||
|
class IECountySelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of Irish Counties as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from ie_counties import IE_COUNTY_CHOICES
|
||||||
|
super(IECountySelect, self).__init__(attrs, choices=IE_COUNTY_CHOICES)
|
40
django/contrib/localflavor/ie/ie_counties.py
Normal file
40
django/contrib/localflavor/ie/ie_counties.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
"""
|
||||||
|
Sources:
|
||||||
|
Irish Counties: http://en.wikipedia.org/wiki/Counties_of_Ireland
|
||||||
|
"""
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
IE_COUNTY_CHOICES = (
|
||||||
|
('antrim', _('Antrim')),
|
||||||
|
('armagh', _('Armagh')),
|
||||||
|
('carlow', _('Carlow')),
|
||||||
|
('cavan', _('Cavan')),
|
||||||
|
('clare', _('Clare')),
|
||||||
|
('cork', _('Cork')),
|
||||||
|
('derry', _('Derry')),
|
||||||
|
('donegal', _('Donegal')),
|
||||||
|
('down', _('Down')),
|
||||||
|
('dublin', _('Dublin')),
|
||||||
|
('fermanagh', _('Fermanagh')),
|
||||||
|
('galway', _('Galway')),
|
||||||
|
('kerry', _('Kerry')),
|
||||||
|
('kildare', _('Kildare')),
|
||||||
|
('kilkenny', _('Kilkenny')),
|
||||||
|
('laois', _('Laois')),
|
||||||
|
('leitrim', _('Leitrim')),
|
||||||
|
('limerick', _('Limerick')),
|
||||||
|
('longford', _('Longford')),
|
||||||
|
('louth', _('Louth')),
|
||||||
|
('mayo', _('Mayo')),
|
||||||
|
('meath', _('Meath')),
|
||||||
|
('monaghan', _('Monaghan')),
|
||||||
|
('offaly', _('Offaly')),
|
||||||
|
('roscommon', _('Roscommon')),
|
||||||
|
('sligo', _('Sligo')),
|
||||||
|
('tipperary', _('Tipperary')),
|
||||||
|
('tyrone', _('Tyrone')),
|
||||||
|
('waterford', _('Waterford')),
|
||||||
|
('westmeath', _('Westmeath')),
|
||||||
|
('wexford', _('Wexford')),
|
||||||
|
('wicklow', _('Wicklow')),
|
||||||
|
)
|
0
django/contrib/localflavor/kw/__init__.py
Normal file
0
django/contrib/localflavor/kw/__init__.py
Normal file
61
django/contrib/localflavor/kw/forms.py
Normal file
61
django/contrib/localflavor/kw/forms.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""
|
||||||
|
Kuwait-specific Form helpers
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from datetime import date
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.forms.fields import Field, RegexField, EMPTY_VALUES
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
id_re = re.compile(r'^(?P<initial>\d{1})(?P<yy>\d\d)(?P<mm>\d\d)(?P<dd>\d\d)(?P<mid>\d{4})(?P<checksum>\d{1})')
|
||||||
|
|
||||||
|
class KWCivilIDNumberField(Field):
|
||||||
|
"""
|
||||||
|
Kuwaiti Civil ID numbers are 12 digits, second to seventh digits
|
||||||
|
represents the person's birthdate.
|
||||||
|
|
||||||
|
Checks the following rules to determine the validty of the number:
|
||||||
|
* The number consist of 12 digits.
|
||||||
|
* The birthdate of the person is a valid date.
|
||||||
|
* The calculated checksum equals to the last digit of the Civil ID.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a valid Kuwaiti Civil ID number'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def has_valid_checksum(self, value):
|
||||||
|
weight = (2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
|
||||||
|
calculated_checksum = 0
|
||||||
|
for i in range(11):
|
||||||
|
calculated_checksum += int(value[i]) * weight[i]
|
||||||
|
|
||||||
|
remainder = calculated_checksum % 11
|
||||||
|
checkdigit = 11 - remainder
|
||||||
|
if checkdigit != int(value[11]):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(KWCivilIDNumberField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
if not re.match(r'^\d{12}$', value):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
match = re.match(id_re, value)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
gd = match.groupdict()
|
||||||
|
|
||||||
|
try:
|
||||||
|
d = date(int(gd['yy']), int(gd['mm']), int(gd['dd']))
|
||||||
|
except ValueError:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
if not self.has_valid_checksum(value):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
return value
|
0
django/contrib/localflavor/pt/__init__.py
Normal file
0
django/contrib/localflavor/pt/__init__.py
Normal file
47
django/contrib/localflavor/pt/forms.py
Normal file
47
django/contrib/localflavor/pt/forms.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"""
|
||||||
|
PT-specific Form helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
|
||||||
|
from django.utils.encoding import smart_unicode
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
import re
|
||||||
|
|
||||||
|
phone_digits_re = re.compile(r'^(\d{9}|(00|\+)\d*)$')
|
||||||
|
|
||||||
|
|
||||||
|
class PTZipCodeField(RegexField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Enter a zip code in the format XXXX-XXX.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(PTZipCodeField, self).__init__(r'^(\d{4}-\d{3}|\d{7})$',
|
||||||
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self,value):
|
||||||
|
cleaned = super(PTZipCodeField, self).clean(value)
|
||||||
|
if len(cleaned) == 7:
|
||||||
|
return u'%s-%s' % (cleaned[:4],cleaned[4:])
|
||||||
|
else:
|
||||||
|
return cleaned
|
||||||
|
|
||||||
|
class PTPhoneNumberField(Field):
|
||||||
|
"""
|
||||||
|
Validate local Portuguese phone number (including international ones)
|
||||||
|
It should have 9 digits (may include spaces) or start by 00 or + (international)
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _('Phone numbers must have 9 digits, or start by + or 00.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
super(PTPhoneNumberField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
value = re.sub('(\.|\s)', '', smart_unicode(value))
|
||||||
|
m = phone_digits_re.search(value)
|
||||||
|
if m:
|
||||||
|
return u'%s' % value
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
@ -33,7 +33,7 @@ class UKPostcodeField(CharField):
|
|||||||
# Put a single space before the incode (second part).
|
# Put a single space before the incode (second part).
|
||||||
postcode = self.space_regex.sub(r' \1', postcode)
|
postcode = self.space_regex.sub(r' \1', postcode)
|
||||||
if not self.postcode_regex.search(postcode):
|
if not self.postcode_regex.search(postcode):
|
||||||
raise ValidationError(self.default_error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return postcode
|
return postcode
|
||||||
|
|
||||||
class UKCountySelect(Select):
|
class UKCountySelect(Select):
|
||||||
|
@ -4,7 +4,7 @@ USA-specific Form helpers
|
|||||||
|
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select
|
from django.forms.fields import Field, RegexField, Select, CharField
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_unicode
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
import re
|
import re
|
||||||
@ -21,7 +21,7 @@ class USZipCodeField(RegexField):
|
|||||||
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
|
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
|
||||||
max_length=None, min_length=None, *args, **kwargs)
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
|
|
||||||
class USPhoneNumberField(Field):
|
class USPhoneNumberField(CharField):
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db.models.fields import Field, CharField
|
from django.db.models.fields import CharField
|
||||||
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
||||||
|
|
||||||
class USStateField(CharField):
|
class USStateField(CharField):
|
||||||
@ -12,22 +12,16 @@ class USStateField(CharField):
|
|||||||
kwargs['max_length'] = 2
|
kwargs['max_length'] = 2
|
||||||
super(USStateField, self).__init__(*args, **kwargs)
|
super(USStateField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
class PhoneNumberField(Field):
|
class PhoneNumberField(CharField):
|
||||||
|
|
||||||
description = _("Phone number")
|
description = _("Phone number")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def __init__(self, *args, **kwargs):
|
||||||
return "PhoneNumberField"
|
kwargs['max_length'] = 20
|
||||||
|
super(PhoneNumberField, self).__init__(*args, **kwargs)
|
||||||
def db_type(self, connection):
|
|
||||||
if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle':
|
|
||||||
return 'VARCHAR2(20)'
|
|
||||||
else:
|
|
||||||
return 'varchar(20)'
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
from django.contrib.localflavor.us.forms import USPhoneNumberField
|
from django.contrib.localflavor.us.forms import USPhoneNumberField
|
||||||
defaults = {'form_class': USPhoneNumberField}
|
defaults = {'form_class': USPhoneNumberField}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(PhoneNumberField, self).formfield(**defaults)
|
return super(PhoneNumberField, self).formfield(**defaults)
|
||||||
|
|
||||||
|
0
django/contrib/localflavor/uy/__init__.py
Normal file
0
django/contrib/localflavor/uy/__init__.py
Normal file
59
django/contrib/localflavor/uy/forms.py
Normal file
59
django/contrib/localflavor/uy/forms.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
UY-specific form helpers.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.forms.fields import Select, RegexField, EMPTY_VALUES
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.contrib.localflavor.uy.util import get_validation_digit
|
||||||
|
|
||||||
|
|
||||||
|
class UYDepartamentSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of Uruguayan departaments as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from uy_departaments import DEPARTAMENT_CHOICES
|
||||||
|
super(UYDepartamentSelect, self).__init__(attrs, choices=DEPARTAMENT_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
class UYCIField(RegexField):
|
||||||
|
"""
|
||||||
|
A field that validates Uruguayan 'Cedula de identidad' (CI) numbers.
|
||||||
|
"""
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid': _("Enter a valid CI number in X.XXX.XXX-X,"
|
||||||
|
"XXXXXXX-X or XXXXXXXX format."),
|
||||||
|
'invalid_validation_digit': _("Enter a valid CI number."),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(UYCIField, self).__init__(r'(?P<num>(\d{6,7}|(\d\.)?\d{3}\.\d{3}))-?(?P<val>\d)',
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Validates format and validation digit.
|
||||||
|
|
||||||
|
The official format is [X.]XXX.XXX-X but usually dots and/or slash are
|
||||||
|
omitted so, when validating, those characters are ignored if found in
|
||||||
|
the correct place. The three typically used formats are supported:
|
||||||
|
[X]XXXXXXX, [X]XXXXXX-X and [X.]XXX.XXX-X.
|
||||||
|
"""
|
||||||
|
|
||||||
|
value = super(UYCIField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
match = self.regex.match(value)
|
||||||
|
if not match:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
number = int(match.group('num').replace('.', ''))
|
||||||
|
validation_digit = int(match.group('val'))
|
||||||
|
|
||||||
|
if not validation_digit == get_validation_digit(number):
|
||||||
|
raise ValidationError(self.error_messages['invalid_validation_digit'])
|
||||||
|
|
||||||
|
return value
|
12
django/contrib/localflavor/uy/util.py
Normal file
12
django/contrib/localflavor/uy/util.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
def get_validation_digit(number):
|
||||||
|
""" Calculates the validation digit for the given number. """
|
||||||
|
sum = 0
|
||||||
|
dvs = [4, 3, 6, 7, 8, 9, 2]
|
||||||
|
number = str(number)
|
||||||
|
|
||||||
|
for i in range(0, len(number)):
|
||||||
|
sum = (int(number[-1 - i]) * dvs[i] + sum) % 10
|
||||||
|
|
||||||
|
return (10-sum) % 10
|
24
django/contrib/localflavor/uy/uy_departaments.py
Normal file
24
django/contrib/localflavor/uy/uy_departaments.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""A list of Urguayan departaments as `choices` in a formfield."""
|
||||||
|
|
||||||
|
DEPARTAMENT_CHOICES = (
|
||||||
|
('G', u'Artigas'),
|
||||||
|
('A', u'Canelones'),
|
||||||
|
('E', u'Cerro Largo'),
|
||||||
|
('L', u'Colonia'),
|
||||||
|
('Q', u'Durazno'),
|
||||||
|
('N', u'Flores'),
|
||||||
|
('O', u'Florida'),
|
||||||
|
('P', u'Lavalleja'),
|
||||||
|
('B', u'Maldonado'),
|
||||||
|
('S', u'Montevideo'),
|
||||||
|
('I', u'Paysandú'),
|
||||||
|
('J', u'Río Negro'),
|
||||||
|
('F', u'Rivera'),
|
||||||
|
('C', u'Rocha'),
|
||||||
|
('H', u'Salto'),
|
||||||
|
('M', u'San José'),
|
||||||
|
('K', u'Soriano'),
|
||||||
|
('R', u'Tacuarembó'),
|
||||||
|
('D', u'Treinta y Tres'),
|
||||||
|
)
|
@ -17,7 +17,7 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *test_labels, **options):
|
def handle(self, *test_labels, **options):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test.utils import get_runner
|
from django.test.utils import get_runner
|
||||||
|
|
||||||
verbosity = int(options.get('verbosity', 1))
|
verbosity = int(options.get('verbosity', 1))
|
||||||
interactive = options.get('interactive', True)
|
interactive = options.get('interactive', True)
|
||||||
failfast = options.get('failfast', False)
|
failfast = options.get('failfast', False)
|
||||||
@ -25,10 +25,10 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Some custom test runners won't accept the failfast flag, so let's make sure they accept it before passing it to them
|
# Some custom test runners won't accept the failfast flag, so let's make sure they accept it before passing it to them
|
||||||
if 'failfast' in test_runner.func_code.co_varnames:
|
if 'failfast' in test_runner.func_code.co_varnames:
|
||||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive,
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive,
|
||||||
failfast=failfast)
|
failfast=failfast)
|
||||||
else:
|
else:
|
||||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
||||||
|
|
||||||
if failures:
|
if failures:
|
||||||
sys.exit(failures)
|
sys.exit(bool(failures))
|
||||||
|
@ -10,8 +10,7 @@ from django.utils.html import escape, conditional_escape
|
|||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.utils.encoding import StrAndUnicode, force_unicode
|
from django.utils.encoding import StrAndUnicode, force_unicode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.formats import localize
|
from django.utils import datetime_safe, formats
|
||||||
from django.utils import datetime_safe
|
|
||||||
from datetime import time
|
from datetime import time
|
||||||
from util import flatatt
|
from util import flatatt
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
@ -209,7 +208,7 @@ class Input(Widget):
|
|||||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||||
if value != '':
|
if value != '':
|
||||||
# Only add the 'value' attribute if a value is non-empty.
|
# Only add the 'value' attribute if a value is non-empty.
|
||||||
final_attrs['value'] = force_unicode(localize(value, is_input=True))
|
final_attrs['value'] = force_unicode(formats.localize_input(value))
|
||||||
return mark_safe(u'<input%s />' % flatatt(final_attrs))
|
return mark_safe(u'<input%s />' % flatatt(final_attrs))
|
||||||
|
|
||||||
class TextInput(Input):
|
class TextInput(Input):
|
||||||
@ -284,7 +283,7 @@ class Textarea(Widget):
|
|||||||
|
|
||||||
class DateInput(Input):
|
class DateInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = '%Y-%m-%d' # '2006-10-25'
|
format = None
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(DateInput, self).__init__(attrs)
|
super(DateInput, self).__init__(attrs)
|
||||||
@ -295,8 +294,7 @@ class DateInput(Input):
|
|||||||
if value is None:
|
if value is None:
|
||||||
return ''
|
return ''
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
value = datetime_safe.new_date(value)
|
return formats.localize_input(value, self.format)
|
||||||
return value.strftime(self.format)
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
@ -308,7 +306,7 @@ class DateInput(Input):
|
|||||||
|
|
||||||
class DateTimeInput(Input):
|
class DateTimeInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59'
|
format = None
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(DateTimeInput, self).__init__(attrs)
|
super(DateTimeInput, self).__init__(attrs)
|
||||||
@ -319,8 +317,7 @@ class DateTimeInput(Input):
|
|||||||
if value is None:
|
if value is None:
|
||||||
return ''
|
return ''
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
value = datetime_safe.new_datetime(value)
|
return formats.localize_input(value, self.format)
|
||||||
return value.strftime(self.format)
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
@ -332,7 +329,7 @@ class DateTimeInput(Input):
|
|||||||
|
|
||||||
class TimeInput(Input):
|
class TimeInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = '%H:%M:%S' # '14:30:59'
|
format = None
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(TimeInput, self).__init__(attrs)
|
super(TimeInput, self).__init__(attrs)
|
||||||
@ -343,7 +340,7 @@ class TimeInput(Input):
|
|||||||
if value is None:
|
if value is None:
|
||||||
return ''
|
return ''
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
return value.strftime(self.format)
|
return formats.localize_input(value, self.format)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
|
@ -15,10 +15,10 @@ except ImportError:
|
|||||||
|
|
||||||
from django.template import Variable, Library
|
from django.template import Variable, Library
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils import formats
|
||||||
from django.utils.translation import ugettext, ungettext
|
from django.utils.translation import ugettext, ungettext
|
||||||
from django.utils.encoding import force_unicode, iri_to_uri
|
from django.utils.encoding import force_unicode, iri_to_uri
|
||||||
from django.utils.safestring import mark_safe, SafeData
|
from django.utils.safestring import mark_safe, SafeData
|
||||||
from django.utils.formats import date_format, number_format
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
@ -167,14 +167,14 @@ def floatformat(text, arg=-1):
|
|||||||
return input_val
|
return input_val
|
||||||
|
|
||||||
if not m and p < 0:
|
if not m and p < 0:
|
||||||
return mark_safe(number_format(u'%d' % (int(d)), 0))
|
return mark_safe(formats.number_format(u'%d' % (int(d)), 0))
|
||||||
|
|
||||||
if p == 0:
|
if p == 0:
|
||||||
exp = Decimal(1)
|
exp = Decimal(1)
|
||||||
else:
|
else:
|
||||||
exp = Decimal('1.0') / (Decimal(10) ** abs(p))
|
exp = Decimal('1.0') / (Decimal(10) ** abs(p))
|
||||||
try:
|
try:
|
||||||
return mark_safe(number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p)))
|
return mark_safe(formats.number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p)))
|
||||||
except InvalidOperation:
|
except InvalidOperation:
|
||||||
return input_val
|
return input_val
|
||||||
floatformat.is_safe = True
|
floatformat.is_safe = True
|
||||||
@ -686,7 +686,7 @@ def date(value, arg=None):
|
|||||||
if arg is None:
|
if arg is None:
|
||||||
arg = settings.DATE_FORMAT
|
arg = settings.DATE_FORMAT
|
||||||
try:
|
try:
|
||||||
return date_format(value, arg)
|
return formats.date_format(value, arg)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
try:
|
try:
|
||||||
return format(value, arg)
|
return format(value, arg)
|
||||||
@ -696,16 +696,16 @@ date.is_safe = False
|
|||||||
|
|
||||||
def time(value, arg=None):
|
def time(value, arg=None):
|
||||||
"""Formats a time according to the given format."""
|
"""Formats a time according to the given format."""
|
||||||
from django.utils.dateformat import time_format
|
from django.utils import dateformat
|
||||||
if value in (None, u''):
|
if value in (None, u''):
|
||||||
return u''
|
return u''
|
||||||
if arg is None:
|
if arg is None:
|
||||||
arg = settings.TIME_FORMAT
|
arg = settings.TIME_FORMAT
|
||||||
try:
|
try:
|
||||||
return date_format(value, arg)
|
return formats.time_format(value, arg)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
try:
|
try:
|
||||||
return time_format(value, arg)
|
return dateformat.time_format(value, arg)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return ''
|
return ''
|
||||||
time.is_safe = False
|
time.is_safe = False
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import sys
|
||||||
|
import signal
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import get_app, get_apps
|
from django.db.models import get_app, get_apps
|
||||||
from django.test import _doctest as doctest
|
from django.test import _doctest as doctest
|
||||||
@ -11,22 +14,50 @@ TEST_MODULE = 'tests'
|
|||||||
doctestOutputChecker = OutputChecker()
|
doctestOutputChecker = OutputChecker()
|
||||||
|
|
||||||
class DjangoTestRunner(unittest.TextTestRunner):
|
class DjangoTestRunner(unittest.TextTestRunner):
|
||||||
|
|
||||||
def __init__(self, verbosity=0, failfast=False, **kwargs):
|
def __init__(self, verbosity=0, failfast=False, **kwargs):
|
||||||
super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
|
super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
|
||||||
self.failfast = failfast
|
self.failfast = failfast
|
||||||
|
self._keyboard_interrupt_intercepted = False
|
||||||
|
|
||||||
|
def run(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Runs the test suite after registering a custom signal handler
|
||||||
|
that triggers a graceful exit when Ctrl-C is pressed.
|
||||||
|
"""
|
||||||
|
self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
|
||||||
|
self._keyboard_interrupt_handler)
|
||||||
|
try:
|
||||||
|
result = super(DjangoTestRunner, self).run(*args, **kwargs)
|
||||||
|
finally:
|
||||||
|
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _keyboard_interrupt_handler(self, signal_number, stack_frame):
|
||||||
|
"""
|
||||||
|
Handles Ctrl-C by setting a flag that will stop the test run when
|
||||||
|
the currently running test completes.
|
||||||
|
"""
|
||||||
|
self._keyboard_interrupt_intercepted = True
|
||||||
|
sys.stderr.write(" <Test run halted by Ctrl-C> ")
|
||||||
|
# Set the interrupt handler back to the default handler, so that
|
||||||
|
# another Ctrl-C press will trigger immediate exit.
|
||||||
|
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
|
||||||
|
|
||||||
def _makeResult(self):
|
def _makeResult(self):
|
||||||
result = super(DjangoTestRunner, self)._makeResult()
|
result = super(DjangoTestRunner, self)._makeResult()
|
||||||
failfast = self.failfast
|
failfast = self.failfast
|
||||||
|
|
||||||
def stoptest_override(func):
|
def stoptest_override(func):
|
||||||
def stoptest(test):
|
def stoptest(test):
|
||||||
if failfast and not result.wasSuccessful():
|
# If we were set to failfast and the unit test failed,
|
||||||
|
# or if the user has typed Ctrl-C, report and quit
|
||||||
|
if (failfast and not result.wasSuccessful()) or \
|
||||||
|
self._keyboard_interrupt_intercepted:
|
||||||
result.stop()
|
result.stop()
|
||||||
func(test)
|
func(test)
|
||||||
return stoptest
|
return stoptest
|
||||||
|
|
||||||
setattr(result, 'stopTest', stoptest_override(result.stopTest))
|
setattr(result, 'stopTest', stoptest_override(result.stopTest))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from types import GeneratorType
|
||||||
|
|
||||||
from django.utils.copycompat import deepcopy
|
from django.utils.copycompat import deepcopy
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +67,11 @@ class SortedDict(dict):
|
|||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
elif isinstance(data, GeneratorType):
|
||||||
|
# Unfortunately we need to be able to read a generator twice. Once
|
||||||
|
# to get the data into self with our super().__init__ call and a
|
||||||
|
# second time to setup keyOrder correctly
|
||||||
|
data = list(data)
|
||||||
super(SortedDict, self).__init__(data)
|
super(SortedDict, self).__init__(data)
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
self.keyOrder = data.keys()
|
self.keyOrder = data.keys()
|
||||||
|
@ -19,7 +19,7 @@ from django.utils.tzinfo import LocalTimezone
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
re_formatchars = re.compile(r'(?<!\\)([aAbBdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
|
re_formatchars = re.compile(r'(?<!\\)([aAbBcdDfFgGhHiIjlLmMnNOPrsStTUuwWyYzZ])')
|
||||||
re_escaped = re.compile(r'\\(.)')
|
re_escaped = re.compile(r'\\(.)')
|
||||||
|
|
||||||
class Formatter(object):
|
class Formatter(object):
|
||||||
@ -104,6 +104,11 @@ class TimeFormat(Formatter):
|
|||||||
"Seconds; i.e. '00' to '59'"
|
"Seconds; i.e. '00' to '59'"
|
||||||
return u'%02d' % self.data.second
|
return u'%02d' % self.data.second
|
||||||
|
|
||||||
|
def u(self):
|
||||||
|
"Microseconds"
|
||||||
|
return self.data.microsecond
|
||||||
|
|
||||||
|
|
||||||
class DateFormat(TimeFormat):
|
class DateFormat(TimeFormat):
|
||||||
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
||||||
|
|
||||||
@ -118,6 +123,13 @@ class DateFormat(TimeFormat):
|
|||||||
"Month, textual, 3 letters, lowercase; e.g. 'jan'"
|
"Month, textual, 3 letters, lowercase; e.g. 'jan'"
|
||||||
return MONTHS_3[self.data.month]
|
return MONTHS_3[self.data.month]
|
||||||
|
|
||||||
|
def c(self):
|
||||||
|
"""
|
||||||
|
ISO 8601 Format
|
||||||
|
Example : '2008-01-02T10:30:00.000123'
|
||||||
|
"""
|
||||||
|
return self.data.isoformat(' ')
|
||||||
|
|
||||||
def d(self):
|
def d(self):
|
||||||
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
|
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
|
||||||
return u'%02d' % self.data.day
|
return u'%02d' % self.data.day
|
||||||
|
@ -131,12 +131,21 @@ def iri_to_uri(iri):
|
|||||||
|
|
||||||
Returns an ASCII string containing the encoded result.
|
Returns an ASCII string containing the encoded result.
|
||||||
"""
|
"""
|
||||||
# The list of safe characters here is constructed from the printable ASCII
|
# The list of safe characters here is constructed from the "reserved" and
|
||||||
# characters that are not explicitly excluded by the list at the end of
|
# "unreserved" characters specified in sections 2.2 and 2.3 of RFC 3986:
|
||||||
# section 3.1 of RFC 3987.
|
# reserved = gen-delims / sub-delims
|
||||||
|
# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||||
|
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||||
|
# / "*" / "+" / "," / ";" / "="
|
||||||
|
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||||
|
# Of the unreserved characters, urllib.quote already considers all but
|
||||||
|
# the ~ safe.
|
||||||
|
# The % character is also added to the list of safe characters here, as the
|
||||||
|
# end of section 3.1 of RFC 3987 specifically mentions that % must not be
|
||||||
|
# converted.
|
||||||
if iri is None:
|
if iri is None:
|
||||||
return iri
|
return iri
|
||||||
return urllib.quote(smart_str(iri), safe='/#%[]=:;$&()+,!?*')
|
return urllib.quote(smart_str(iri), safe="/#%[]=:;$&()+,!?*@'~")
|
||||||
|
|
||||||
|
|
||||||
# The encoding of the default system locale but falls back to the
|
# The encoding of the default system locale but falls back to the
|
||||||
|
@ -4,15 +4,15 @@ import datetime
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import get_language, to_locale, check_for_language
|
from django.utils.translation import get_language, to_locale, check_for_language
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils import dateformat
|
from django.utils.encoding import smart_str
|
||||||
from django.utils import numberformat
|
from django.utils import dateformat, numberformat, datetime_safe
|
||||||
|
|
||||||
def get_format_modules():
|
def get_format_modules(reverse=False):
|
||||||
"""
|
"""
|
||||||
Returns an iterator over the format modules found in the project and Django
|
Returns an iterator over the format modules found in the project and Django
|
||||||
"""
|
"""
|
||||||
modules = []
|
modules = []
|
||||||
if not check_for_language(get_language()):
|
if not check_for_language(get_language()) or not settings.USE_L10N:
|
||||||
return modules
|
return modules
|
||||||
locale = to_locale(get_language())
|
locale = to_locale(get_language())
|
||||||
if settings.FORMAT_MODULE_PATH:
|
if settings.FORMAT_MODULE_PATH:
|
||||||
@ -30,6 +30,8 @@ def get_format_modules():
|
|||||||
# Don't return duplicates
|
# Don't return duplicates
|
||||||
if mod not in modules:
|
if mod not in modules:
|
||||||
modules.append(mod)
|
modules.append(mod)
|
||||||
|
if reverse:
|
||||||
|
modules.reverse()
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
def get_format(format_type):
|
def get_format(format_type):
|
||||||
@ -38,6 +40,7 @@ def get_format(format_type):
|
|||||||
language (locale), defaults to the format in the settings.
|
language (locale), defaults to the format in the settings.
|
||||||
format_type is the name of the format, e.g. 'DATE_FORMAT'
|
format_type is the name of the format, e.g. 'DATE_FORMAT'
|
||||||
"""
|
"""
|
||||||
|
format_type = smart_str(format_type)
|
||||||
if settings.USE_L10N:
|
if settings.USE_L10N:
|
||||||
for module in get_format_modules():
|
for module in get_format_modules():
|
||||||
try:
|
try:
|
||||||
@ -53,6 +56,12 @@ def date_format(value, format=None):
|
|||||||
"""
|
"""
|
||||||
return dateformat.format(value, get_format(format or 'DATE_FORMAT'))
|
return dateformat.format(value, get_format(format or 'DATE_FORMAT'))
|
||||||
|
|
||||||
|
def time_format(value, format=None):
|
||||||
|
"""
|
||||||
|
Formats a datetime.time object using a localizable format
|
||||||
|
"""
|
||||||
|
return dateformat.time_format(value, get_format(format or 'TIME_FORMAT'))
|
||||||
|
|
||||||
def number_format(value, decimal_pos=None):
|
def number_format(value, decimal_pos=None):
|
||||||
"""
|
"""
|
||||||
Formats a numeric value using localization settings
|
Formats a numeric value using localization settings
|
||||||
@ -65,11 +74,10 @@ def number_format(value, decimal_pos=None):
|
|||||||
get_format('THOUSAND_SEPARATOR'),
|
get_format('THOUSAND_SEPARATOR'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def localize(value, is_input=False):
|
def localize(value):
|
||||||
"""
|
"""
|
||||||
Checks value, and if it has a localizable type (date,
|
Checks if value is a localizable type (date, number...) and returns it
|
||||||
number...) it returns the value as a string using
|
formatted as a string using current locale format
|
||||||
current locale format
|
|
||||||
"""
|
"""
|
||||||
if settings.USE_L10N:
|
if settings.USE_L10N:
|
||||||
if isinstance(value, decimal.Decimal):
|
if isinstance(value, decimal.Decimal):
|
||||||
@ -79,19 +87,27 @@ def localize(value, is_input=False):
|
|||||||
elif isinstance(value, int):
|
elif isinstance(value, int):
|
||||||
return number_format(value)
|
return number_format(value)
|
||||||
elif isinstance(value, datetime.datetime):
|
elif isinstance(value, datetime.datetime):
|
||||||
if not is_input:
|
return date_format(value, 'DATETIME_FORMAT')
|
||||||
return date_format(value, 'DATETIME_FORMAT')
|
|
||||||
else:
|
|
||||||
return value.strftime(get_format('DATETIME_INPUT_FORMATS')[0])
|
|
||||||
elif isinstance(value, datetime.date):
|
elif isinstance(value, datetime.date):
|
||||||
if not is_input:
|
return date_format(value)
|
||||||
return date_format(value)
|
|
||||||
else:
|
|
||||||
return value.strftime(get_format('DATE_INPUT_FORMATS')[0])
|
|
||||||
elif isinstance(value, datetime.time):
|
elif isinstance(value, datetime.time):
|
||||||
if not is_input:
|
return time_format(value, 'TIME_FORMAT')
|
||||||
return date_format(value, 'TIME_FORMAT')
|
|
||||||
else:
|
|
||||||
return value.strftime(get_format('TIME_INPUT_FORMATS')[0])
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def localize_input(value, default=None):
|
||||||
|
"""
|
||||||
|
Checks if an input value is a localizable type and returns it
|
||||||
|
formatted with the appropriate formatting string of the current locale.
|
||||||
|
"""
|
||||||
|
if isinstance(value, datetime.datetime):
|
||||||
|
value = datetime_safe.new_datetime(value)
|
||||||
|
format = smart_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
|
||||||
|
return value.strftime(format)
|
||||||
|
elif isinstance(value, datetime.date):
|
||||||
|
value = datetime_safe.new_date(value)
|
||||||
|
format = smart_str(default or get_format('DATE_INPUT_FORMATS')[0])
|
||||||
|
return value.strftime(format)
|
||||||
|
elif isinstance(value, datetime.time):
|
||||||
|
format = smart_str(default or get_format('TIME_INPUT_FORMATS')[0])
|
||||||
|
return value.strftime(format)
|
||||||
|
return value
|
||||||
|
@ -41,6 +41,9 @@ def to_locale(language, to_lower=False):
|
|||||||
if to_lower:
|
if to_lower:
|
||||||
return language[:p].lower()+'_'+language[p+1:].lower()
|
return language[:p].lower()+'_'+language[p+1:].lower()
|
||||||
else:
|
else:
|
||||||
|
# Get correct locale for sr-latn
|
||||||
|
if len(language[p+1:]) > 2:
|
||||||
|
return language[:p].lower()+'_'+language[p+1].upper()+language[p+2:].lower()
|
||||||
return language[:p].lower()+'_'+language[p+1:].upper()
|
return language[:p].lower()+'_'+language[p+1:].upper()
|
||||||
else:
|
else:
|
||||||
return language.lower()
|
return language.lower()
|
||||||
|
@ -6,6 +6,7 @@ from django.conf import settings
|
|||||||
from django.utils import importlib
|
from django.utils import importlib
|
||||||
from django.utils.translation import check_for_language, activate, to_locale, get_language
|
from django.utils.translation import check_for_language, activate, to_locale, get_language
|
||||||
from django.utils.text import javascript_quote
|
from django.utils.text import javascript_quote
|
||||||
|
from django.utils.encoding import smart_unicode
|
||||||
from django.utils.formats import get_format_modules
|
from django.utils.formats import get_format_modules
|
||||||
|
|
||||||
def set_language(request):
|
def set_language(request):
|
||||||
@ -36,15 +37,17 @@ def set_language(request):
|
|||||||
|
|
||||||
def get_formats():
|
def get_formats():
|
||||||
"""
|
"""
|
||||||
Returns an iterator over all formats in formats file
|
Returns all formats strings required for i18n to work
|
||||||
"""
|
"""
|
||||||
FORMAT_SETTINGS = ('DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
|
FORMAT_SETTINGS = (
|
||||||
|
'DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
|
||||||
'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
|
'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
|
||||||
'SHORT_DATETIME_FORMAT', 'FIRST_DAY_OF_WEEK', 'DECIMAL_SEPARATOR',
|
'SHORT_DATETIME_FORMAT', 'FIRST_DAY_OF_WEEK', 'DECIMAL_SEPARATOR',
|
||||||
'THOUSAND_SEPARATOR', 'NUMBER_GROUPING')
|
'THOUSAND_SEPARATOR', 'NUMBER_GROUPING',
|
||||||
|
'DATE_INPUT_FORMATS', 'TIME_INPUT_FORMATS', 'DATETIME_INPUT_FORMATS'
|
||||||
|
)
|
||||||
result = {}
|
result = {}
|
||||||
for module in [settings] + get_format_modules():
|
for module in [settings] + get_format_modules(reverse=True):
|
||||||
for attr in FORMAT_SETTINGS:
|
for attr in FORMAT_SETTINGS:
|
||||||
try:
|
try:
|
||||||
result[attr] = getattr(module, attr)
|
result[attr] = getattr(module, attr)
|
||||||
@ -140,7 +143,7 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||||||
activate(request.GET['language'])
|
activate(request.GET['language'])
|
||||||
if packages is None:
|
if packages is None:
|
||||||
packages = ['django.conf']
|
packages = ['django.conf']
|
||||||
if type(packages) in (str, unicode):
|
if isinstance(packages, basestring):
|
||||||
packages = packages.split('+')
|
packages = packages.split('+')
|
||||||
packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
|
packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
|
||||||
default_locale = to_locale(settings.LANGUAGE_CODE)
|
default_locale = to_locale(settings.LANGUAGE_CODE)
|
||||||
@ -194,9 +197,9 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||||||
for k, v in t.items():
|
for k, v in t.items():
|
||||||
if k == '':
|
if k == '':
|
||||||
continue
|
continue
|
||||||
if type(k) in (str, unicode):
|
if isinstance(k, basestring):
|
||||||
csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v)))
|
csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v)))
|
||||||
elif type(k) == tuple:
|
elif isinstance(k, tuple):
|
||||||
if k[0] not in pdict:
|
if k[0] not in pdict:
|
||||||
pdict[k[0]] = k[1]
|
pdict[k[0]] = k[1]
|
||||||
else:
|
else:
|
||||||
@ -208,7 +211,11 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||||||
for k, v in pdict.items():
|
for k, v in pdict.items():
|
||||||
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
||||||
for k, v in get_formats().items():
|
for k, v in get_formats().items():
|
||||||
src.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(unicode(v))))
|
if isinstance(v, (basestring, int)):
|
||||||
|
src.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(smart_unicode(v))))
|
||||||
|
elif isinstance(v, (tuple, list)):
|
||||||
|
v = [javascript_quote(smart_unicode(value)) for value in v]
|
||||||
|
src.append("catalog['%s'] = ['%s'];\n" % (javascript_quote(k), "', '".join(v)))
|
||||||
src.extend(csrc)
|
src.extend(csrc)
|
||||||
src.append(LibFoot)
|
src.append(LibFoot)
|
||||||
src.append(InterPolate)
|
src.append(InterPolate)
|
||||||
|
@ -50,13 +50,17 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
|||||||
* Germany_
|
* Germany_
|
||||||
* Iceland_
|
* Iceland_
|
||||||
* India_
|
* India_
|
||||||
|
* Indonesia_
|
||||||
|
* Ireland_
|
||||||
* Italy_
|
* Italy_
|
||||||
* Japan_
|
* Japan_
|
||||||
|
* Kuwait_
|
||||||
* Mexico_
|
* Mexico_
|
||||||
* `The Netherlands`_
|
* `The Netherlands`_
|
||||||
* Norway_
|
* Norway_
|
||||||
* Peru_
|
* Peru_
|
||||||
* Poland_
|
* Poland_
|
||||||
|
* Portugal_
|
||||||
* Romania_
|
* Romania_
|
||||||
* Slovakia_
|
* Slovakia_
|
||||||
* `South Africa`_
|
* `South Africa`_
|
||||||
@ -65,6 +69,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
|||||||
* Switzerland_
|
* Switzerland_
|
||||||
* `United Kingdom`_
|
* `United Kingdom`_
|
||||||
* `United States of America`_
|
* `United States of America`_
|
||||||
|
* Uruguay_
|
||||||
|
|
||||||
The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage,
|
The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage,
|
||||||
containing useful code that is not specific to one particular country or culture.
|
containing useful code that is not specific to one particular country or culture.
|
||||||
@ -92,12 +97,16 @@ Here's an example of how to use them::
|
|||||||
.. _The Netherlands: `The Netherlands (nl)`_
|
.. _The Netherlands: `The Netherlands (nl)`_
|
||||||
.. _Iceland: `Iceland (is\_)`_
|
.. _Iceland: `Iceland (is\_)`_
|
||||||
.. _India: `India (in\_)`_
|
.. _India: `India (in\_)`_
|
||||||
|
.. _Indonesia: `Indonesia (id)`_
|
||||||
|
.. _Ireland: `Ireland (ie)`_
|
||||||
.. _Italy: `Italy (it)`_
|
.. _Italy: `Italy (it)`_
|
||||||
.. _Japan: `Japan (jp)`_
|
.. _Japan: `Japan (jp)`_
|
||||||
|
.. _Kuwait: `Kuwait (kw)`_
|
||||||
.. _Mexico: `Mexico (mx)`_
|
.. _Mexico: `Mexico (mx)`_
|
||||||
.. _Norway: `Norway (no)`_
|
.. _Norway: `Norway (no)`_
|
||||||
.. _Peru: `Peru (pe)`_
|
.. _Peru: `Peru (pe)`_
|
||||||
.. _Poland: `Poland (pl)`_
|
.. _Poland: `Poland (pl)`_
|
||||||
|
.. _Portugal: `Portugal (pt)`_
|
||||||
.. _Romania: `Romania (ro)`_
|
.. _Romania: `Romania (ro)`_
|
||||||
.. _Slovakia: `Slovakia (sk)`_
|
.. _Slovakia: `Slovakia (sk)`_
|
||||||
.. _South Africa: `South Africa (za)`_
|
.. _South Africa: `South Africa (za)`_
|
||||||
@ -106,6 +115,7 @@ Here's an example of how to use them::
|
|||||||
.. _Switzerland: `Switzerland (ch)`_
|
.. _Switzerland: `Switzerland (ch)`_
|
||||||
.. _United Kingdom: `United Kingdom (uk)`_
|
.. _United Kingdom: `United Kingdom (uk)`_
|
||||||
.. _United States of America: `United States of America (us)`_
|
.. _United States of America: `United States of America (us)`_
|
||||||
|
.. _Uruguay: `Uruguay (uy)`_
|
||||||
|
|
||||||
Adding flavors
|
Adding flavors
|
||||||
==============
|
==============
|
||||||
@ -369,6 +379,46 @@ India (``in_``)
|
|||||||
A ``Select`` widget that uses a list of Indian states/territories as its
|
A ``Select`` widget that uses a list of Indian states/territories as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
|
Ireland (``ie``)
|
||||||
|
================
|
||||||
|
|
||||||
|
.. class:: ie.forms.IECountySelect
|
||||||
|
|
||||||
|
A ``Select`` widget that uses a list of Irish Counties as its choices.
|
||||||
|
|
||||||
|
Indonesia (``id``)
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. class:: id.forms.IDPostCodeField
|
||||||
|
|
||||||
|
A form field that validates input as an Indonesian post code field.
|
||||||
|
|
||||||
|
.. class:: id.forms.IDProvinceSelect
|
||||||
|
|
||||||
|
A ``Select`` widget that uses a list of Indonesian provinces as its choices.
|
||||||
|
|
||||||
|
.. class:: id.forms.IDPhoneNumberField
|
||||||
|
|
||||||
|
A form field that validates input as an Indonesian telephone number.
|
||||||
|
|
||||||
|
.. class:: id.forms.IDLicensePlatePrefixSelect
|
||||||
|
|
||||||
|
A ``Select`` widget that uses a list of Indonesian license plate
|
||||||
|
prefix code as its choices.
|
||||||
|
|
||||||
|
.. class:: id.forms.IDLicensePlateField
|
||||||
|
|
||||||
|
A form field that validates input as an Indonesian vehicle license plate.
|
||||||
|
|
||||||
|
.. class:: id.forms.IDNationalIdentityNumberField
|
||||||
|
|
||||||
|
A form field that validates input as an Indonesian national identity
|
||||||
|
number (`NIK`_/KTP). The output will be in the format of
|
||||||
|
'XX.XXXX.DDMMYY.XXXX'. Dots or spaces can be used in the input to break
|
||||||
|
down the numbers.
|
||||||
|
|
||||||
|
.. _NIK: http://en.wikipedia.org/wiki/Indonesian_identity_card
|
||||||
|
|
||||||
Italy (``it``)
|
Italy (``it``)
|
||||||
==============
|
==============
|
||||||
|
|
||||||
@ -408,6 +458,18 @@ Japan (``jp``)
|
|||||||
|
|
||||||
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
|
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
|
||||||
|
|
||||||
|
Kuwait (``kw``)
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. class:: kw.forms.KWCivilIDNumberField
|
||||||
|
|
||||||
|
A form field that validates input as a Kuwaiti Civil ID number. A valid
|
||||||
|
Civil ID number must obey the following rules:
|
||||||
|
|
||||||
|
* The number consist of 12 digits.
|
||||||
|
* The birthdate of the person is a valid date.
|
||||||
|
* The calculated checksum equals to the last digit of the Civil ID.
|
||||||
|
|
||||||
Mexico (``mx``)
|
Mexico (``mx``)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
@ -438,31 +500,31 @@ Norway (``no``)
|
|||||||
Peru (``pe``)
|
Peru (``pe``)
|
||||||
=============
|
=============
|
||||||
|
|
||||||
.. class:: pt.forms.PEDNIField
|
.. class:: pe.forms.PEDNIField
|
||||||
|
|
||||||
A form field that validates input as a DNI (Peruvian national identity)
|
A form field that validates input as a DNI (Peruvian national identity)
|
||||||
number.
|
number.
|
||||||
|
|
||||||
.. class:: pt.forms.PERUCField
|
.. class:: pe.forms.PERUCField
|
||||||
|
|
||||||
A form field that validates input as an RUC (Registro Unico de
|
A form field that validates input as an RUC (Registro Unico de
|
||||||
Contribuyentes) number. Valid RUC numbers have 11 digits.
|
Contribuyentes) number. Valid RUC numbers have 11 digits.
|
||||||
|
|
||||||
.. class:: pt.forms.PEDepartmentSelect
|
.. class:: pe.forms.PEDepartmentSelect
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
|
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
|
||||||
|
|
||||||
Poland (``pl``)
|
Poland (``pl``)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
.. class:: pl.forms.PLNationalIdentificationNumberField
|
.. class:: pl.forms.PLPESELField
|
||||||
|
|
||||||
A form field that validates input as a Polish national identification number
|
A form field that validates input as a Polish national identification number
|
||||||
(PESEL_).
|
(PESEL_).
|
||||||
|
|
||||||
.. _PESEL: http://en.wikipedia.org/wiki/PESEL
|
.. _PESEL: http://en.wikipedia.org/wiki/PESEL
|
||||||
|
|
||||||
.. class:: pl.forms.PLNationalBusinessRegisterField
|
.. class:: pl.forms.PLREGONField
|
||||||
|
|
||||||
A form field that validates input as a Polish National Official Business
|
A form field that validates input as a Polish National Official Business
|
||||||
Register Number (REGON_), having either seven or nine digits. The checksum
|
Register Number (REGON_), having either seven or nine digits. The checksum
|
||||||
@ -476,22 +538,35 @@ Poland (``pl``)
|
|||||||
A form field that validates input as a Polish postal code. The valid format
|
A form field that validates input as a Polish postal code. The valid format
|
||||||
is XX-XXX, where X is a digit.
|
is XX-XXX, where X is a digit.
|
||||||
|
|
||||||
.. class:: pl.forms.PLTaxNumberField
|
.. class:: pl.forms.PLNIPField
|
||||||
|
|
||||||
A form field that validates input as a Polish Tax Number (NIP). Valid
|
A form field that validates input as a Polish Tax Number (NIP). Valid
|
||||||
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
|
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
|
||||||
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
||||||
|
|
||||||
.. class:: pl.forms.PLAdministrativeUnitSelect
|
.. class:: pl.forms.PLCountySelect
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Polish administrative units as its
|
A ``Select`` widget that uses a list of Polish administrative units as its
|
||||||
choices.
|
choices.
|
||||||
|
|
||||||
.. class:: pl.forms.PLVoivodeshipSelect
|
.. class:: pl.forms.PLProvinceSelect
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
||||||
provinces) as its choices.
|
provinces) as its choices.
|
||||||
|
|
||||||
|
Portugal (``pt``)
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. class:: pt.forms.PTZipCodeField
|
||||||
|
|
||||||
|
A form field that validates input as a Portuguese zip code.
|
||||||
|
|
||||||
|
.. class:: pt.forms.PTPhoneNumberField
|
||||||
|
|
||||||
|
A form field that validates input as a Portuguese phone number.
|
||||||
|
Valid numbers have 9 digits (may include spaces) or start by 00
|
||||||
|
or + (international).
|
||||||
|
|
||||||
Romania (``ro``)
|
Romania (``ro``)
|
||||||
================
|
================
|
||||||
|
|
||||||
@ -738,3 +813,15 @@ United States of America (``us``)
|
|||||||
|
|
||||||
A model field that forms represent as a ``forms.USStateField`` field and
|
A model field that forms represent as a ``forms.USStateField`` field and
|
||||||
stores the two-letter U.S. state abbreviation in the database.
|
stores the two-letter U.S. state abbreviation in the database.
|
||||||
|
|
||||||
|
Uruguay (``uy``)
|
||||||
|
================
|
||||||
|
|
||||||
|
.. class:: uy.forms.UYCIField
|
||||||
|
|
||||||
|
A field that validates Uruguayan 'Cedula de identidad' (CI) numbers.
|
||||||
|
|
||||||
|
.. class:: uy.forms.UYDepartamentSelect
|
||||||
|
|
||||||
|
A ``Select`` widget that uses a list of Uruguayan departaments as its
|
||||||
|
choices.
|
||||||
|
@ -812,12 +812,10 @@ test <app or test identifier>
|
|||||||
Runs tests for all installed models. See :ref:`topics-testing` for more
|
Runs tests for all installed models. See :ref:`topics-testing` for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
--failfast
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
.. versionadded:: 1.2
|
.. versionadded:: 1.2
|
||||||
|
.. django-admin-option:: --failfast
|
||||||
|
|
||||||
Use the ``--failfast`` option to stop running tests and report the failure
|
Use the :djadminopt:`--failfast` option to stop running tests and report the failure
|
||||||
immediately after a test fails.
|
immediately after a test fails.
|
||||||
|
|
||||||
testserver <fixture fixture ...>
|
testserver <fixture fixture ...>
|
||||||
|
@ -219,7 +219,7 @@ SQLite. This can be configured using the following::
|
|||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': 'mydatabase'
|
'NAME': 'mydatabase'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -637,6 +637,7 @@ Available format strings:
|
|||||||
A ``'AM'`` or ``'PM'``. ``'AM'``
|
A ``'AM'`` or ``'PM'``. ``'AM'``
|
||||||
b Month, textual, 3 letters, lowercase. ``'jan'``
|
b Month, textual, 3 letters, lowercase. ``'jan'``
|
||||||
B Not implemented.
|
B Not implemented.
|
||||||
|
c ISO 8601 Format. ``2008-01-02 10:30:00.000123``
|
||||||
d Day of the month, 2 digits with ``'01'`` to ``'31'``
|
d Day of the month, 2 digits with ``'01'`` to ``'31'``
|
||||||
leading zeros.
|
leading zeros.
|
||||||
D Day of the week, textual, 3 letters. ``'Fri'``
|
D Day of the week, textual, 3 letters. ``'Fri'``
|
||||||
@ -673,6 +674,7 @@ Available format strings:
|
|||||||
month, 2 characters.
|
month, 2 characters.
|
||||||
t Number of days in the given month. ``28`` to ``31``
|
t Number of days in the given month. ``28`` to ``31``
|
||||||
T Time zone of this machine. ``'EST'``, ``'MDT'``
|
T Time zone of this machine. ``'EST'``, ``'MDT'``
|
||||||
|
u Microseconds. ``0`` to ``999999``
|
||||||
U Seconds since the Unix Epoch
|
U Seconds since the Unix Epoch
|
||||||
(January 1 1970 00:00:00 UTC).
|
(January 1 1970 00:00:00 UTC).
|
||||||
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
|
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
|
||||||
|
@ -19,8 +19,21 @@ development or deployment currently using or targeting Django 1.1.
|
|||||||
For full details on the new features, backwards incompatibilities, and
|
For full details on the new features, backwards incompatibilities, and
|
||||||
deprecated features in the 1.1 branch, see the :ref:`releases-1.1`.
|
deprecated features in the 1.1 branch, see the :ref:`releases-1.1`.
|
||||||
|
|
||||||
|
Backwards-incompatible changes in 1.1.2
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Test runner exit status code
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
The exit status code of the test runners (``tests/runtests.py`` and ``python
|
||||||
|
manage.py test``) no longer represents the number of failed tests, since a
|
||||||
|
failure of 256 or more tests resulted in a wrong exit status code. The exit
|
||||||
|
status code for the test runner is now 0 for success (no failing tests) and 1
|
||||||
|
for any number of test failures. If needed, the number of test failures can be
|
||||||
|
found at the end of the test runner's output.
|
||||||
|
|
||||||
One new feature
|
One new feature
|
||||||
---------------
|
===============
|
||||||
|
|
||||||
Ordinarily, a point release would not include new features, but in the
|
Ordinarily, a point release would not include new features, but in the
|
||||||
case of Django 1.1.2, we have made an exception to this rule. Django
|
case of Django 1.1.2, we have made an exception to this rule. Django
|
||||||
|
@ -232,6 +232,16 @@ party packages, or that you wrote yourself, you should ensure that the
|
|||||||
information, see
|
information, see
|
||||||
:ref:`template tag thread safety considerations<template_tag_thread_safety>`.
|
:ref:`template tag thread safety considerations<template_tag_thread_safety>`.
|
||||||
|
|
||||||
|
Test runner exit status code
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
The exit status code of the test runners (``tests/runtests.py`` and ``python
|
||||||
|
manage.py test``) no longer represents the number of failed tests, since a
|
||||||
|
failure of 256 or more tests resulted in a wrong exit status code. The exit
|
||||||
|
status code for the test runner is now 0 for success (no failing tests) and 1
|
||||||
|
for any number of test failures. If needed, the number of test failures can be
|
||||||
|
found at the end of the test runner's output.
|
||||||
|
|
||||||
.. _deprecated-features-1.2:
|
.. _deprecated-features-1.2:
|
||||||
|
|
||||||
Features deprecated in 1.2
|
Features deprecated in 1.2
|
||||||
@ -471,10 +481,12 @@ Models can now use a 64 bit :class:`~django.db.models.BigIntegerField` type.
|
|||||||
Fast Failure for Tests
|
Fast Failure for Tests
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script
|
The :djadmin:`test` subcommand of ``django-admin.py``, and the ``runtests.py``
|
||||||
used to run Django's own test suite, support a new ``--failfast`` option.
|
script used to run Django's own test suite, support a new ``--failfast`` option.
|
||||||
When specified, this option causes the test runner to exit after
|
When specified, this option causes the test runner to exit after encountering
|
||||||
encountering a failure instead of continuing with the test run.
|
a failure instead of continuing with the test run. In addition, the handling
|
||||||
|
of ``Ctrl-C`` during a test run has been improved to trigger a graceful exit
|
||||||
|
from the test run that reports details of the tests run before the interruption.
|
||||||
|
|
||||||
Improved localization
|
Improved localization
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -34,7 +34,7 @@ Authentication support is bundled as a Django application in
|
|||||||
|
|
||||||
1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
|
1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
|
||||||
your :setting:`INSTALLED_APPS` setting.
|
your :setting:`INSTALLED_APPS` setting.
|
||||||
(The :class:`~django.contrib.auth.models.Permisson` model in
|
(The :class:`~django.contrib.auth.models.Permission` model in
|
||||||
:mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.)
|
:mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.)
|
||||||
2. Run the command ``manage.py syncdb``.
|
2. Run the command ``manage.py syncdb``.
|
||||||
|
|
||||||
|
@ -242,8 +242,8 @@ in different circumstances.
|
|||||||
Running tests
|
Running tests
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Once you've written tests, run them using your project's ``manage.py``
|
Once you've written tests, run them using the :djadmin:`test` subcommand of
|
||||||
utility::
|
your project's ``manage.py`` utility::
|
||||||
|
|
||||||
$ ./manage.py test
|
$ ./manage.py test
|
||||||
|
|
||||||
@ -274,6 +274,23 @@ a test case, add the name of the test method to the label::
|
|||||||
|
|
||||||
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
|
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``.
|
||||||
|
|
||||||
|
If you press ``Ctrl-C`` while the tests are running, the test runner will
|
||||||
|
wait for the currently running test to complete and then exit gracefully.
|
||||||
|
During a graceful exit the test runner will output details of any test
|
||||||
|
failures, report on how many tests were run and how many errors and failures
|
||||||
|
were encountered, and destroy any test databases as usual. Thus pressing
|
||||||
|
``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast`
|
||||||
|
option, notice that some tests are unexpectedly failing, and want to get details
|
||||||
|
on the failures without waiting for the full test run to complete.
|
||||||
|
|
||||||
|
If you do not want to wait for the currently running test to finish, you
|
||||||
|
can press ``Ctrl-C`` a second time and the test run will halt immediately,
|
||||||
|
but not gracefully. No details of the tests run before the interruption will
|
||||||
|
be reported, and any test databases created by the run will not be destroyed.
|
||||||
|
|
||||||
The test database
|
The test database
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@ -63,11 +63,20 @@ class AdminViewBasicTest(TestCase):
|
|||||||
|
|
||||||
def testBasicEditGet(self):
|
def testBasicEditGet(self):
|
||||||
"""
|
"""
|
||||||
A smoke test to ensureGET on the change_view works.
|
A smoke test to ensure GET on the change_view works.
|
||||||
"""
|
"""
|
||||||
response = self.client.get('/test_admin/%s/admin_views/section/1/' % self.urlbit)
|
response = self.client.get('/test_admin/%s/admin_views/section/1/' % self.urlbit)
|
||||||
self.failUnlessEqual(response.status_code, 200)
|
self.failUnlessEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def testBasicEditGetStringPK(self):
|
||||||
|
"""
|
||||||
|
A smoke test to ensure GET on the change_view works (returns an HTTP
|
||||||
|
404 error, see #11191) when passing a string as the PK argument for a
|
||||||
|
model with an integer PK field.
|
||||||
|
"""
|
||||||
|
response = self.client.get('/test_admin/%s/admin_views/section/abc/' % self.urlbit)
|
||||||
|
self.failUnlessEqual(response.status_code, 404)
|
||||||
|
|
||||||
def testBasicAddPost(self):
|
def testBasicAddPost(self):
|
||||||
"""
|
"""
|
||||||
A smoke test to ensure POST on add_view works.
|
A smoke test to ensure POST on add_view works.
|
||||||
|
@ -77,6 +77,9 @@ __test__ = {'WIDGETS_TESTS': """
|
|||||||
>>> from django.contrib.admin.widgets import FilteredSelectMultiple, AdminSplitDateTime
|
>>> from django.contrib.admin.widgets import FilteredSelectMultiple, AdminSplitDateTime
|
||||||
>>> from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget, ManyToManyRawIdWidget
|
>>> from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget, ManyToManyRawIdWidget
|
||||||
>>> from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
>>> from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
||||||
|
>>> from django.utils.translation import activate, deactivate
|
||||||
|
>>> from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
Calling conditional_escape on the output of widget.render will simulate what
|
Calling conditional_escape on the output of widget.render will simulate what
|
||||||
happens in the template. This is easier than setting up a template and context
|
happens in the template. This is easier than setting up a template and context
|
||||||
@ -94,6 +97,12 @@ HTML escaped.
|
|||||||
>>> w = AdminSplitDateTime()
|
>>> w = AdminSplitDateTime()
|
||||||
>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
|
>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
|
||||||
<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
|
||||||
|
<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
>>> band = Band.objects.create(pk=1, name='Linkin Park')
|
>>> band = Band.objects.create(pk=1, name='Linkin Park')
|
||||||
>>> album = band.album_set.create(name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg')
|
>>> album = band.album_set.create(name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg')
|
||||||
|
@ -3,6 +3,7 @@ from django.contrib import admin
|
|||||||
from django.contrib.admin import widgets
|
from django.contrib.admin import widgets
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from django.test import TestCase as DjangoTestCase
|
from django.test import TestCase as DjangoTestCase
|
||||||
|
from django.db.models import DateField
|
||||||
import models
|
import models
|
||||||
|
|
||||||
class AdminFormfieldForDBFieldTests(TestCase):
|
class AdminFormfieldForDBFieldTests(TestCase):
|
||||||
@ -89,7 +90,7 @@ class AdminFormfieldForDBFieldTests(TestCase):
|
|||||||
|
|
||||||
def testFormfieldOverrides(self):
|
def testFormfieldOverrides(self):
|
||||||
self.assertFormfield(models.Event, 'start_date', forms.TextInput,
|
self.assertFormfield(models.Event, 'start_date', forms.TextInput,
|
||||||
formfield_overrides={'widget': forms.TextInput})
|
formfield_overrides={DateField: {'widget': forms.TextInput}})
|
||||||
|
|
||||||
def testFieldWithChoices(self):
|
def testFieldWithChoices(self):
|
||||||
self.assertFormfield(models.Member, 'gender', forms.Select)
|
self.assertFormfield(models.Member, 'gender', forms.Select)
|
||||||
|
@ -60,9 +60,9 @@ MultiValueDictKeyError: "Key 'lastname' not found in <MultiValueDict: {'position
|
|||||||
>>> d.setlist('lastname', ['Holovaty', 'Willison'])
|
>>> d.setlist('lastname', ['Holovaty', 'Willison'])
|
||||||
>>> d.getlist('lastname')
|
>>> d.getlist('lastname')
|
||||||
['Holovaty', 'Willison']
|
['Holovaty', 'Willison']
|
||||||
>>> d.values()
|
>>> d.values()
|
||||||
['Developer', 'Simon', 'Willison']
|
['Developer', 'Simon', 'Willison']
|
||||||
>>> list(d.itervalues())
|
>>> list(d.itervalues())
|
||||||
['Developer', 'Simon', 'Willison']
|
['Developer', 'Simon', 'Willison']
|
||||||
|
|
||||||
### SortedDict #################################################################
|
### SortedDict #################################################################
|
||||||
@ -95,6 +95,9 @@ True
|
|||||||
>>> d.pop('one', 'missing')
|
>>> d.pop('one', 'missing')
|
||||||
'missing'
|
'missing'
|
||||||
|
|
||||||
|
>>> SortedDict((i, i) for i in xrange(3))
|
||||||
|
{0: 0, 1: 1, 2: 2}
|
||||||
|
|
||||||
We don't know which item will be popped in popitem(), so we'll just check that
|
We don't know which item will be popped in popitem(), so we'll just check that
|
||||||
the number of keys has decreased.
|
the number of keys has decreased.
|
||||||
>>> l = len(d)
|
>>> l = len(d)
|
||||||
|
@ -39,8 +39,10 @@ class DateFormatTests(TestCase):
|
|||||||
|
|
||||||
def test_date_formats(self):
|
def test_date_formats(self):
|
||||||
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
||||||
|
timestamp = datetime.datetime(2008, 5, 19, 11, 45, 23, 123456)
|
||||||
|
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'A'), u'PM')
|
self.assertEquals(dateformat.format(my_birthday, 'A'), u'PM')
|
||||||
|
self.assertEquals(dateformat.format(timestamp, 'c'), u'2008-05-19 11:45:23.123456')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'd'), u'08')
|
self.assertEquals(dateformat.format(my_birthday, 'd'), u'08')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'j'), u'8')
|
self.assertEquals(dateformat.format(my_birthday, 'j'), u'8')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'l'), u'Sunday')
|
self.assertEquals(dateformat.format(my_birthday, 'l'), u'Sunday')
|
||||||
@ -79,12 +81,14 @@ class DateFormatTests(TestCase):
|
|||||||
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
||||||
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
||||||
wintertime = datetime.datetime(2005, 10, 30, 4, 00)
|
wintertime = datetime.datetime(2005, 10, 30, 4, 00)
|
||||||
|
timestamp = datetime.datetime(2008, 5, 19, 11, 45, 23, 123456)
|
||||||
|
|
||||||
if self.tz_tests:
|
if self.tz_tests:
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'O'), u'+0100')
|
self.assertEquals(dateformat.format(my_birthday, 'O'), u'+0100')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'r'), u'Sun, 8 Jul 1979 22:00:00 +0100')
|
self.assertEquals(dateformat.format(my_birthday, 'r'), u'Sun, 8 Jul 1979 22:00:00 +0100')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'T'), u'CET')
|
self.assertEquals(dateformat.format(my_birthday, 'T'), u'CET')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'U'), u'300315600')
|
self.assertEquals(dateformat.format(my_birthday, 'U'), u'300315600')
|
||||||
|
self.assertEquals(dateformat.format(timestamp, 'u'), u'123456')
|
||||||
self.assertEquals(dateformat.format(my_birthday, 'Z'), u'3600')
|
self.assertEquals(dateformat.format(my_birthday, 'Z'), u'3600')
|
||||||
self.assertEquals(dateformat.format(summertime, 'I'), u'1')
|
self.assertEquals(dateformat.format(summertime, 'I'), u'1')
|
||||||
self.assertEquals(dateformat.format(summertime, 'O'), u'+0200')
|
self.assertEquals(dateformat.format(summertime, 'O'), u'+0200')
|
||||||
|
175
tests/regressiontests/forms/localflavor/id.py
Normal file
175
tests/regressiontests/forms/localflavor/id.py
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ ID form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
|
||||||
|
# IDPhoneNumberField ########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDPhoneNumberField
|
||||||
|
>>> f = IDPhoneNumberField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean('0812-3456789')
|
||||||
|
u'0812-3456789'
|
||||||
|
>>> f.clean('081234567890')
|
||||||
|
u'081234567890'
|
||||||
|
>>> f.clean('021 345 6789')
|
||||||
|
u'021 345 6789'
|
||||||
|
>>> f.clean('0213456789')
|
||||||
|
u'0213456789'
|
||||||
|
>>> f.clean('0123456789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
>>> f.clean('+62-21-3456789')
|
||||||
|
u'+62-21-3456789'
|
||||||
|
>>> f.clean('+62-021-3456789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
>>> f.clean('(021) 345 6789')
|
||||||
|
u'(021) 345 6789'
|
||||||
|
>>> f.clean('+62-021-3456789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
>>> f.clean('+62-0812-3456789')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
>>> f.clean('0812345678901')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid phone number']
|
||||||
|
|
||||||
|
# IDPostCodeField ############################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDPostCodeField
|
||||||
|
>>> f = IDPostCodeField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean('12340')
|
||||||
|
u'12340'
|
||||||
|
>>> f.clean('25412')
|
||||||
|
u'25412'
|
||||||
|
>>> f.clean(' 12340 ')
|
||||||
|
u'12340'
|
||||||
|
>>> f.clean('12 3 4 0')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid post code']
|
||||||
|
>>> f.clean('12345')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid post code']
|
||||||
|
>>> f.clean('10100')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid post code']
|
||||||
|
>>> f.clean('123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid post code']
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid post code']
|
||||||
|
|
||||||
|
# IDNationalIdentityNumberField #########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDNationalIdentityNumberField
|
||||||
|
>>> f = IDNationalIdentityNumberField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(' 12.3456.010178 3456 ')
|
||||||
|
u'12.3456.010178.3456'
|
||||||
|
>>> f.clean('1234560101783456')
|
||||||
|
u'12.3456.010178.3456'
|
||||||
|
>>> f.clean('12.3456.010101.3456')
|
||||||
|
u'12.3456.010101.3456'
|
||||||
|
>>> f.clean('12.3456.310278.3456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid NIK/KTP number']
|
||||||
|
>>> f.clean('00.0000.010101.0000')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid NIK/KTP number']
|
||||||
|
>>> f.clean('1234567890123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid NIK/KTP number']
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid NIK/KTP number']
|
||||||
|
|
||||||
|
# IDProvinceSelect ##########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDProvinceSelect
|
||||||
|
>>> s = IDProvinceSelect()
|
||||||
|
>>> s.render('provinces', 'LPG')
|
||||||
|
u'<select name="provinces">\n<option value="BLI">Bali</option>\n<option value="BTN">Banten</option>\n<option value="BKL">Bengkulu</option>\n<option value="DIY">Yogyakarta</option>\n<option value="JKT">Jakarta</option>\n<option value="GOR">Gorontalo</option>\n<option value="JMB">Jambi</option>\n<option value="JBR">Jawa Barat</option>\n<option value="JTG">Jawa Tengah</option>\n<option value="JTM">Jawa Timur</option>\n<option value="KBR">Kalimantan Barat</option>\n<option value="KSL">Kalimantan Selatan</option>\n<option value="KTG">Kalimantan Tengah</option>\n<option value="KTM">Kalimantan Timur</option>\n<option value="BBL">Kepulauan Bangka-Belitung</option>\n<option value="KRI">Kepulauan Riau</option>\n<option value="LPG" selected="selected">Lampung</option>\n<option value="MLK">Maluku</option>\n<option value="MUT">Maluku Utara</option>\n<option value="NAD">Nanggroe Aceh Darussalam</option>\n<option value="NTB">Nusa Tenggara Barat</option>\n<option value="NTT">Nusa Tenggara Timur</option>\n<option value="PPA">Papua</option>\n<option value="PPB">Papua Barat</option>\n<option value="RIU">Riau</option>\n<option value="SLB">Sulawesi Barat</option>\n<option value="SLS">Sulawesi Selatan</option>\n<option value="SLT">Sulawesi Tengah</option>\n<option value="SLR">Sulawesi Tenggara</option>\n<option value="SLU">Sulawesi Utara</option>\n<option value="SMB">Sumatera Barat</option>\n<option value="SMS">Sumatera Selatan</option>\n<option value="SMU">Sumatera Utara</option>\n</select>'
|
||||||
|
|
||||||
|
# IDLicensePlatePrefixelect ########################################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDLicensePlatePrefixSelect
|
||||||
|
>>> s = IDLicensePlatePrefixSelect()
|
||||||
|
>>> s.render('codes', 'BE')
|
||||||
|
u'<select name="codes">\n<option value="A">Banten</option>\n<option value="AA">Magelang</option>\n<option value="AB">Yogyakarta</option>\n<option value="AD">Surakarta - Solo</option>\n<option value="AE">Madiun</option>\n<option value="AG">Kediri</option>\n<option value="B">Jakarta</option>\n<option value="BA">Sumatera Barat</option>\n<option value="BB">Tapanuli</option>\n<option value="BD">Bengkulu</option>\n<option value="BE" selected="selected">Lampung</option>\n<option value="BG">Sumatera Selatan</option>\n<option value="BH">Jambi</option>\n<option value="BK">Sumatera Utara</option>\n<option value="BL">Nanggroe Aceh Darussalam</option>\n<option value="BM">Riau</option>\n<option value="BN">Kepulauan Bangka Belitung</option>\n<option value="BP">Kepulauan Riau</option>\n<option value="CC">Corps Consulate</option>\n<option value="CD">Corps Diplomatic</option>\n<option value="D">Bandung</option>\n<option value="DA">Kalimantan Selatan</option>\n<option value="DB">Sulawesi Utara Daratan</option>\n<option value="DC">Sulawesi Barat</option>\n<option value="DD">Sulawesi Selatan</option>\n<option value="DE">Maluku</option>\n<option value="DG">Maluku Utara</option>\n<option value="DH">NTT - Timor</option>\n<option value="DK">Bali</option>\n<option value="DL">Sulawesi Utara Kepulauan</option>\n<option value="DM">Gorontalo</option>\n<option value="DN">Sulawesi Tengah</option>\n<option value="DR">NTB - Lombok</option>\n<option value="DS">Papua dan Papua Barat</option>\n<option value="DT">Sulawesi Tenggara</option>\n<option value="E">Cirebon</option>\n<option value="EA">NTB - Sumbawa</option>\n<option value="EB">NTT - Flores</option>\n<option value="ED">NTT - Sumba</option>\n<option value="F">Bogor</option>\n<option value="G">Pekalongan</option>\n<option value="H">Semarang</option>\n<option value="K">Pati</option>\n<option value="KB">Kalimantan Barat</option>\n<option value="KH">Kalimantan Tengah</option>\n<option value="KT">Kalimantan Timur</option>\n<option value="L">Surabaya</option>\n<option value="M">Madura</option>\n<option value="N">Malang</option>\n<option value="P">Jember</option>\n<option value="R">Banyumas</option>\n<option value="RI">Federal Government</option>\n<option value="S">Bojonegoro</option>\n<option value="T">Purwakarta</option>\n<option value="W">Sidoarjo</option>\n<option value="Z">Garut</option>\n</select>'
|
||||||
|
|
||||||
|
# IDLicensePlateField #######################################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.id.forms import IDLicensePlateField
|
||||||
|
>>> f = IDLicensePlateField(required=False)
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(' b 1234 ab ')
|
||||||
|
u'B 1234 AB'
|
||||||
|
>>> f.clean('B 1234 ABC')
|
||||||
|
u'B 1234 ABC'
|
||||||
|
>>> f.clean('A 12')
|
||||||
|
u'A 12'
|
||||||
|
>>> f.clean('DK 12345 12')
|
||||||
|
u'DK 12345 12'
|
||||||
|
>>> f.clean('RI 10')
|
||||||
|
u'RI 10'
|
||||||
|
>>> f.clean('CD 12 12')
|
||||||
|
u'CD 12 12'
|
||||||
|
>>> f.clean('CD 10 12')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('CD 1234 12')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('RI 10 AB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('B 12345 01')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('N 1234 12')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('A 12 XYZ')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('Q 1234 AB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid vehicle license plate number']
|
||||||
|
"""
|
12
tests/regressiontests/forms/localflavor/ie.py
Normal file
12
tests/regressiontests/forms/localflavor/ie.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ie form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# IECountySelect #########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.ie.forms import IECountySelect
|
||||||
|
>>> f = IECountySelect()
|
||||||
|
>>> f.render('counties', 'dublin')
|
||||||
|
u'<select name="counties">\n<option value="antrim">Antrim</option>\n<option value="armagh">Armagh</option>\n<option value="carlow">Carlow</option>\n<option value="cavan">Cavan</option>\n<option value="clare">Clare</option>\n<option value="cork">Cork</option>\n<option value="derry">Derry</option>\n<option value="donegal">Donegal</option>\n<option value="down">Down</option>\n<option value="dublin" selected="selected">Dublin</option>\n<option value="fermanagh">Fermanagh</option>\n<option value="galway">Galway</option>\n<option value="kerry">Kerry</option>\n<option value="kildare">Kildare</option>\n<option value="kilkenny">Kilkenny</option>\n<option value="laois">Laois</option>\n<option value="leitrim">Leitrim</option>\n<option value="limerick">Limerick</option>\n<option value="longford">Longford</option>\n<option value="louth">Louth</option>\n<option value="mayo">Mayo</option>\n<option value="meath">Meath</option>\n<option value="monaghan">Monaghan</option>\n<option value="offaly">Offaly</option>\n<option value="roscommon">Roscommon</option>\n<option value="sligo">Sligo</option>\n<option value="tipperary">Tipperary</option>\n<option value="tyrone">Tyrone</option>\n<option value="waterford">Waterford</option>\n<option value="westmeath">Westmeath</option>\n<option value="wexford">Wexford</option>\n<option value="wicklow">Wicklow</option>\n</select>'
|
||||||
|
|
||||||
|
"""
|
15
tests/regressiontests/forms/localflavor/kw.py
Normal file
15
tests/regressiontests/forms/localflavor/kw.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ KW form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# KWCivilIDNumberField ########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.kw.forms import KWCivilIDNumberField
|
||||||
|
>>> f = KWCivilIDNumberField()
|
||||||
|
>>> f.clean('282040701483')
|
||||||
|
'282040701483'
|
||||||
|
>>> f.clean('289332013455')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid Kuwaiti Civil ID number']
|
||||||
|
"""
|
106
tests/regressiontests/forms/localflavor/pt.py
Normal file
106
tests/regressiontests/forms/localflavor/pt.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ PT form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# PTZipCodeField #############################################################
|
||||||
|
|
||||||
|
PTZipCodeField validates that the data is a valid PT zipcode.
|
||||||
|
>>> from django.contrib.localflavor.pt.forms import PTZipCodeField
|
||||||
|
>>> f = PTZipCodeField()
|
||||||
|
>>> f.clean('3030-034')
|
||||||
|
u'3030-034'
|
||||||
|
>>> f.clean('1003456')
|
||||||
|
u'1003-456'
|
||||||
|
>>> f.clean('2A200')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a zip code in the format XXXX-XXX.']
|
||||||
|
>>> f.clean('980001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a zip code in the format XXXX-XXX.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = PTZipCodeField(required=False)
|
||||||
|
>>> f.clean('3030-034')
|
||||||
|
u'3030-034'
|
||||||
|
>>> f.clean('1003456')
|
||||||
|
u'1003-456'
|
||||||
|
>>> f.clean('2A200')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a zip code in the format XXXX-XXX.']
|
||||||
|
>>> f.clean('980001')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a zip code in the format XXXX-XXX.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# PTPhoneNumberField ##########################################################
|
||||||
|
|
||||||
|
PTPhoneNumberField validates that the data is a valid Portuguese phone number.
|
||||||
|
It's normalized to XXXXXXXXX format or +X(X) for international numbers. Dots are valid too.
|
||||||
|
>>> from django.contrib.localflavor.pt.forms import PTPhoneNumberField
|
||||||
|
>>> f = PTPhoneNumberField()
|
||||||
|
>>> f.clean('917845189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('91 784 5189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('91 784 5189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('+351 91 111')
|
||||||
|
u'+35191111'
|
||||||
|
>>> f.clean('00351873')
|
||||||
|
u'00351873'
|
||||||
|
>>> f.clean('91 784 51 8')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Phone numbers must have 9 digits, or start by + or 00.']
|
||||||
|
>>> f.clean('091 456 987 1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Phone numbers must have 9 digits, or start by + or 00.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = PTPhoneNumberField(required=False)
|
||||||
|
>>> f.clean('917845189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('91 784 5189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('91 784 5189')
|
||||||
|
u'917845189'
|
||||||
|
>>> f.clean('+351 91 111')
|
||||||
|
u'+35191111'
|
||||||
|
>>> f.clean('00351873')
|
||||||
|
u'00351873'
|
||||||
|
>>> f.clean('91 784 51 8')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Phone numbers must have 9 digits, or start by + or 00.']
|
||||||
|
>>> f.clean('091 456 987 1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Phone numbers must have 9 digits, or start by + or 00.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
|
||||||
|
"""
|
@ -58,4 +58,15 @@ u'BT32 4PX'
|
|||||||
u''
|
u''
|
||||||
>>> f.clean('')
|
>>> f.clean('')
|
||||||
u''
|
u''
|
||||||
|
>>> class MyUKPostcodeField(UKPostcodeField):
|
||||||
|
... default_error_messages = {
|
||||||
|
... 'invalid': 'Enter a bloody postcode!',
|
||||||
|
... }
|
||||||
|
...
|
||||||
|
>>>
|
||||||
|
>>> f = MyUKPostcodeField(required=False)
|
||||||
|
>>> f.clean('1NV 4L1D')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a bloody postcode!']
|
||||||
"""
|
"""
|
||||||
|
46
tests/regressiontests/forms/localflavor/uy.py
Normal file
46
tests/regressiontests/forms/localflavor/uy.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Tests for the contrib/localflavor/ UY form fields.
|
||||||
|
|
||||||
|
tests = r"""
|
||||||
|
# UYDepartamentSelect #########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.uy.forms import UYDepartamentSelect
|
||||||
|
>>> f = UYDepartamentSelect()
|
||||||
|
>>> f.render('departamentos', 'S')
|
||||||
|
u'<select name="departamentos">\n<option value="G">Artigas</option>\n<option value="A">Canelones</option>\n<option value="E">Cerro Largo</option>\n<option value="L">Colonia</option>\n<option value="Q">Durazno</option>\n<option value="N">Flores</option>\n<option value="O">Florida</option>\n<option value="P">Lavalleja</option>\n<option value="B">Maldonado</option>\n<option value="S" selected="selected">Montevideo</option>\n<option value="I">Paysand\xfa</option>\n<option value="J">R\xedo Negro</option>\n<option value="F">Rivera</option>\n<option value="C">Rocha</option>\n<option value="H">Salto</option>\n<option value="M">San Jos\xe9</option>\n<option value="K">Soriano</option>\n<option value="R">Tacuaremb\xf3</option>\n<option value="D">Treinta y Tres</option>\n</select>'
|
||||||
|
|
||||||
|
# UYCIField ###################################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.uy.util import get_validation_digit
|
||||||
|
>>> get_validation_digit(409805) == 3
|
||||||
|
True
|
||||||
|
>>> get_validation_digit(1005411) == 2
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.uy.forms import UYCIField
|
||||||
|
>>> f = UYCIField()
|
||||||
|
>>> f.clean('4098053')
|
||||||
|
u'4098053'
|
||||||
|
>>> f.clean('409805-3')
|
||||||
|
u'409805-3'
|
||||||
|
>>> f.clean('409.805-3')
|
||||||
|
u'409.805-3'
|
||||||
|
>>> f.clean('10054112')
|
||||||
|
u'10054112'
|
||||||
|
>>> f.clean('1005411-2')
|
||||||
|
u'1005411-2'
|
||||||
|
>>> f.clean('1.005.411-2')
|
||||||
|
u'1.005.411-2'
|
||||||
|
>>> f.clean('foo')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CI number in X.XXX.XXX-X,XXXXXXX-X or XXXXXXXX format.']
|
||||||
|
>>> f.clean('409805-2')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CI number.']
|
||||||
|
>>> f.clean('1.005.411-5')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CI number.']
|
||||||
|
"""
|
@ -15,16 +15,21 @@ from localflavor.es import tests as localflavor_es_tests
|
|||||||
from localflavor.fi import tests as localflavor_fi_tests
|
from localflavor.fi import tests as localflavor_fi_tests
|
||||||
from localflavor.fr import tests as localflavor_fr_tests
|
from localflavor.fr import tests as localflavor_fr_tests
|
||||||
from localflavor.generic import tests as localflavor_generic_tests
|
from localflavor.generic import tests as localflavor_generic_tests
|
||||||
|
from localflavor.id import tests as localflavor_id_tests
|
||||||
|
from localflavor.ie import tests as localflavor_ie_tests
|
||||||
from localflavor.is_ import tests as localflavor_is_tests
|
from localflavor.is_ import tests as localflavor_is_tests
|
||||||
from localflavor.it import tests as localflavor_it_tests
|
from localflavor.it import tests as localflavor_it_tests
|
||||||
from localflavor.jp import tests as localflavor_jp_tests
|
from localflavor.jp import tests as localflavor_jp_tests
|
||||||
|
from localflavor.kw import tests as localflavor_kw_tests
|
||||||
from localflavor.nl import tests as localflavor_nl_tests
|
from localflavor.nl import tests as localflavor_nl_tests
|
||||||
from localflavor.pl import tests as localflavor_pl_tests
|
from localflavor.pl import tests as localflavor_pl_tests
|
||||||
|
from localflavor.pt import tests as localflavor_pt_tests
|
||||||
from localflavor.ro import tests as localflavor_ro_tests
|
from localflavor.ro import tests as localflavor_ro_tests
|
||||||
from localflavor.se import tests as localflavor_se_tests
|
from localflavor.se import tests as localflavor_se_tests
|
||||||
from localflavor.sk import tests as localflavor_sk_tests
|
from localflavor.sk import tests as localflavor_sk_tests
|
||||||
from localflavor.uk import tests as localflavor_uk_tests
|
from localflavor.uk import tests as localflavor_uk_tests
|
||||||
from localflavor.us import tests as localflavor_us_tests
|
from localflavor.us import tests as localflavor_us_tests
|
||||||
|
from localflavor.uy import tests as localflavor_uy_tests
|
||||||
from localflavor.za import tests as localflavor_za_tests
|
from localflavor.za import tests as localflavor_za_tests
|
||||||
from regressions import tests as regression_tests
|
from regressions import tests as regression_tests
|
||||||
from util import tests as util_tests
|
from util import tests as util_tests
|
||||||
@ -52,16 +57,21 @@ __test__ = {
|
|||||||
'localflavor_fi_tests': localflavor_fi_tests,
|
'localflavor_fi_tests': localflavor_fi_tests,
|
||||||
'localflavor_fr_tests': localflavor_fr_tests,
|
'localflavor_fr_tests': localflavor_fr_tests,
|
||||||
'localflavor_generic_tests': localflavor_generic_tests,
|
'localflavor_generic_tests': localflavor_generic_tests,
|
||||||
|
'localflavor_id_tests': localflavor_id_tests,
|
||||||
|
'localflavor_ie_tests': localflavor_ie_tests,
|
||||||
'localflavor_is_tests': localflavor_is_tests,
|
'localflavor_is_tests': localflavor_is_tests,
|
||||||
'localflavor_it_tests': localflavor_it_tests,
|
'localflavor_it_tests': localflavor_it_tests,
|
||||||
'localflavor_jp_tests': localflavor_jp_tests,
|
'localflavor_jp_tests': localflavor_jp_tests,
|
||||||
|
'localflavor_kw_tests': localflavor_kw_tests,
|
||||||
'localflavor_nl_tests': localflavor_nl_tests,
|
'localflavor_nl_tests': localflavor_nl_tests,
|
||||||
'localflavor_pl_tests': localflavor_pl_tests,
|
'localflavor_pl_tests': localflavor_pl_tests,
|
||||||
|
'localflavor_pt_tests': localflavor_pt_tests,
|
||||||
'localflavor_ro_tests': localflavor_ro_tests,
|
'localflavor_ro_tests': localflavor_ro_tests,
|
||||||
'localflavor_se_tests': localflavor_se_tests,
|
'localflavor_se_tests': localflavor_se_tests,
|
||||||
'localflavor_sk_tests': localflavor_sk_tests,
|
'localflavor_sk_tests': localflavor_sk_tests,
|
||||||
'localflavor_uk_tests': localflavor_uk_tests,
|
'localflavor_uk_tests': localflavor_uk_tests,
|
||||||
'localflavor_us_tests': localflavor_us_tests,
|
'localflavor_us_tests': localflavor_us_tests,
|
||||||
|
'localflavor_uy_tests': localflavor_uy_tests,
|
||||||
'localflavor_za_tests': localflavor_za_tests,
|
'localflavor_za_tests': localflavor_za_tests,
|
||||||
'regression_tests': regression_tests,
|
'regression_tests': regression_tests,
|
||||||
'formset_tests': formset_tests,
|
'formset_tests': formset_tests,
|
||||||
|
@ -10,6 +10,8 @@ tests = r"""
|
|||||||
... from decimal import Decimal
|
... from decimal import Decimal
|
||||||
... except ImportError:
|
... except ImportError:
|
||||||
... from django.utils._decimal import Decimal
|
... from django.utils._decimal import Decimal
|
||||||
|
>>> from django.utils.translation import activate, deactivate
|
||||||
|
>>> from django.conf import settings
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# Widgets #
|
# Widgets #
|
||||||
@ -1082,6 +1084,13 @@ True
|
|||||||
False
|
False
|
||||||
>>> w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06/05/2008', u'12:41'])
|
>>> w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06/05/2008', u'12:41'])
|
||||||
True
|
True
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06.05.2008', u'12:41'])
|
||||||
|
True
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
|
|
||||||
# DateTimeInput ###############################################################
|
# DateTimeInput ###############################################################
|
||||||
|
|
||||||
@ -1099,6 +1108,12 @@ u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
|
|||||||
u'<input type="text" name="date" value="2007-09-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))
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||||
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
|
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.render('date', d)
|
||||||
|
u'<input type="text" name="date" value="17.09.2007 12:51:34" />'
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
Use 'format' to change the way a value is displayed.
|
Use 'format' to change the way a value is displayed.
|
||||||
>>> w = DateTimeInput(format='%d/%m/%Y %H:%M')
|
>>> w = DateTimeInput(format='%d/%m/%Y %H:%M')
|
||||||
@ -1107,6 +1122,7 @@ u'<input type="text" name="date" value="17/09/2007 12:51" />'
|
|||||||
>>> w._has_changed(d, '17/09/2007 12:51')
|
>>> w._has_changed(d, '17/09/2007 12:51')
|
||||||
False
|
False
|
||||||
|
|
||||||
|
|
||||||
# DateInput ###################################################################
|
# DateInput ###################################################################
|
||||||
|
|
||||||
>>> w = DateInput()
|
>>> w = DateInput()
|
||||||
@ -1125,6 +1141,13 @@ We should be able to initialize from a unicode value.
|
|||||||
>>> w.render('date', u'2007-09-17')
|
>>> w.render('date', u'2007-09-17')
|
||||||
u'<input type="text" name="date" value="2007-09-17" />'
|
u'<input type="text" name="date" value="2007-09-17" />'
|
||||||
|
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.render('date', d)
|
||||||
|
u'<input type="text" name="date" value="17.09.2007" />'
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
Use 'format' to change the way a value is displayed.
|
Use 'format' to change the way a value is displayed.
|
||||||
>>> w = DateInput(format='%d/%m/%Y')
|
>>> w = DateInput(format='%d/%m/%Y')
|
||||||
>>> w.render('date', d)
|
>>> w.render('date', d)
|
||||||
@ -1153,6 +1176,13 @@ We should be able to initialize from a unicode value.
|
|||||||
>>> w.render('time', u'13:12:11')
|
>>> w.render('time', u'13:12:11')
|
||||||
u'<input type="text" name="time" value="13:12:11" />'
|
u'<input type="text" name="time" value="13:12:11" />'
|
||||||
|
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.render('date', d)
|
||||||
|
u'<input type="text" name="date" value="17.09.2007" />'
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
Use 'format' to change the way a value is displayed.
|
Use 'format' to change the way a value is displayed.
|
||||||
>>> w = TimeInput(format='%H:%M')
|
>>> w = TimeInput(format='%H:%M')
|
||||||
>>> w.render('time', t)
|
>>> w.render('time', t)
|
||||||
@ -1176,6 +1206,12 @@ u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" n
|
|||||||
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />'
|
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />'
|
||||||
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||||
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />'
|
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />'
|
||||||
|
>>> activate('de-at')
|
||||||
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||||
|
u'<input type="hidden" name="date_0" value="17.09.2007" /><input type="hidden" name="date_1" value="12:51:00" />'
|
||||||
|
>>> deactivate()
|
||||||
|
>>> settings.USE_L10N = False
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from django import template, forms
|
from django import template, forms
|
||||||
from django.forms.extras import SelectDateWidget
|
from django.forms.extras import SelectDateWidget
|
||||||
|
from models import Company
|
||||||
|
|
||||||
class I18nForm(forms.Form):
|
class I18nForm(forms.Form):
|
||||||
decimal_field = forms.DecimalField()
|
decimal_field = forms.DecimalField()
|
||||||
@ -11,3 +12,6 @@ class I18nForm(forms.Form):
|
|||||||
class SelectDateForm(forms.Form):
|
class SelectDateForm(forms.Form):
|
||||||
date_field = forms.DateField(widget=SelectDateWidget)
|
date_field = forms.DateField(widget=SelectDateWidget)
|
||||||
|
|
||||||
|
class CompanyForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Company
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
|
from datetime import datetime
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
class TestModel(models.Model):
|
class TestModel(models.Model):
|
||||||
text = models.CharField(max_length=10, default=_('Anything'))
|
text = models.CharField(max_length=10, default=_('Anything'))
|
||||||
|
|
||||||
|
class Company(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
date_added = models.DateTimeField(default=datetime(1799,1,31,23,59,59,0))
|
||||||
|
|
||||||
__test__ = {'API_TESTS': '''
|
__test__ = {'API_TESTS': '''
|
||||||
>>> tm = TestModel()
|
>>> tm = TestModel()
|
||||||
>>> tm.save()
|
>>> tm.save()
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
import sys
|
import sys
|
||||||
import decimal
|
import decimal
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.template import Template, Context
|
from django.template import Template, Context
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.formats import get_format, date_format, number_format, localize
|
from django.utils.formats import get_format, date_format, time_format, number_format, localize, localize_input
|
||||||
from django.utils.numberformat import format
|
from django.utils.numberformat import format
|
||||||
from django.test import TestCase, client
|
from django.test import TestCase, client
|
||||||
from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy
|
from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale
|
||||||
|
|
||||||
|
from forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
|
||||||
|
|
||||||
from forms import I18nForm, SelectDateForm, SelectDateWidget
|
|
||||||
|
|
||||||
class TranslationTests(TestCase):
|
class TranslationTests(TestCase):
|
||||||
|
|
||||||
@ -80,6 +82,23 @@ class TranslationTests(TestCase):
|
|||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
|
|
||||||
|
def test_to_locale(self):
|
||||||
|
"""
|
||||||
|
Tests the to_locale function and the special case of Serbian Latin
|
||||||
|
(refs #12230 and r11299)
|
||||||
|
"""
|
||||||
|
self.assertEqual(to_locale('en-us'), 'en_US')
|
||||||
|
self.assertEqual(to_locale('sr-lat'), 'sr_Lat')
|
||||||
|
|
||||||
|
def test_to_language(self):
|
||||||
|
"""
|
||||||
|
Test the to_language function
|
||||||
|
"""
|
||||||
|
from django.utils.translation.trans_real import to_language
|
||||||
|
self.assertEqual(to_language('en_US'), 'en-us')
|
||||||
|
self.assertEqual(to_language('sr_Lat'), 'sr-lat')
|
||||||
|
|
||||||
|
|
||||||
class FormattingTests(TestCase):
|
class FormattingTests(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -90,8 +109,10 @@ class FormattingTests(TestCase):
|
|||||||
self.f = 99999.999
|
self.f = 99999.999
|
||||||
self.d = datetime.date(2009, 12, 31)
|
self.d = datetime.date(2009, 12, 31)
|
||||||
self.dt = datetime.datetime(2009, 12, 31, 20, 50)
|
self.dt = datetime.datetime(2009, 12, 31, 20, 50)
|
||||||
|
self.t = datetime.time(10, 15, 48)
|
||||||
self.ctxt = Context({
|
self.ctxt = Context({
|
||||||
'n': self.n,
|
'n': self.n,
|
||||||
|
't': self.t,
|
||||||
'd': self.d,
|
'd': self.d,
|
||||||
'dt': self.dt,
|
'dt': self.dt,
|
||||||
'f': self.f
|
'f': self.f
|
||||||
@ -102,10 +123,10 @@ class FormattingTests(TestCase):
|
|||||||
settings.USE_I18N = self._use_i18n
|
settings.USE_I18N = self._use_i18n
|
||||||
settings.USE_L10N = self._use_l10n
|
settings.USE_L10N = self._use_l10n
|
||||||
settings.USE_THOUSAND_SEPARATOR = self._use_thousand_separator
|
settings.USE_THOUSAND_SEPARATOR = self._use_thousand_separator
|
||||||
|
|
||||||
def test_locale_independent(self):
|
def test_locale_independent(self):
|
||||||
"""
|
"""
|
||||||
Localization of dates and numbers
|
Localization of numbers
|
||||||
"""
|
"""
|
||||||
settings.USE_L10N = True
|
settings.USE_L10N = True
|
||||||
settings.USE_THOUSAND_SEPARATOR = False
|
settings.USE_THOUSAND_SEPARATOR = False
|
||||||
@ -118,6 +139,10 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(u'-66666.6', format(-66666.666, decimal_sep='.', decimal_pos=1))
|
self.assertEqual(u'-66666.6', format(-66666.666, decimal_sep='.', decimal_pos=1))
|
||||||
self.assertEqual(u'-66666.0', format(int('-66666'), decimal_sep='.', decimal_pos=1))
|
self.assertEqual(u'-66666.0', format(int('-66666'), decimal_sep='.', decimal_pos=1))
|
||||||
|
|
||||||
|
# date filter
|
||||||
|
self.assertEqual(u'31.12.2009 в 20:50', Template('{{ dt|date:"d.m.Y в H:i" }}').render(self.ctxt))
|
||||||
|
self.assertEqual(u'⌚ 10:15', Template('{{ t|time:"⌚ H:i" }}').render(self.ctxt))
|
||||||
|
|
||||||
def test_l10n_disabled(self):
|
def test_l10n_disabled(self):
|
||||||
"""
|
"""
|
||||||
Catalan locale with format i18n disabled translations will be used,
|
Catalan locale with format i18n disabled translations will be used,
|
||||||
@ -129,6 +154,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual('N j, Y', get_format('DATE_FORMAT'))
|
self.assertEqual('N j, Y', get_format('DATE_FORMAT'))
|
||||||
self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK'))
|
self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK'))
|
||||||
self.assertEqual('.', get_format('DECIMAL_SEPARATOR'))
|
self.assertEqual('.', get_format('DECIMAL_SEPARATOR'))
|
||||||
|
self.assertEqual(u'10:15 a.m.', time_format(self.t))
|
||||||
self.assertEqual(u'des. 31, 2009', date_format(self.d))
|
self.assertEqual(u'des. 31, 2009', date_format(self.d))
|
||||||
self.assertEqual(u'desembre 2009', date_format(self.d, 'YEAR_MONTH_FORMAT'))
|
self.assertEqual(u'desembre 2009', date_format(self.d, 'YEAR_MONTH_FORMAT'))
|
||||||
self.assertEqual(u'12/31/2009 8:50 p.m.', date_format(self.dt, 'SHORT_DATETIME_FORMAT'))
|
self.assertEqual(u'12/31/2009 8:50 p.m.', date_format(self.dt, 'SHORT_DATETIME_FORMAT'))
|
||||||
@ -143,6 +169,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(u'2009-12-31 20:50:00', Template('{{ dt }}').render(self.ctxt))
|
self.assertEqual(u'2009-12-31 20:50:00', Template('{{ dt }}').render(self.ctxt))
|
||||||
self.assertEqual(u'66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
|
self.assertEqual(u'66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
|
||||||
self.assertEqual(u'100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
|
self.assertEqual(u'100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
|
||||||
|
self.assertEqual(u'10:15 a.m.', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt))
|
||||||
self.assertEqual(u'12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
|
self.assertEqual(u'12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
|
||||||
self.assertEqual(u'12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt))
|
self.assertEqual(u'12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt))
|
||||||
|
|
||||||
@ -168,7 +195,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field'])
|
self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field'])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
||||||
SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
|
SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
@ -183,6 +210,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual('j \de F \de Y', get_format('DATE_FORMAT'))
|
self.assertEqual('j \de F \de Y', get_format('DATE_FORMAT'))
|
||||||
self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK'))
|
self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK'))
|
||||||
self.assertEqual(',', get_format('DECIMAL_SEPARATOR'))
|
self.assertEqual(',', get_format('DECIMAL_SEPARATOR'))
|
||||||
|
self.assertEqual(u'10:15:48', time_format(self.t))
|
||||||
self.assertEqual(u'31 de desembre de 2009', date_format(self.d))
|
self.assertEqual(u'31 de desembre de 2009', date_format(self.d))
|
||||||
self.assertEqual(u'desembre del 2009', date_format(self.d, 'YEAR_MONTH_FORMAT'))
|
self.assertEqual(u'desembre del 2009', date_format(self.d, 'YEAR_MONTH_FORMAT'))
|
||||||
self.assertEqual(u'31/12/2009 20:50', date_format(self.dt, 'SHORT_DATETIME_FORMAT'))
|
self.assertEqual(u'31/12/2009 20:50', date_format(self.dt, 'SHORT_DATETIME_FORMAT'))
|
||||||
@ -209,6 +237,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(u'31 de desembre de 2009 a les 20:50', Template('{{ dt }}').render(self.ctxt))
|
self.assertEqual(u'31 de desembre de 2009 a les 20:50', Template('{{ dt }}').render(self.ctxt))
|
||||||
self.assertEqual(u'66666,67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
|
self.assertEqual(u'66666,67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
|
||||||
self.assertEqual(u'100000,0', Template('{{ f|floatformat }}').render(self.ctxt))
|
self.assertEqual(u'100000,0', Template('{{ f|floatformat }}').render(self.ctxt))
|
||||||
|
self.assertEqual(u'10:15:48', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt))
|
||||||
self.assertEqual(u'31/12/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
|
self.assertEqual(u'31/12/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
|
||||||
self.assertEqual(u'31/12/2009 20:50', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt))
|
self.assertEqual(u'31/12/2009 20:50', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt))
|
||||||
|
|
||||||
@ -235,7 +264,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(datetime.date(2009, 12, 31), form4.cleaned_data['date_field'])
|
self.assertEqual(datetime.date(2009, 12, 31), form4.cleaned_data['date_field'])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
u'<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
u'<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_month" id="id_mydate_month">\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
||||||
SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
|
SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
@ -300,7 +329,7 @@ class FormattingTests(TestCase):
|
|||||||
self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
|
self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12" selected="selected">December</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
u'<select name="mydate_month" id="id_mydate_month">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12" selected="selected">December</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>',
|
||||||
SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
|
SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
@ -323,6 +352,28 @@ class FormattingTests(TestCase):
|
|||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
|
|
||||||
|
def test_localized_input(self):
|
||||||
|
"""
|
||||||
|
Tests if form input is correctly localized
|
||||||
|
"""
|
||||||
|
settings.USE_L10N = True
|
||||||
|
activate('de-at')
|
||||||
|
try:
|
||||||
|
form6 = CompanyForm({
|
||||||
|
'name': u'acme',
|
||||||
|
'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0),
|
||||||
|
})
|
||||||
|
form6.save()
|
||||||
|
self.assertEqual(True, form6.is_valid())
|
||||||
|
self.assertEqual(
|
||||||
|
form6.as_ul(),
|
||||||
|
u'<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="acme" maxlength="50" /></li>\n<li><label for="id_date_added">Date added:</label> <input type="text" name="date_added" value="31.12.2009 06:00:00" id="id_date_added" /></li>'
|
||||||
|
)
|
||||||
|
self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00')
|
||||||
|
self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
|
||||||
|
finally:
|
||||||
|
deactivate()
|
||||||
|
|
||||||
class MiscTests(TestCase):
|
class MiscTests(TestCase):
|
||||||
|
|
||||||
def test_parse_spec_http_header(self):
|
def test_parse_spec_http_header(self):
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
from models import Place
|
from models import Place
|
||||||
|
|
||||||
class PlaceForm(ModelForm):
|
|
||||||
"""docstring for PlaceForm"""
|
|
||||||
class Meta:
|
|
||||||
model = Place
|
|
||||||
from django.forms import ModelForm
|
|
||||||
from models import Place
|
|
||||||
|
|
||||||
class PlaceForm(ModelForm):
|
class PlaceForm(ModelForm):
|
||||||
"""docstring for PlaceForm"""
|
"""docstring for PlaceForm"""
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.localflavor.us.models import USStateField
|
from django.contrib.localflavor.us.models import USStateField
|
||||||
|
|
||||||
class Place(models.Model):
|
|
||||||
state = USStateField(blank=True)
|
|
||||||
state_req = USStateField()
|
|
||||||
state_default = USStateField(default="CA", blank=True)
|
|
||||||
name = models.CharField(max_length=20)
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.localflavor.us.models import USStateField
|
|
||||||
|
|
||||||
class Place(models.Model):
|
class Place(models.Model):
|
||||||
state = USStateField(blank=True)
|
state = USStateField(blank=True)
|
||||||
state_req = USStateField()
|
state_req = USStateField()
|
||||||
|
@ -2,89 +2,6 @@ from django.test import TestCase
|
|||||||
from models import Place
|
from models import Place
|
||||||
from forms import PlaceForm
|
from forms import PlaceForm
|
||||||
|
|
||||||
class USLocalflavorTests(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.form = PlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
|
|
||||||
|
|
||||||
def test_get_display_methods(self):
|
|
||||||
"""Test that the get_*_display() methods are added to the model instances."""
|
|
||||||
place = self.form.save()
|
|
||||||
self.assertEqual(place.get_state_display(), 'Georgia')
|
|
||||||
self.assertEqual(place.get_state_req_display(), 'North Carolina')
|
|
||||||
|
|
||||||
def test_required(self):
|
|
||||||
"""Test that required USStateFields throw appropriate errors."""
|
|
||||||
form = PlaceForm({'state':'GA', 'name':'Place in GA'})
|
|
||||||
self.assertFalse(form.is_valid())
|
|
||||||
self.assertEqual(form.errors['state_req'], [u'This field is required.'])
|
|
||||||
|
|
||||||
def test_field_blank_option(self):
|
|
||||||
"""Test that the empty option is there."""
|
|
||||||
state_select_html = """\
|
|
||||||
<select name="state" id="id_state">
|
|
||||||
<option value="">---------</option>
|
|
||||||
<option value="AL">Alabama</option>
|
|
||||||
<option value="AK">Alaska</option>
|
|
||||||
<option value="AS">American Samoa</option>
|
|
||||||
<option value="AZ">Arizona</option>
|
|
||||||
<option value="AR">Arkansas</option>
|
|
||||||
<option value="CA">California</option>
|
|
||||||
<option value="CO">Colorado</option>
|
|
||||||
<option value="CT">Connecticut</option>
|
|
||||||
<option value="DE">Delaware</option>
|
|
||||||
<option value="DC">District of Columbia</option>
|
|
||||||
<option value="FL">Florida</option>
|
|
||||||
<option value="GA" selected="selected">Georgia</option>
|
|
||||||
<option value="GU">Guam</option>
|
|
||||||
<option value="HI">Hawaii</option>
|
|
||||||
<option value="ID">Idaho</option>
|
|
||||||
<option value="IL">Illinois</option>
|
|
||||||
<option value="IN">Indiana</option>
|
|
||||||
<option value="IA">Iowa</option>
|
|
||||||
<option value="KS">Kansas</option>
|
|
||||||
<option value="KY">Kentucky</option>
|
|
||||||
<option value="LA">Louisiana</option>
|
|
||||||
<option value="ME">Maine</option>
|
|
||||||
<option value="MD">Maryland</option>
|
|
||||||
<option value="MA">Massachusetts</option>
|
|
||||||
<option value="MI">Michigan</option>
|
|
||||||
<option value="MN">Minnesota</option>
|
|
||||||
<option value="MS">Mississippi</option>
|
|
||||||
<option value="MO">Missouri</option>
|
|
||||||
<option value="MT">Montana</option>
|
|
||||||
<option value="NE">Nebraska</option>
|
|
||||||
<option value="NV">Nevada</option>
|
|
||||||
<option value="NH">New Hampshire</option>
|
|
||||||
<option value="NJ">New Jersey</option>
|
|
||||||
<option value="NM">New Mexico</option>
|
|
||||||
<option value="NY">New York</option>
|
|
||||||
<option value="NC">North Carolina</option>
|
|
||||||
<option value="ND">North Dakota</option>
|
|
||||||
<option value="MP">Northern Mariana Islands</option>
|
|
||||||
<option value="OH">Ohio</option>
|
|
||||||
<option value="OK">Oklahoma</option>
|
|
||||||
<option value="OR">Oregon</option>
|
|
||||||
<option value="PA">Pennsylvania</option>
|
|
||||||
<option value="PR">Puerto Rico</option>
|
|
||||||
<option value="RI">Rhode Island</option>
|
|
||||||
<option value="SC">South Carolina</option>
|
|
||||||
<option value="SD">South Dakota</option>
|
|
||||||
<option value="TN">Tennessee</option>
|
|
||||||
<option value="TX">Texas</option>
|
|
||||||
<option value="UT">Utah</option>
|
|
||||||
<option value="VT">Vermont</option>
|
|
||||||
<option value="VI">Virgin Islands</option>
|
|
||||||
<option value="VA">Virginia</option>
|
|
||||||
<option value="WA">Washington</option>
|
|
||||||
<option value="WV">West Virginia</option>
|
|
||||||
<option value="WI">Wisconsin</option>
|
|
||||||
<option value="WY">Wyoming</option>
|
|
||||||
</select>"""
|
|
||||||
self.assertEqual(str(self.form['state']), state_select_html)
|
|
||||||
from django.test import TestCase
|
|
||||||
from models import Place
|
|
||||||
from forms import PlaceForm
|
|
||||||
|
|
||||||
class USLocalflavorTests(TestCase):
|
class USLocalflavorTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.form = PlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
|
self.form = PlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
|
||||||
|
4
tests/regressiontests/settings/__init__.py
Normal file
4
tests/regressiontests/settings/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Settings file automatically generated by regressiontests.admin_scripts test case
|
||||||
|
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'SUPPORTS_TRANSACTIONS': True, 'NAME': ':memory:', 'TEST_CHARSET': None, 'TIME_ZONE': 'America/Chicago', 'TEST_COLLATION': None, 'PORT': '', 'HOST': '', 'USER': '', 'TEST_NAME': None, 'PASSWORD': '', 'OPTIONS': {}}, 'other': {'ENGINE': 'django.db.backends.sqlite3', 'SUPPORTS_TRANSACTIONS': True, 'NAME': 'other_db14006', 'TEST_CHARSET': None, 'TIME_ZONE': 'America/Chicago', 'TEST_COLLATION': None, 'PORT': '', 'HOST': '', 'USER': '', 'TEST_NAME': 'other_db14006', 'PASSWORD': '', 'OPTIONS': {}}}
|
||||||
|
ROOT_URLCONF = 'urls'
|
||||||
|
INSTALLED_APPS = ['django.contrib.auth', 'django.contrib.contenttypes', 'admin_scripts']
|
BIN
tests/regressiontests/views/locale/ru/LC_MESSAGES/djangojs.mo
Normal file
BIN
tests/regressiontests/views/locale/ru/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
@ -0,0 +1,20 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2007-09-15 16:45+0200\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
msgid "this is to be translated"
|
||||||
|
msgstr "перевод"
|
@ -4,6 +4,7 @@ import gettext
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils.translation import activate
|
from django.utils.translation import activate
|
||||||
|
from django.utils.text import javascript_quote
|
||||||
|
|
||||||
from regressiontests.views.urls import locale_dir
|
from regressiontests.views.urls import locale_dir
|
||||||
|
|
||||||
@ -20,11 +21,12 @@ class I18NTests(TestCase):
|
|||||||
|
|
||||||
def test_jsi18n(self):
|
def test_jsi18n(self):
|
||||||
"""The javascript_catalog can be deployed with language settings"""
|
"""The javascript_catalog can be deployed with language settings"""
|
||||||
for lang_code in ['es', 'fr', 'en']:
|
for lang_code in ['es', 'fr', 'en', 'ru']:
|
||||||
activate(lang_code)
|
activate(lang_code)
|
||||||
catalog = gettext.translation('djangojs', locale_dir, [lang_code])
|
catalog = gettext.translation('djangojs', locale_dir, [lang_code])
|
||||||
trans_txt = catalog.ugettext('this is to be translated')
|
trans_txt = catalog.ugettext('this is to be translated')
|
||||||
response = self.client.get('/views/jsi18n/')
|
response = self.client.get('/views/jsi18n/')
|
||||||
# in response content must to be a line like that:
|
# in response content must to be a line like that:
|
||||||
# catalog['this is to be translated'] = 'same_that_trans_txt'
|
# catalog['this is to be translated'] = 'same_that_trans_txt'
|
||||||
self.assertContains(response, trans_txt, 1)
|
# javascript_quote is used to be able to check unicode strings
|
||||||
|
self.assertContains(response, javascript_quote(trans_txt), 1)
|
||||||
|
@ -162,7 +162,7 @@ def django_tests(verbosity, interactive, failfast, test_labels):
|
|||||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, failfast=failfast,
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, failfast=failfast,
|
||||||
extra_tests=extra_tests)
|
extra_tests=extra_tests)
|
||||||
if failures:
|
if failures:
|
||||||
sys.exit(failures)
|
sys.exit(bool(failures))
|
||||||
|
|
||||||
# Restore the old settings.
|
# Restore the old settings.
|
||||||
settings.INSTALLED_APPS = old_installed_apps
|
settings.INSTALLED_APPS = old_installed_apps
|
||||||
|
Loading…
x
Reference in New Issue
Block a user