mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +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>
|
||||
alang@bright-green.com
|
||||
Alcides Fonseca
|
||||
Andi Albrecht <albrecht.andi@gmail.com>
|
||||
Marty Alchin <gulopine@gamemusic.org>
|
||||
Ahmad Alhashemi <trans@ahmadh.com>
|
||||
Ahmad Al-Ibrahim
|
||||
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
|
||||
AgarFu <heaven@croasanaso.sytes.net>
|
||||
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>
|
||||
Owen Griffiths
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
Janos Guljas
|
||||
Thomas Güttler <hv@tbz-pariv.de>
|
||||
Horst Gutmann <zerok@zerokspot.com>
|
||||
Scot Hacker <shacker@birdhouse.org>
|
||||
@ -195,6 +198,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
hambaloney
|
||||
Brian Harring <ferringb@gmail.com>
|
||||
Brant Harris
|
||||
Ronny Haryanto <http://ronny.haryan.to/>
|
||||
Hawkeye
|
||||
Joe Heck <http://www.rhonabwy.com/wp/>
|
||||
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>
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
ryankanno
|
||||
Gonzalo Saavedra <gonzalosaavedra@gmail.com>
|
||||
Manuel Saelices <msaelices@yaco.es>
|
||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||
@ -482,6 +487,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
ymasuda@ethercube.com
|
||||
Jesse Young <adunar@gmail.com>
|
||||
Mykola Zamkovoi <nickzam@gmail.com>
|
||||
zegor
|
||||
Gasper Zejn <zejn@kiberpipa.org>
|
||||
Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||
Cheng Zhang
|
||||
|
@ -84,6 +84,7 @@ LANGUAGES = (
|
||||
('sk', gettext_noop('Slovak')),
|
||||
('sl', gettext_noop('Slovenian')),
|
||||
('sr', gettext_noop('Serbian')),
|
||||
('sr-latn', gettext_noop('Serbian Latin')),
|
||||
('sv', gettext_noop('Swedish')),
|
||||
('ta', gettext_noop('Tamil')),
|
||||
('te', gettext_noop('Telugu')),
|
||||
|
@ -2,17 +2,40 @@
|
||||
# This file is distributed under the same license as the Django package.
|
||||
#
|
||||
|
||||
DATE_FORMAT = 'd F Y'
|
||||
TIME_FORMAT = 'H.i.s'
|
||||
# DATETIME_FORMAT =
|
||||
YEAR_MONTH_FORMAT = 'F Y'
|
||||
MONTH_DAY_FORMAT = 'j F'
|
||||
SHORT_DATE_FORMAT = 'd/M/Y'
|
||||
# SHORT_DATETIME_FORMAT =
|
||||
# FIRST_DAY_OF_WEEK =
|
||||
# DATE_INPUT_FORMATS =
|
||||
# TIME_INPUT_FORMATS =
|
||||
# DATETIME_INPUT_FORMATS =
|
||||
DATE_FORMAT = 'd F Y' # 25 Ottobre 2006
|
||||
TIME_FORMAT = 'H:i:s' # 14:30:59
|
||||
DATETIME_FORMAT = 'w d F Y H:i:s' # Mercoledì 25 Ottobre 2006 14:30:59
|
||||
YEAR_MONTH_FORMAT = 'F Y' # Ottobre 2006
|
||||
MONTH_DAY_FORMAT = 'j/F' # 10/2006
|
||||
SHORT_DATE_FORMAT = 'd/M/Y' # 25/12/2009
|
||||
SHORT_DATETIME_FORMAT = 'd/M/Y H:i:s' # 25/10/2009 14:30:59
|
||||
FIRST_DAY_OF_WEEK = 1 # Lunedì
|
||||
DATE_INPUT_FORMATS = (
|
||||
'%Y-%m-%d', '%Y/%m/%d', # '2008-10-25', '2008/10/25'
|
||||
'%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 = ','
|
||||
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'
|
||||
)
|
||||
TIME_INPUT_FORMATS = (
|
||||
'%H:%i:%S', # '14:30:59'
|
||||
'%H:%i', # '14:30'
|
||||
'%H:%M:%S', # '14:30:59'
|
||||
'%H:%M', # '14:30'
|
||||
)
|
||||
DATETIME_INPUT_FORMATS = (
|
||||
'%Y-%m-%d %H:%i:%S', # '2006-10-25 14:30:59'
|
||||
'%Y-%m-%d %H:%i', # '2006-10-25 14:30'
|
||||
'%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'
|
||||
'%Y-%m-%j', # '2006-10-25'
|
||||
'%j.%m.%Y %H:%i:%S', # '25.10.2006 14:30:59'
|
||||
'%j.%m.%Y %H:%i', # '25.10.2006 14:30'
|
||||
'%j.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
|
||||
'%j.%m.%Y %H:%M', # '25.10.2006 14:30'
|
||||
'%j.%m.%Y', # '25.10.2006'
|
||||
'%j.%m.%y %H:%i:%S', # '25.10.06 14:30:59'
|
||||
'%j.%m.%y %H:%i', # '25.10.06 14:30'
|
||||
'%j.%m.%y %H:%M:%S', # '25.10.06 14:30:59'
|
||||
'%j.%m.%y %H:%M', # '25.10.06 14:30'
|
||||
'%j.%m.%y', # '25.10.06'
|
||||
)
|
||||
DECIMAL_SEPARATOR = ','
|
||||
|
@ -5,7 +5,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django\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"
|
||||
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -223,7 +223,7 @@ msgstr "chiński tradycyjny"
|
||||
msgid "Successfully deleted %(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?"
|
||||
msgstr "Jesteś pewien?"
|
||||
|
||||
@ -314,94 +314,94 @@ msgstr "logi"
|
||||
msgid "None"
|
||||
msgstr "brak"
|
||||
|
||||
#: contrib/admin/options.py:540
|
||||
#: contrib/admin/options.py:554
|
||||
#, python-format
|
||||
msgid "Changed %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
|
||||
#: forms/models.py:598
|
||||
msgid "and"
|
||||
msgstr "i"
|
||||
|
||||
#: contrib/admin/options.py:545
|
||||
#: contrib/admin/options.py:559
|
||||
#, python-format
|
||||
msgid "Added %(name)s \"%(object)s\"."
|
||||
msgstr "Dodano %(name)s \"%(object)s\"."
|
||||
|
||||
#: contrib/admin/options.py:549
|
||||
#: contrib/admin/options.py:563
|
||||
#, python-format
|
||||
msgid "Changed %(list)s for %(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
|
||||
msgid "Deleted %(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."
|
||||
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
|
||||
msgid "The %(name)s \"%(obj)s\" was added successfully."
|
||||
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
|
||||
msgid "You may edit it again below."
|
||||
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
|
||||
msgid "You may add another %s below."
|
||||
msgstr "Możesz dodać nowy wpis %s poniżej."
|
||||
|
||||
#: contrib/admin/options.py:655
|
||||
#: contrib/admin/options.py:669
|
||||
#, python-format
|
||||
msgid "The %(name)s \"%(obj)s\" was changed successfully."
|
||||
msgstr "%(name)s \"%(obj)s\" zostało pomyślnie zmienione."
|
||||
|
||||
#: contrib/admin/options.py:663
|
||||
#: contrib/admin/options.py:677
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below."
|
||||
msgstr ""
|
||||
"%(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 ""
|
||||
"Items must be selected in order to perform actions on them. No items have "
|
||||
"been changed."
|
||||
msgstr ""
|
||||
"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."
|
||||
msgstr "Nie wybrano akcji."
|
||||
|
||||
#: contrib/admin/options.py:808
|
||||
#: contrib/admin/options.py:822
|
||||
#, python-format
|
||||
msgid "Add %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
|
||||
msgid "%(name)s object with primary key %(key)r does not exist."
|
||||
msgstr "Obiekt %(name)s o kluczu głównym %(key)r nie istnieje."
|
||||
|
||||
#: contrib/admin/options.py:905
|
||||
#: contrib/admin/options.py:913
|
||||
#, python-format
|
||||
msgid "Change %s"
|
||||
msgstr "Zmień %s"
|
||||
|
||||
#: contrib/admin/options.py:950
|
||||
#: contrib/admin/options.py:958
|
||||
msgid "Database error"
|
||||
msgstr "Błąd bazy danych"
|
||||
|
||||
#: contrib/admin/options.py:986
|
||||
#: contrib/admin/options.py:994
|
||||
#, python-format
|
||||
msgid "%(count)s %(name)s was 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[2] "%(count)s %(name)s zostało pomyślnie zmienionych."
|
||||
|
||||
#: contrib/admin/options.py:1066
|
||||
#: contrib/admin/options.py:1068
|
||||
#, python-format
|
||||
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
|
||||
msgstr "%(name)s \"%(obj)s\" usunięty pomyślnie."
|
||||
|
||||
#: contrib/admin/options.py:1103
|
||||
#: contrib/admin/options.py:1105
|
||||
#, python-format
|
||||
msgid "Change history: %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-"
|
||||
"mail and should be fixed shortly. Thanks for your patience."
|
||||
msgstr ""
|
||||
"Wystąpił niespodziewany błąd. Raport został wysłany e-mailem "
|
||||
"administratorowi strony i powinien zostać wkrótce naprawiony. Dziękujemy za "
|
||||
"cierpliwość."
|
||||
"Wystąpił niespodziewany błąd. Został on zgłoszony e-mailem administratorowi "
|
||||
"strony i powinien zostać wkrótce naprawiony. Dziękujemy za cierpliwość."
|
||||
|
||||
#: contrib/admin/templates/admin/actions.html:4
|
||||
msgid "Run the selected action"
|
||||
|
@ -44,7 +44,7 @@ var DateTimeShortcuts = {
|
||||
var shortcuts_span = document.createElement('span');
|
||||
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
|
||||
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')));
|
||||
var clock_link = document.createElement('a');
|
||||
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
|
||||
@ -80,10 +80,10 @@ var DateTimeShortcuts = {
|
||||
quickElement('h2', clock_box, gettext('Choose a time'));
|
||||
time_list = quickElement('ul', clock_box, '');
|
||||
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("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '00:00:00');")
|
||||
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("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '12:00:00');")
|
||||
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 + ", 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 + ", 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 + ", new Date(1970,1,1,12,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
||||
|
||||
cancel_p = quickElement('p', clock_box, '');
|
||||
cancel_p.className = 'calendar-cancel';
|
||||
@ -195,20 +195,19 @@ var DateTimeShortcuts = {
|
||||
openCalendar: function(num) {
|
||||
var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+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.
|
||||
// If so, draw the calendar with that date's year and month.
|
||||
if (inp.value) {
|
||||
var date_parts = inp.value.split('-');
|
||||
var year = date_parts[0];
|
||||
var month = parseFloat(date_parts[1]);
|
||||
if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
|
||||
DateTimeShortcuts.calendars[num].drawDate(month, year);
|
||||
}
|
||||
}
|
||||
// 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 (inp.value) {
|
||||
var date_parts = inp.value.split('-');
|
||||
var year = date_parts[0];
|
||||
var month = parseFloat(date_parts[1]);
|
||||
if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
|
||||
DateTimeShortcuts.calendars[num].drawDate(month, year);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Recalculate the clockbox position
|
||||
// is it left-to-right or right-to-left layout ?
|
||||
if (getStyle(document.body,'direction')!='rtl') {
|
||||
@ -237,12 +236,19 @@ var DateTimeShortcuts = {
|
||||
DateTimeShortcuts.calendars[num].drawNextMonth();
|
||||
},
|
||||
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) {
|
||||
var d = new Date();
|
||||
d.setDate(d.getDate() + offset)
|
||||
DateTimeShortcuts.calendarInputs[num].value = d.getISODate();
|
||||
DateTimeShortcuts.calendarInputs[num].value = d.strftime(gettext('DATE_INPUT_FORMATS'));
|
||||
DateTimeShortcuts.dismissCalendar(num);
|
||||
},
|
||||
cancelEventPropagation: function(e) {
|
||||
|
@ -115,6 +115,10 @@ Date.prototype.getCorrectYear = function() {
|
||||
return (y < 38) ? y + 2000 : y + 1900;
|
||||
}
|
||||
|
||||
Date.prototype.getTwelveHours = function() {
|
||||
return (this.getHours() <= 12) ? this.getHours() : 24 - this.getHours();
|
||||
}
|
||||
|
||||
Date.prototype.getTwoDigitMonth = function() {
|
||||
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();
|
||||
}
|
||||
|
||||
Date.prototype.getTwoDigitTwelveHour = function() {
|
||||
return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
|
||||
}
|
||||
|
||||
Date.prototype.getTwoDigitHour = function() {
|
||||
return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
|
||||
}
|
||||
@ -147,6 +155,37 @@ Date.prototype.getHourMinuteSecond = function() {
|
||||
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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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 import messages
|
||||
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.models.fields import BLANK_CHOICE_DASH
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
@ -368,6 +368,20 @@ class ModelAdmin(BaseModelAdmin):
|
||||
from django.contrib.admin.views.main import 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):
|
||||
"""
|
||||
Returns a Form class for use in the Formset on the changelist page.
|
||||
@ -829,13 +843,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
model = self.model
|
||||
opts = model._meta
|
||||
|
||||
try:
|
||||
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
|
||||
obj = self.get_object(request, unquote(object_id))
|
||||
|
||||
if not self.has_change_permission(request, obj):
|
||||
raise PermissionDenied
|
||||
@ -1040,13 +1048,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
opts = self.model._meta
|
||||
app_label = opts.app_label
|
||||
|
||||
try:
|
||||
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
|
||||
obj = self.get_object(request, unquote(object_id))
|
||||
|
||||
if not self.has_delete_permission(request, obj):
|
||||
raise PermissionDenied
|
||||
|
@ -247,8 +247,8 @@ def date_hierarchy(cl):
|
||||
return {
|
||||
'show': True,
|
||||
'choices': [{
|
||||
'link': link({year_field: year.year}),
|
||||
'title': year.year
|
||||
'link': link({year_field: str(year.year)}),
|
||||
'title': str(year.year),
|
||||
} for year in years]
|
||||
}
|
||||
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):
|
||||
try:
|
||||
model._meta.get_field_by_name(name)[0]
|
||||
return name
|
||||
return model._meta.get_field_by_name(name)[0].verbose_name
|
||||
except models.FieldDoesNotExist:
|
||||
if name == "__unicode__":
|
||||
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))
|
||||
return mark_safe(u''.join(output))
|
||||
|
||||
class AdminDateWidget(forms.TextInput):
|
||||
class AdminDateWidget(forms.DateTimeInput):
|
||||
class Media:
|
||||
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
||||
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
||||
|
||||
def __init__(self, attrs={}):
|
||||
super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
|
||||
def __init__(self, attrs={}, format=None):
|
||||
super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'}, format=format)
|
||||
|
||||
class AdminTimeWidget(forms.TextInput):
|
||||
class AdminTimeWidget(forms.TimeInput):
|
||||
class Media:
|
||||
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
||||
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
||||
|
||||
def __init__(self, attrs={}):
|
||||
super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
|
||||
def __init__(self, attrs={}, format=None):
|
||||
super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'}, format=format)
|
||||
|
||||
class AdminSplitDateTime(forms.SplitDateTimeWidget):
|
||||
"""
|
||||
|
@ -218,22 +218,26 @@ class User(models.Model):
|
||||
permissions = set()
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "get_group_permissions"):
|
||||
if obj is not None and backend.supports_object_permissions:
|
||||
group_permissions = backend.get_group_permissions(self, obj)
|
||||
if obj is not None:
|
||||
if backend.supports_object_permissions:
|
||||
permissions.update(
|
||||
backend.get_group_permissions(self, obj)
|
||||
)
|
||||
else:
|
||||
group_permissions = backend.get_group_permissions(self)
|
||||
permissions.update(group_permissions)
|
||||
permissions.update(backend.get_group_permissions(self))
|
||||
return permissions
|
||||
|
||||
def get_all_permissions(self, obj=None):
|
||||
permissions = set()
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "get_all_permissions"):
|
||||
if obj is not None and backend.supports_object_permissions:
|
||||
all_permissions = backend.get_all_permissions(self, obj)
|
||||
if obj is not None:
|
||||
if backend.supports_object_permissions:
|
||||
permissions.update(
|
||||
backend.get_all_permissions(self, obj)
|
||||
)
|
||||
else:
|
||||
all_permissions = backend.get_all_permissions(self)
|
||||
permissions.update(all_permissions)
|
||||
permissions.update(backend.get_all_permissions(self))
|
||||
return permissions
|
||||
|
||||
def has_perm(self, perm, obj=None):
|
||||
@ -255,9 +259,10 @@ class User(models.Model):
|
||||
# Otherwise we need to check the backends.
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "has_perm"):
|
||||
if obj is not None and backend.supports_object_permissions:
|
||||
if backend.has_perm(self, perm, obj):
|
||||
return True
|
||||
if obj is not None:
|
||||
if (backend.supports_object_permissions and
|
||||
backend.has_perm(self, perm, obj)):
|
||||
return True
|
||||
else:
|
||||
if backend.has_perm(self, perm):
|
||||
return True
|
||||
|
@ -69,6 +69,21 @@ class BackendTest(TestCase):
|
||||
self.assertEqual(user.has_perm('test'), 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):
|
||||
pass
|
||||
|
@ -158,7 +158,7 @@ class EasyInstanceField(object):
|
||||
if isinstance(self.field, models.DateTimeField):
|
||||
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
|
||||
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:
|
||||
objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
|
||||
else:
|
||||
|
@ -37,7 +37,7 @@ class CalendarPlugin(DatabrowsePlugin):
|
||||
return [mark_safe(u'%s%s/%s/%s/%s/%s/' % (
|
||||
easy_instance_field.model.url(),
|
||||
plugin_name, easy_instance_field.field.name,
|
||||
d.year,
|
||||
str(d.year),
|
||||
datetime_safe.new_date(d).strftime('%b').lower(),
|
||||
d.day))]
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
{% 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>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% 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 %}
|
||||
</ul>
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
{% 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">
|
||||
{% 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.measure import Distance
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.backends.postgresql.operations import DatabaseOperations
|
||||
from django.db.backends.postgresql_psycopg2.base import Database
|
||||
from django.db.backends.postgresql_psycopg2.base import Database, DatabaseOperations
|
||||
|
||||
#### Classes used in constructing PostGIS spatial SQL ####
|
||||
class PostGISOperator(SpatialOperation):
|
||||
@ -404,11 +403,12 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||
"""
|
||||
cursor = self.connection._cursor()
|
||||
try:
|
||||
cursor.execute('SELECT %s()' % func)
|
||||
row = cursor.fetchone()
|
||||
except:
|
||||
# Responsibility of callers to perform error handling.
|
||||
raise
|
||||
try:
|
||||
cursor.execute('SELECT %s()' % func)
|
||||
row = cursor.fetchone()
|
||||
except:
|
||||
# Responsibility of callers to perform error handling.
|
||||
raise
|
||||
finally:
|
||||
cursor.close()
|
||||
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.operations import SpatiaLiteOperations
|
||||
|
||||
|
||||
class DatabaseWrapper(SqliteDatabaseWrapper):
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Before we get too far, make sure pysqlite 2.5+ is installed.
|
||||
@ -36,6 +35,7 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
|
||||
|
||||
def _cursor(self):
|
||||
if self.connection is None:
|
||||
## The following is the same as in django.db.backends.sqlite3.base ##
|
||||
settings_dict = self.settings_dict
|
||||
if not settings_dict['NAME']:
|
||||
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_date_trunc", 2, _sqlite_date_trunc)
|
||||
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:
|
||||
self.connection.enable_load_extension(True)
|
||||
except AttributeError:
|
||||
@ -59,15 +63,14 @@ class DatabaseWrapper(SqliteDatabaseWrapper):
|
||||
'the loading of extensions to use SpatiaLite.'
|
||||
)
|
||||
|
||||
connection_created.send(sender=self.__class__)
|
||||
return self.connection.cursor(factory=SQLiteCursorWrapper)
|
||||
|
||||
def load_spatialite(self):
|
||||
"""
|
||||
Loads the SpatiaLite library.
|
||||
"""
|
||||
try:
|
||||
self._cursor().execute("SELECT load_extension(%s)", (self.spatialite_lib,))
|
||||
except Exception, msg:
|
||||
raise ImproperlyConfigured('Unable to load the SpatiaLite extension '
|
||||
'"%s" because: %s' % (self.spatialite_lib, msg))
|
||||
# Loading the SpatiaLite library extension on the connection, and returning
|
||||
# the created cursor.
|
||||
cur = self.connection.cursor(factory=SQLiteCursorWrapper)
|
||||
try:
|
||||
cur.execute("SELECT load_extension(%s)", (self.spatialite_lib,))
|
||||
except Exception, msg:
|
||||
raise ImproperlyConfigured('Unable to load the SpatiaLite library extension '
|
||||
'"%s" because: %s' % (self.spatialite_lib, msg))
|
||||
return cur
|
||||
else:
|
||||
return self.connection.cursor(factory=SQLiteCursorWrapper)
|
||||
|
@ -24,8 +24,7 @@ class SpatiaLiteCreation(DatabaseCreation):
|
||||
self.connection.settings_dict["NAME"] = test_database_name
|
||||
can_rollback = self._rollback_works()
|
||||
self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
|
||||
# Need to load the SpatiaLite library and initializatin SQL before running `syncdb`.
|
||||
self.connection.load_spatialite()
|
||||
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
|
||||
self.load_spatialite_sql()
|
||||
call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
|
||||
|
||||
|
@ -51,8 +51,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||
name = 'spatialite'
|
||||
spatialite = True
|
||||
version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
|
||||
valid_aggregates = dict([(k, None) for k in
|
||||
('Extent', 'Union')])
|
||||
valid_aggregates = dict([(k, None) for k in ('Extent', 'Union')])
|
||||
|
||||
Adapter = SpatiaLiteAdapter
|
||||
|
||||
@ -112,10 +111,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||
super(DatabaseOperations, self).__init__()
|
||||
self.connection = connection
|
||||
|
||||
# Load the spatialite library (must be done before getting the
|
||||
# SpatiaLite version).
|
||||
self.connection.load_spatialite()
|
||||
|
||||
# Determine the version of the SpatiaLite library.
|
||||
try:
|
||||
vtup = self.spatialite_version_tuple()
|
||||
version = vtup[1:]
|
||||
@ -211,11 +207,12 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||
"""
|
||||
cursor = self.connection._cursor()
|
||||
try:
|
||||
cursor.execute('SELECT %s()' % func)
|
||||
row = cursor.fetchone()
|
||||
except:
|
||||
# TODO: raise helpful exception here.
|
||||
raise
|
||||
try:
|
||||
cursor.execute('SELECT %s()' % func)
|
||||
row = cursor.fetchone()
|
||||
except:
|
||||
# Responsibility of caller to perform error handling.
|
||||
raise
|
||||
finally:
|
||||
cursor.close()
|
||||
return row[0]
|
||||
@ -268,7 +265,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||
"""
|
||||
Returns the SpatiaLite-specific SQL for the given lookup value
|
||||
[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
|
||||
|
||||
|
@ -10,7 +10,10 @@ class GeoManager(Manager):
|
||||
use_for_related_fields = True
|
||||
|
||||
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):
|
||||
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):
|
||||
# We resolve the rest of the columns if we're on Oracle or if
|
||||
# the `geo_values` attribute is defined.
|
||||
for value, field in izip(row[index_start:], fields):
|
||||
values.append(self.query.convert_values(value, field, self.connection))
|
||||
for value, field in map(None, row[index_start:], fields):
|
||||
values.append(self.query.convert_values(value, field, connection=self.connection))
|
||||
else:
|
||||
values.extend(row[index_start:])
|
||||
return tuple(values)
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""
|
||||
Error checking functions for GEOS ctypes prototype functions.
|
||||
"""
|
||||
import os
|
||||
from ctypes import c_void_p, string_at, CDLL
|
||||
from django.contrib.gis.geos.error import GEOSException
|
||||
from django.contrib.gis.geos.libgeos import lgeos, GEOS_VERSION
|
||||
@ -15,8 +16,12 @@ if GEOS_VERSION >= (3, 1, 1):
|
||||
free.restype = None
|
||||
else:
|
||||
# Getting the `free` routine from the C library of the platform.
|
||||
# The C library is obtained by passing None into `CDLL`.
|
||||
libc = CDLL(None)
|
||||
if os.name == 'nt':
|
||||
# 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
|
||||
|
||||
### ctypes error checking routines ###
|
||||
|
@ -19,7 +19,6 @@ class RelatedGeoModelTest(unittest.TestCase):
|
||||
loc = Location.objects.create(point=Point(lon, lat))
|
||||
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):
|
||||
"Testing `select_related` on geographic models (see #7126)."
|
||||
qs1 = City.objects.all()
|
||||
@ -34,7 +33,6 @@ class RelatedGeoModelTest(unittest.TestCase):
|
||||
self.assertEqual(Point(lon, lat), c.location.point)
|
||||
|
||||
@no_mysql
|
||||
@no_oracle # Pagination problem is implicated in this test as well.
|
||||
def test03_transform_related(self):
|
||||
"Testing the `transform` GeoQuerySet method on related geographic models."
|
||||
# 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).
|
||||
postcode = self.space_regex.sub(r' \1', postcode)
|
||||
if not self.postcode_regex.search(postcode):
|
||||
raise ValidationError(self.default_error_messages['invalid'])
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
return postcode
|
||||
|
||||
class UKCountySelect(Select):
|
||||
|
@ -4,7 +4,7 @@ USA-specific Form helpers
|
||||
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
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.translation import ugettext_lazy as _
|
||||
import re
|
||||
@ -21,7 +21,7 @@ class USZipCodeField(RegexField):
|
||||
super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$',
|
||||
max_length=None, min_length=None, *args, **kwargs)
|
||||
|
||||
class USPhoneNumberField(Field):
|
||||
class USPhoneNumberField(CharField):
|
||||
default_error_messages = {
|
||||
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.conf import settings
|
||||
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
|
||||
|
||||
class USStateField(CharField):
|
||||
@ -12,22 +12,16 @@ class USStateField(CharField):
|
||||
kwargs['max_length'] = 2
|
||||
super(USStateField, self).__init__(*args, **kwargs)
|
||||
|
||||
class PhoneNumberField(Field):
|
||||
class PhoneNumberField(CharField):
|
||||
|
||||
description = _("Phone number")
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PhoneNumberField"
|
||||
|
||||
def db_type(self, connection):
|
||||
if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle':
|
||||
return 'VARCHAR2(20)'
|
||||
else:
|
||||
return 'varchar(20)'
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = 20
|
||||
super(PhoneNumberField, self).__init__(*args, **kwargs)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
from django.contrib.localflavor.us.forms import USPhoneNumberField
|
||||
defaults = {'form_class': USPhoneNumberField}
|
||||
defaults.update(kwargs)
|
||||
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):
|
||||
from django.conf import settings
|
||||
from django.test.utils import get_runner
|
||||
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive', True)
|
||||
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
|
||||
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)
|
||||
else:
|
||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
||||
|
||||
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.encoding import StrAndUnicode, force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.formats import localize
|
||||
from django.utils import datetime_safe
|
||||
from django.utils import datetime_safe, formats
|
||||
from datetime import time
|
||||
from util import flatatt
|
||||
from urlparse import urljoin
|
||||
@ -209,7 +208,7 @@ class Input(Widget):
|
||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||
if value != '':
|
||||
# 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))
|
||||
|
||||
class TextInput(Input):
|
||||
@ -284,7 +283,7 @@ class Textarea(Widget):
|
||||
|
||||
class DateInput(Input):
|
||||
input_type = 'text'
|
||||
format = '%Y-%m-%d' # '2006-10-25'
|
||||
format = None
|
||||
|
||||
def __init__(self, attrs=None, format=None):
|
||||
super(DateInput, self).__init__(attrs)
|
||||
@ -295,8 +294,7 @@ class DateInput(Input):
|
||||
if value is None:
|
||||
return ''
|
||||
elif hasattr(value, 'strftime'):
|
||||
value = datetime_safe.new_date(value)
|
||||
return value.strftime(self.format)
|
||||
return formats.localize_input(value, self.format)
|
||||
return value
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
@ -308,7 +306,7 @@ class DateInput(Input):
|
||||
|
||||
class DateTimeInput(Input):
|
||||
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):
|
||||
super(DateTimeInput, self).__init__(attrs)
|
||||
@ -319,8 +317,7 @@ class DateTimeInput(Input):
|
||||
if value is None:
|
||||
return ''
|
||||
elif hasattr(value, 'strftime'):
|
||||
value = datetime_safe.new_datetime(value)
|
||||
return value.strftime(self.format)
|
||||
return formats.localize_input(value, self.format)
|
||||
return value
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
@ -332,7 +329,7 @@ class DateTimeInput(Input):
|
||||
|
||||
class TimeInput(Input):
|
||||
input_type = 'text'
|
||||
format = '%H:%M:%S' # '14:30:59'
|
||||
format = None
|
||||
|
||||
def __init__(self, attrs=None, format=None):
|
||||
super(TimeInput, self).__init__(attrs)
|
||||
@ -343,7 +340,7 @@ class TimeInput(Input):
|
||||
if value is None:
|
||||
return ''
|
||||
elif hasattr(value, 'strftime'):
|
||||
return value.strftime(self.format)
|
||||
return formats.localize_input(value, self.format)
|
||||
return value
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
|
@ -15,10 +15,10 @@ except ImportError:
|
||||
|
||||
from django.template import Variable, Library
|
||||
from django.conf import settings
|
||||
from django.utils import formats
|
||||
from django.utils.translation import ugettext, ungettext
|
||||
from django.utils.encoding import force_unicode, iri_to_uri
|
||||
from django.utils.safestring import mark_safe, SafeData
|
||||
from django.utils.formats import date_format, number_format
|
||||
|
||||
register = Library()
|
||||
|
||||
@ -167,14 +167,14 @@ def floatformat(text, arg=-1):
|
||||
return input_val
|
||||
|
||||
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:
|
||||
exp = Decimal(1)
|
||||
else:
|
||||
exp = Decimal('1.0') / (Decimal(10) ** abs(p))
|
||||
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:
|
||||
return input_val
|
||||
floatformat.is_safe = True
|
||||
@ -686,7 +686,7 @@ def date(value, arg=None):
|
||||
if arg is None:
|
||||
arg = settings.DATE_FORMAT
|
||||
try:
|
||||
return date_format(value, arg)
|
||||
return formats.date_format(value, arg)
|
||||
except AttributeError:
|
||||
try:
|
||||
return format(value, arg)
|
||||
@ -696,16 +696,16 @@ date.is_safe = False
|
||||
|
||||
def time(value, arg=None):
|
||||
"""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''):
|
||||
return u''
|
||||
if arg is None:
|
||||
arg = settings.TIME_FORMAT
|
||||
try:
|
||||
return date_format(value, arg)
|
||||
return formats.time_format(value, arg)
|
||||
except AttributeError:
|
||||
try:
|
||||
return time_format(value, arg)
|
||||
return dateformat.time_format(value, arg)
|
||||
except AttributeError:
|
||||
return ''
|
||||
time.is_safe = False
|
||||
|
@ -1,4 +1,7 @@
|
||||
import sys
|
||||
import signal
|
||||
import unittest
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import get_app, get_apps
|
||||
from django.test import _doctest as doctest
|
||||
@ -11,22 +14,50 @@ TEST_MODULE = 'tests'
|
||||
doctestOutputChecker = OutputChecker()
|
||||
|
||||
class DjangoTestRunner(unittest.TextTestRunner):
|
||||
|
||||
|
||||
def __init__(self, verbosity=0, failfast=False, **kwargs):
|
||||
super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
|
||||
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):
|
||||
result = super(DjangoTestRunner, self)._makeResult()
|
||||
failfast = self.failfast
|
||||
|
||||
|
||||
def stoptest_override(func):
|
||||
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()
|
||||
func(test)
|
||||
return stoptest
|
||||
|
||||
|
||||
setattr(result, 'stopTest', stoptest_override(result.stopTest))
|
||||
return result
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
from types import GeneratorType
|
||||
|
||||
from django.utils.copycompat import deepcopy
|
||||
|
||||
|
||||
@ -65,6 +67,11 @@ class SortedDict(dict):
|
||||
def __init__(self, data=None):
|
||||
if data is None:
|
||||
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)
|
||||
if isinstance(data, dict):
|
||||
self.keyOrder = data.keys()
|
||||
|
@ -19,7 +19,7 @@ from django.utils.tzinfo import LocalTimezone
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.encoding import force_unicode
|
||||
|
||||
re_formatchars = re.compile(r'(?<!\\)([aAbBdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
|
||||
re_formatchars = re.compile(r'(?<!\\)([aAbBcdDfFgGhHiIjlLmMnNOPrsStTUuwWyYzZ])')
|
||||
re_escaped = re.compile(r'\\(.)')
|
||||
|
||||
class Formatter(object):
|
||||
@ -104,6 +104,11 @@ class TimeFormat(Formatter):
|
||||
"Seconds; i.e. '00' to '59'"
|
||||
return u'%02d' % self.data.second
|
||||
|
||||
def u(self):
|
||||
"Microseconds"
|
||||
return self.data.microsecond
|
||||
|
||||
|
||||
class DateFormat(TimeFormat):
|
||||
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'"
|
||||
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):
|
||||
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
|
||||
return u'%02d' % self.data.day
|
||||
|
@ -131,12 +131,21 @@ def iri_to_uri(iri):
|
||||
|
||||
Returns an ASCII string containing the encoded result.
|
||||
"""
|
||||
# The list of safe characters here is constructed from the printable ASCII
|
||||
# characters that are not explicitly excluded by the list at the end of
|
||||
# section 3.1 of RFC 3987.
|
||||
# The list of safe characters here is constructed from the "reserved" and
|
||||
# "unreserved" characters specified in sections 2.2 and 2.3 of RFC 3986:
|
||||
# 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:
|
||||
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
|
||||
|
@ -4,15 +4,15 @@ import datetime
|
||||
from django.conf import settings
|
||||
from django.utils.translation import get_language, to_locale, check_for_language
|
||||
from django.utils.importlib import import_module
|
||||
from django.utils import dateformat
|
||||
from django.utils import numberformat
|
||||
from django.utils.encoding import smart_str
|
||||
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
|
||||
"""
|
||||
modules = []
|
||||
if not check_for_language(get_language()):
|
||||
if not check_for_language(get_language()) or not settings.USE_L10N:
|
||||
return modules
|
||||
locale = to_locale(get_language())
|
||||
if settings.FORMAT_MODULE_PATH:
|
||||
@ -30,6 +30,8 @@ def get_format_modules():
|
||||
# Don't return duplicates
|
||||
if mod not in modules:
|
||||
modules.append(mod)
|
||||
if reverse:
|
||||
modules.reverse()
|
||||
return modules
|
||||
|
||||
def get_format(format_type):
|
||||
@ -38,6 +40,7 @@ def get_format(format_type):
|
||||
language (locale), defaults to the format in the settings.
|
||||
format_type is the name of the format, e.g. 'DATE_FORMAT'
|
||||
"""
|
||||
format_type = smart_str(format_type)
|
||||
if settings.USE_L10N:
|
||||
for module in get_format_modules():
|
||||
try:
|
||||
@ -53,6 +56,12 @@ def date_format(value, format=None):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Formats a numeric value using localization settings
|
||||
@ -65,11 +74,10 @@ def number_format(value, decimal_pos=None):
|
||||
get_format('THOUSAND_SEPARATOR'),
|
||||
)
|
||||
|
||||
def localize(value, is_input=False):
|
||||
def localize(value):
|
||||
"""
|
||||
Checks value, and if it has a localizable type (date,
|
||||
number...) it returns the value as a string using
|
||||
current locale format
|
||||
Checks if value is a localizable type (date, number...) and returns it
|
||||
formatted as a string using current locale format
|
||||
"""
|
||||
if settings.USE_L10N:
|
||||
if isinstance(value, decimal.Decimal):
|
||||
@ -79,19 +87,27 @@ def localize(value, is_input=False):
|
||||
elif isinstance(value, int):
|
||||
return number_format(value)
|
||||
elif isinstance(value, datetime.datetime):
|
||||
if not is_input:
|
||||
return date_format(value, 'DATETIME_FORMAT')
|
||||
else:
|
||||
return value.strftime(get_format('DATETIME_INPUT_FORMATS')[0])
|
||||
return date_format(value, 'DATETIME_FORMAT')
|
||||
elif isinstance(value, datetime.date):
|
||||
if not is_input:
|
||||
return date_format(value)
|
||||
else:
|
||||
return value.strftime(get_format('DATE_INPUT_FORMATS')[0])
|
||||
return date_format(value)
|
||||
elif isinstance(value, datetime.time):
|
||||
if not is_input:
|
||||
return date_format(value, 'TIME_FORMAT')
|
||||
else:
|
||||
return value.strftime(get_format('TIME_INPUT_FORMATS')[0])
|
||||
return time_format(value, 'TIME_FORMAT')
|
||||
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:
|
||||
return language[:p].lower()+'_'+language[p+1:].lower()
|
||||
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()
|
||||
else:
|
||||
return language.lower()
|
||||
|
@ -6,6 +6,7 @@ from django.conf import settings
|
||||
from django.utils import importlib
|
||||
from django.utils.translation import check_for_language, activate, to_locale, get_language
|
||||
from django.utils.text import javascript_quote
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.formats import get_format_modules
|
||||
|
||||
def set_language(request):
|
||||
@ -36,15 +37,17 @@ def set_language(request):
|
||||
|
||||
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',
|
||||
'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 = {}
|
||||
for module in [settings] + get_format_modules():
|
||||
for module in [settings] + get_format_modules(reverse=True):
|
||||
for attr in FORMAT_SETTINGS:
|
||||
try:
|
||||
result[attr] = getattr(module, attr)
|
||||
@ -140,7 +143,7 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
||||
activate(request.GET['language'])
|
||||
if packages is None:
|
||||
packages = ['django.conf']
|
||||
if type(packages) in (str, unicode):
|
||||
if isinstance(packages, basestring):
|
||||
packages = packages.split('+')
|
||||
packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
|
||||
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():
|
||||
if k == '':
|
||||
continue
|
||||
if type(k) in (str, unicode):
|
||||
if isinstance(k, basestring):
|
||||
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:
|
||||
pdict[k[0]] = k[1]
|
||||
else:
|
||||
@ -208,7 +211,11 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
||||
for k, v in pdict.items():
|
||||
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
||||
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.append(LibFoot)
|
||||
src.append(InterPolate)
|
||||
|
@ -50,13 +50,17 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
||||
* Germany_
|
||||
* Iceland_
|
||||
* India_
|
||||
* Indonesia_
|
||||
* Ireland_
|
||||
* Italy_
|
||||
* Japan_
|
||||
* Kuwait_
|
||||
* Mexico_
|
||||
* `The Netherlands`_
|
||||
* Norway_
|
||||
* Peru_
|
||||
* Poland_
|
||||
* Portugal_
|
||||
* Romania_
|
||||
* Slovakia_
|
||||
* `South Africa`_
|
||||
@ -65,6 +69,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are:
|
||||
* Switzerland_
|
||||
* `United Kingdom`_
|
||||
* `United States of America`_
|
||||
* Uruguay_
|
||||
|
||||
The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage,
|
||||
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)`_
|
||||
.. _Iceland: `Iceland (is\_)`_
|
||||
.. _India: `India (in\_)`_
|
||||
.. _Indonesia: `Indonesia (id)`_
|
||||
.. _Ireland: `Ireland (ie)`_
|
||||
.. _Italy: `Italy (it)`_
|
||||
.. _Japan: `Japan (jp)`_
|
||||
.. _Kuwait: `Kuwait (kw)`_
|
||||
.. _Mexico: `Mexico (mx)`_
|
||||
.. _Norway: `Norway (no)`_
|
||||
.. _Peru: `Peru (pe)`_
|
||||
.. _Poland: `Poland (pl)`_
|
||||
.. _Portugal: `Portugal (pt)`_
|
||||
.. _Romania: `Romania (ro)`_
|
||||
.. _Slovakia: `Slovakia (sk)`_
|
||||
.. _South Africa: `South Africa (za)`_
|
||||
@ -106,6 +115,7 @@ Here's an example of how to use them::
|
||||
.. _Switzerland: `Switzerland (ch)`_
|
||||
.. _United Kingdom: `United Kingdom (uk)`_
|
||||
.. _United States of America: `United States of America (us)`_
|
||||
.. _Uruguay: `Uruguay (uy)`_
|
||||
|
||||
Adding flavors
|
||||
==============
|
||||
@ -369,6 +379,46 @@ India (``in_``)
|
||||
A ``Select`` widget that uses a list of Indian states/territories as its
|
||||
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``)
|
||||
==============
|
||||
|
||||
@ -408,6 +458,18 @@ Japan (``jp``)
|
||||
|
||||
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``)
|
||||
===============
|
||||
|
||||
@ -438,31 +500,31 @@ Norway (``no``)
|
||||
Peru (``pe``)
|
||||
=============
|
||||
|
||||
.. class:: pt.forms.PEDNIField
|
||||
.. class:: pe.forms.PEDNIField
|
||||
|
||||
A form field that validates input as a DNI (Peruvian national identity)
|
||||
number.
|
||||
|
||||
.. class:: pt.forms.PERUCField
|
||||
.. class:: pe.forms.PERUCField
|
||||
|
||||
A form field that validates input as an RUC (Registro Unico de
|
||||
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.
|
||||
|
||||
Poland (``pl``)
|
||||
===============
|
||||
|
||||
.. class:: pl.forms.PLNationalIdentificationNumberField
|
||||
.. class:: pl.forms.PLPESELField
|
||||
|
||||
A form field that validates input as a Polish national identification number
|
||||
(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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
.. class:: pl.forms.PLAdministrativeUnitSelect
|
||||
.. class:: pl.forms.PLCountySelect
|
||||
|
||||
A ``Select`` widget that uses a list of Polish administrative units as its
|
||||
choices.
|
||||
|
||||
.. class:: pl.forms.PLVoivodeshipSelect
|
||||
.. class:: pl.forms.PLProvinceSelect
|
||||
|
||||
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
||||
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``)
|
||||
================
|
||||
|
||||
@ -738,3 +813,15 @@ United States of America (``us``)
|
||||
|
||||
A model field that forms represent as a ``forms.USStateField`` field and
|
||||
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
|
||||
information.
|
||||
|
||||
--failfast
|
||||
~~~~~~~~~~
|
||||
|
||||
.. 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.
|
||||
|
||||
testserver <fixture fixture ...>
|
||||
|
@ -219,7 +219,7 @@ SQLite. This can be configured using the following::
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.db.backends.sqlite3',
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': 'mydatabase'
|
||||
}
|
||||
}
|
||||
|
@ -637,6 +637,7 @@ Available format strings:
|
||||
A ``'AM'`` or ``'PM'``. ``'AM'``
|
||||
b Month, textual, 3 letters, lowercase. ``'jan'``
|
||||
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'``
|
||||
leading zeros.
|
||||
D Day of the week, textual, 3 letters. ``'Fri'``
|
||||
@ -673,6 +674,7 @@ Available format strings:
|
||||
month, 2 characters.
|
||||
t Number of days in the given month. ``28`` to ``31``
|
||||
T Time zone of this machine. ``'EST'``, ``'MDT'``
|
||||
u Microseconds. ``0`` to ``999999``
|
||||
U Seconds since the Unix Epoch
|
||||
(January 1 1970 00:00:00 UTC).
|
||||
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
|
||||
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
|
||||
---------------
|
||||
===============
|
||||
|
||||
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
|
||||
|
@ -232,6 +232,16 @@ party packages, or that you wrote yourself, you should ensure that the
|
||||
information, see
|
||||
: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:
|
||||
|
||||
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
|
||||
----------------------
|
||||
|
||||
The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` 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
|
||||
encountering a failure instead of continuing with the test run.
|
||||
The :djadmin:`test` subcommand of ``django-admin.py``, and the ``runtests.py``
|
||||
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 encountering
|
||||
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
|
||||
---------------------
|
||||
|
@ -34,7 +34,7 @@ Authentication support is bundled as a Django application in
|
||||
|
||||
1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
|
||||
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`.)
|
||||
2. Run the command ``manage.py syncdb``.
|
||||
|
||||
|
@ -242,8 +242,8 @@ in different circumstances.
|
||||
Running tests
|
||||
=============
|
||||
|
||||
Once you've written tests, run them using your project's ``manage.py``
|
||||
utility::
|
||||
Once you've written tests, run them using the :djadmin:`test` subcommand of
|
||||
your project's ``manage.py`` utility::
|
||||
|
||||
$ ./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
|
||||
|
||||
.. 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
|
||||
-----------------
|
||||
|
||||
|
@ -63,11 +63,20 @@ class AdminViewBasicTest(TestCase):
|
||||
|
||||
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)
|
||||
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):
|
||||
"""
|
||||
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 AdminFileWidget, ForeignKeyRawIdWidget, ManyToManyRawIdWidget
|
||||
>>> 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
|
||||
happens in the template. This is easier than setting up a template and context
|
||||
@ -94,6 +97,12 @@ HTML escaped.
|
||||
>>> w = AdminSplitDateTime()
|
||||
>>> 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>
|
||||
>>> 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')
|
||||
>>> 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 unittest import TestCase
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from django.db.models import DateField
|
||||
import models
|
||||
|
||||
class AdminFormfieldForDBFieldTests(TestCase):
|
||||
@ -89,7 +90,7 @@ class AdminFormfieldForDBFieldTests(TestCase):
|
||||
|
||||
def testFormfieldOverrides(self):
|
||||
self.assertFormfield(models.Event, 'start_date', forms.TextInput,
|
||||
formfield_overrides={'widget': forms.TextInput})
|
||||
formfield_overrides={DateField: {'widget': forms.TextInput}})
|
||||
|
||||
def testFieldWithChoices(self):
|
||||
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.getlist('lastname')
|
||||
['Holovaty', 'Willison']
|
||||
>>> d.values()
|
||||
>>> d.values()
|
||||
['Developer', 'Simon', 'Willison']
|
||||
>>> list(d.itervalues())
|
||||
>>> list(d.itervalues())
|
||||
['Developer', 'Simon', 'Willison']
|
||||
|
||||
### SortedDict #################################################################
|
||||
@ -95,6 +95,9 @@ True
|
||||
>>> d.pop('one', '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
|
||||
the number of keys has decreased.
|
||||
>>> l = len(d)
|
||||
|
@ -39,8 +39,10 @@ class DateFormatTests(TestCase):
|
||||
|
||||
def test_date_formats(self):
|
||||
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(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, 'j'), u'8')
|
||||
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)
|
||||
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
||||
wintertime = datetime.datetime(2005, 10, 30, 4, 00)
|
||||
timestamp = datetime.datetime(2008, 5, 19, 11, 45, 23, 123456)
|
||||
|
||||
if self.tz_tests:
|
||||
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, 'T'), u'CET')
|
||||
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(summertime, 'I'), u'1')
|
||||
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''
|
||||
>>> f.clean('')
|
||||
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.fr import tests as localflavor_fr_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.it import tests as localflavor_it_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.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.se import tests as localflavor_se_tests
|
||||
from localflavor.sk import tests as localflavor_sk_tests
|
||||
from localflavor.uk import tests as localflavor_uk_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 regressions import tests as regression_tests
|
||||
from util import tests as util_tests
|
||||
@ -52,16 +57,21 @@ __test__ = {
|
||||
'localflavor_fi_tests': localflavor_fi_tests,
|
||||
'localflavor_fr_tests': localflavor_fr_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_it_tests': localflavor_it_tests,
|
||||
'localflavor_jp_tests': localflavor_jp_tests,
|
||||
'localflavor_kw_tests': localflavor_kw_tests,
|
||||
'localflavor_nl_tests': localflavor_nl_tests,
|
||||
'localflavor_pl_tests': localflavor_pl_tests,
|
||||
'localflavor_pt_tests': localflavor_pt_tests,
|
||||
'localflavor_ro_tests': localflavor_ro_tests,
|
||||
'localflavor_se_tests': localflavor_se_tests,
|
||||
'localflavor_sk_tests': localflavor_sk_tests,
|
||||
'localflavor_uk_tests': localflavor_uk_tests,
|
||||
'localflavor_us_tests': localflavor_us_tests,
|
||||
'localflavor_uy_tests': localflavor_uy_tests,
|
||||
'localflavor_za_tests': localflavor_za_tests,
|
||||
'regression_tests': regression_tests,
|
||||
'formset_tests': formset_tests,
|
||||
|
@ -10,6 +10,8 @@ tests = r"""
|
||||
... from decimal import Decimal
|
||||
... except ImportError:
|
||||
... from django.utils._decimal import Decimal
|
||||
>>> from django.utils.translation import activate, deactivate
|
||||
>>> from django.conf import settings
|
||||
|
||||
###########
|
||||
# Widgets #
|
||||
@ -1082,6 +1084,13 @@ True
|
||||
False
|
||||
>>> w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06/05/2008', u'12:41'])
|
||||
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 ###############################################################
|
||||
|
||||
@ -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" />'
|
||||
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||
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.
|
||||
>>> 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')
|
||||
False
|
||||
|
||||
|
||||
# DateInput ###################################################################
|
||||
|
||||
>>> w = DateInput()
|
||||
@ -1125,6 +1141,13 @@ We should be able to initialize from a unicode value.
|
||||
>>> w.render('date', u'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.
|
||||
>>> w = DateInput(format='%d/%m/%Y')
|
||||
>>> 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')
|
||||
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.
|
||||
>>> w = TimeInput(format='%H:%M')
|
||||
>>> 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" />'
|
||||
>>> 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" />'
|
||||
>>> 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.forms.extras import SelectDateWidget
|
||||
from models import Company
|
||||
|
||||
class I18nForm(forms.Form):
|
||||
decimal_field = forms.DecimalField()
|
||||
@ -11,3 +12,6 @@ class I18nForm(forms.Form):
|
||||
class SelectDateForm(forms.Form):
|
||||
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.utils.translation import ugettext_lazy as _
|
||||
|
||||
class TestModel(models.Model):
|
||||
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': '''
|
||||
>>> tm = TestModel()
|
||||
>>> tm.save()
|
||||
'''
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
import sys
|
||||
import decimal
|
||||
import datetime
|
||||
|
||||
from django.template import Template, Context
|
||||
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.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):
|
||||
|
||||
@ -80,6 +82,23 @@ class TranslationTests(TestCase):
|
||||
finally:
|
||||
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):
|
||||
|
||||
def setUp(self):
|
||||
@ -90,8 +109,10 @@ class FormattingTests(TestCase):
|
||||
self.f = 99999.999
|
||||
self.d = datetime.date(2009, 12, 31)
|
||||
self.dt = datetime.datetime(2009, 12, 31, 20, 50)
|
||||
self.t = datetime.time(10, 15, 48)
|
||||
self.ctxt = Context({
|
||||
'n': self.n,
|
||||
't': self.t,
|
||||
'd': self.d,
|
||||
'dt': self.dt,
|
||||
'f': self.f
|
||||
@ -102,10 +123,10 @@ class FormattingTests(TestCase):
|
||||
settings.USE_I18N = self._use_i18n
|
||||
settings.USE_L10N = self._use_l10n
|
||||
settings.USE_THOUSAND_SEPARATOR = self._use_thousand_separator
|
||||
|
||||
|
||||
def test_locale_independent(self):
|
||||
"""
|
||||
Localization of dates and numbers
|
||||
Localization of numbers
|
||||
"""
|
||||
settings.USE_L10N = True
|
||||
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.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):
|
||||
"""
|
||||
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(0, get_format('FIRST_DAY_OF_WEEK'))
|
||||
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'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'))
|
||||
@ -143,6 +169,7 @@ class FormattingTests(TestCase):
|
||||
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'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 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(
|
||||
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:
|
||||
deactivate()
|
||||
@ -183,6 +210,7 @@ class FormattingTests(TestCase):
|
||||
self.assertEqual('j \de F \de Y', get_format('DATE_FORMAT'))
|
||||
self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK'))
|
||||
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'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'))
|
||||
@ -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'66666,67', Template('{{ n|floatformat:2 }}').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 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(
|
||||
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:
|
||||
deactivate()
|
||||
@ -300,7 +329,7 @@ class FormattingTests(TestCase):
|
||||
self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
|
||||
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>',
|
||||
SelectDateWidget().render('mydate', datetime.date(2009, 12, 31))
|
||||
SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
|
||||
)
|
||||
finally:
|
||||
deactivate()
|
||||
@ -323,6 +352,28 @@ class FormattingTests(TestCase):
|
||||
finally:
|
||||
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):
|
||||
|
||||
def test_parse_spec_http_header(self):
|
||||
|
@ -1,13 +1,6 @@
|
||||
from django.forms import ModelForm
|
||||
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):
|
||||
"""docstring for PlaceForm"""
|
||||
class Meta:
|
||||
|
@ -1,14 +1,6 @@
|
||||
from django.db import models
|
||||
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):
|
||||
state = USStateField(blank=True)
|
||||
state_req = USStateField()
|
||||
|
@ -2,89 +2,6 @@ from django.test import TestCase
|
||||
from models import Place
|
||||
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):
|
||||
def setUp(self):
|
||||
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.test import TestCase
|
||||
from django.utils.translation import activate
|
||||
from django.utils.text import javascript_quote
|
||||
|
||||
from regressiontests.views.urls import locale_dir
|
||||
|
||||
@ -20,11 +21,12 @@ class I18NTests(TestCase):
|
||||
|
||||
def test_jsi18n(self):
|
||||
"""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)
|
||||
catalog = gettext.translation('djangojs', locale_dir, [lang_code])
|
||||
trans_txt = catalog.ugettext('this is to be translated')
|
||||
response = self.client.get('/views/jsi18n/')
|
||||
# in response content must to be a line like that:
|
||||
# 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,
|
||||
extra_tests=extra_tests)
|
||||
if failures:
|
||||
sys.exit(failures)
|
||||
sys.exit(bool(failures))
|
||||
|
||||
# Restore the old settings.
|
||||
settings.INSTALLED_APPS = old_installed_apps
|
||||
|
Loading…
x
Reference in New Issue
Block a user