Commits

Honz...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed 7743c88

[soc2009/model-validation] Merged to trunk at r12070

  • Participants
  • Parent commits 66318a6
  • Branches soc2009/model-validation

Comments (0)

Files changed (85)

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

File django/conf/global_settings.py

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

File django/conf/locale/it/formats.py

 # 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

File django/conf/locale/no/formats.py

     '%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 = ','

File django/conf/locale/pl/LC_MESSAGES/django.po

 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"
 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?"
 
 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."
 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"
 "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"

File django/contrib/admin/media/js/admin/DateTimeShortcuts.js

         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 + ');');
         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';
     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') {
         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) {

File django/contrib/admin/media/js/core.js

     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);
 }
     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();
 }
     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
 // ----------------------------------------------------------------------------

File django/contrib/admin/options.py

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

File django/contrib/admin/templatetags/admin_list.py

             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)

File django/contrib/admin/util.py

 
 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)

File django/contrib/admin/widgets.py

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

File django/contrib/auth/models.py

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

File django/contrib/auth/tests/auth_backends.py

         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

File django/contrib/databrowse/datastructures.py

                 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:

File django/contrib/databrowse/plugins/calendars.py

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

File django/contrib/databrowse/templates/databrowse/calendar_day.html

 
 {% 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>
 

File django/contrib/databrowse/templates/databrowse/calendar_main.html

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

File django/contrib/databrowse/templates/databrowse/calendar_month.html

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

File django/contrib/gis/db/backends/postgis/operations.py

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

File django/contrib/gis/db/backends/spatialite/base.py

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

File django/contrib/gis/db/backends/spatialite/creation.py

         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)
 

File django/contrib/gis/db/backends/spatialite/operations.py

     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
 
         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:]
         """
         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]
         """
         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
 

File django/contrib/gis/db/models/manager.py

     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)

File django/contrib/gis/db/models/sql/compiler.py

         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)

File django/contrib/gis/geos/prototypes/errcheck.py

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

File django/contrib/gis/tests/relatedapp/tests.py

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

File django/contrib/localflavor/id/__init__.py

Empty file added.

File django/contrib/localflavor/id/forms.py

+"""
+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:])

File django/contrib/localflavor/id/id_choices.py

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

File django/contrib/localflavor/ie/__init__.py

Empty file added.

File django/contrib/localflavor/ie/forms.py

+"""
+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)

File django/contrib/localflavor/ie/ie_counties.py

+"""
+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')),
+)

File django/contrib/localflavor/kw/__init__.py

Empty file added.

File django/contrib/localflavor/kw/forms.py

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

File django/contrib/localflavor/pt/__init__.py

Empty file added.

File django/contrib/localflavor/pt/forms.py

+"""
+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'])

File django/contrib/localflavor/uk/forms.py

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

File django/contrib/localflavor/us/forms.py

 
 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
         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.',
     }

File django/contrib/localflavor/us/models.py

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

File django/contrib/localflavor/uy/__init__.py

Empty file added.

File django/contrib/localflavor/uy/forms.py

+# -*- 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

File django/contrib/localflavor/uy/util.py

+# -*- 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

File django/contrib/localflavor/uy/uy_departaments.py

+# -*- 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'),
+)

File django/core/management/commands/test.py

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

File django/forms/widgets.py

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

File django/template/defaultfilters.py

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

File django/test/simple.py

+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
 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.
+        """