diff options
author | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-04-17 15:57:16 +0000 |
---|---|---|
committer | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-04-17 15:57:16 +0000 |
commit | ab622a35bd75dbaaa712e77b35ee0fdaefabc8a0 (patch) | |
tree | f4445a87226cd362a7fd9464ffbc8607a779a869 | |
parent | e2a3b9e1bdff6a43f8525319ebfeff6949aa796f (diff) | |
download | django-ab622a35bd75dbaaa712e77b35ee0fdaefabc8a0.tar.gz |
boulder-oracle-sprint: Merged to [5018]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5019 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | django/contrib/databrowse/datastructures.py | 10 | ||||
-rw-r--r-- | django/contrib/localflavor/it/forms.py | 48 | ||||
-rw-r--r-- | django/contrib/localflavor/it/util.py | 40 | ||||
-rw-r--r-- | django/db/backends/postgresql/base.py | 4 | ||||
-rw-r--r-- | django/db/backends/postgresql_psycopg2/base.py | 4 | ||||
-rw-r--r-- | tests/regressiontests/fixtures_regress/models.py | 7 | ||||
-rw-r--r-- | tests/regressiontests/forms/localflavor.py | 42 |
8 files changed, 147 insertions, 9 deletions
@@ -174,6 +174,7 @@ answer newbie questions, and generally made Django that much better: J. Rademaker Michael Radziej <mir@noris.de> ramiro + Massimiliano Ravelli <massimiliano.ravelli@gmail.com> Brian Ray <http://brianray.chipy.org/> remco@diji.biz rhettg@gmail.com diff --git a/django/contrib/databrowse/datastructures.py b/django/contrib/databrowse/datastructures.py index 3c509a2830..24f2e68f46 100644 --- a/django/contrib/databrowse/datastructures.py +++ b/django/contrib/databrowse/datastructures.py @@ -3,12 +3,13 @@ These classes are light wrappers around Django's database API that provide convenience functionality and permalink functions for the databrowse app. """ -from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE from django.db import models from django.utils import dateformat from django.utils.text import capfirst from django.utils.translation import get_date_formats +EMPTY_VALUE = '(None)' + class EasyModel(object): def __init__(self, site, model): self.site = site @@ -132,13 +133,16 @@ class EasyInstanceField(object): Returns a list of values for this field for this instance. It's a list so we can accomodate many-to-many fields. """ + # This import is deliberately inside the function because it causes + # some settings to be imported, and we don't want to do that at the + # module level. if self.field.rel: if isinstance(self.field.rel, models.ManyToOneRel): objs = getattr(self.instance.instance, self.field.name) elif isinstance(self.field.rel, models.ManyToManyRel): # ManyToManyRel return list(getattr(self.instance.instance, self.field.name).all()) elif self.field.choices: - objs = dict(self.field.choices).get(self.raw_value, EMPTY_CHANGELIST_VALUE) + objs = dict(self.field.choices).get(self.raw_value, EMPTY_VALUE) elif isinstance(self.field, models.DateField) or isinstance(self.field, models.TimeField): if self.raw_value: date_format, datetime_format, time_format = get_date_formats() @@ -149,7 +153,7 @@ class EasyInstanceField(object): else: objs = capfirst(dateformat.format(self.raw_value, date_format)) else: - objs = EMPTY_CHANGELIST_VALUE + objs = EMPTY_VALUE elif isinstance(self.field, models.BooleanField) or isinstance(self.field, models.NullBooleanField): objs = {True: 'Yes', False: 'No', None: 'Unknown'}[self.raw_value] else: diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py index 8e9d8bc11d..bb1bb2e6a4 100644 --- a/django/contrib/localflavor/it/forms.py +++ b/django/contrib/localflavor/it/forms.py @@ -5,13 +5,15 @@ IT-specific Form helpers from django.newforms import ValidationError from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES from django.utils.translation import gettext +from django.utils.encoding import smart_unicode +from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit import re class ITZipCodeField(RegexField): def __init__(self, *args, **kwargs): super(ITZipCodeField, self).__init__(r'^\d{5}$', max_length=None, min_length=None, - error_message=gettext(u'Enter a zip code in the format XXXXX.'), + error_message=gettext(u'Enter a valid zip code.'), *args, **kwargs) class ITRegionSelect(Select): @@ -29,3 +31,47 @@ class ITProvinceSelect(Select): def __init__(self, attrs=None): from it_province import PROVINCE_CHOICES # relative import super(ITProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES) + +class ITSocialSecurityNumberField(RegexField): + """ + A form field that validates Italian Social Security numbers (codice fiscale). + For reference see http://www.agenziaentrate.it/ and search for + 'Informazioni sulla codificazione delle persone fisiche'. + """ + err_msg = gettext(u'Enter a valid Social Security number.') + def __init__(self, *args, **kwargs): + super(ITSocialSecurityNumberField, self).__init__(r'^\w{3}\s*\w{3}\s*\w{5}\s*\w{5}$', + max_length=None, min_length=None, error_message=self.err_msg, + *args, **kwargs) + + def clean(self, value): + value = super(ITSocialSecurityNumberField, self).clean(value) + if value == u'': + return value + value = re.sub('\s', u'', value).upper() + try: + check_digit = ssn_check_digit(value) + except ValueError: + raise ValidationError(self.err_msg) + if not value[15] == check_digit: + raise ValidationError(self.err_msg) + return value + +class ITVatNumberField(Field): + """ + A form field that validates Italian VAT numbers (partita IVA). + """ + def clean(self, value): + value = super(ITVatNumberField, self).clean(value) + if value == u'': + return value + err_msg = gettext(u'Enter a valid VAT number.') + try: + vat_number = int(value) + except ValueError: + raise ValidationError(err_msg) + vat_number = str(vat_number).zfill(11) + check_digit = vat_number_check_digit(vat_number[0:10]) + if not vat_number[10] == check_digit: + raise ValidationError(err_msg) + return smart_unicode(vat_number) diff --git a/django/contrib/localflavor/it/util.py b/django/contrib/localflavor/it/util.py new file mode 100644 index 0000000000..49b607f160 --- /dev/null +++ b/django/contrib/localflavor/it/util.py @@ -0,0 +1,40 @@ +def ssn_check_digit(value): + "Calculate Italian social security number check digit." + ssn_even_chars = { + '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, + 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9, + 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, + 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25 + } + ssn_odd_chars = { + '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19, '9': 21, + 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17, 'I': 19, 'J': 21, + 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6, 'R': 8, 'S': 12, + 'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23 + } + # Chars from 'A' to 'Z' + ssn_check_digits = [chr(x) for x in range(65, 91)] + + ssn = value.upper() + total = 0 + for i in range(0,15): + try: + if i % 2 == 0: + total += ssn_odd_chars[ssn[i]] + else: + total += ssn_even_chars[ssn[i]] + except KeyError: + msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]} + raise ValueError(msg) + return ssn_check_digits[total % 26] + +def vat_number_check_digit(vat_number): + "Calculate Italian VAT number check digit." + normalized_vat_number = str(vat_number).zfill(10) + total = 0 + for i in range(0, 10, 2): + total += int(normalized_vat_number[i]) + for i in range(1, 11, 2): + quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10) + total += quotient + remainder + return str((10 - total % 10) % 10) diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 9f191f27a3..2f2363728f 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -210,7 +210,7 @@ def get_sql_flush(style, tables, sequences): sql.append("%s %s %s %s %s %s;" % \ (style.SQL_KEYWORD('ALTER'), style.SQL_KEYWORD('SEQUENCE'), - style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)), + style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))), style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('WITH'), style.SQL_FIELD('1') @@ -221,7 +221,7 @@ def get_sql_flush(style, tables, sequences): sql.append("%s %s %s %s %s %s;" % \ (style.SQL_KEYWORD('ALTER'), style.SQL_KEYWORD('SEQUENCE'), - style.SQL_FIELD('%s_id_seq' % table_name), + style.SQL_FIELD(quote_name('%s_id_seq' % table_name)), style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('WITH'), style.SQL_FIELD('1') diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index 25dbd7873a..1a149f42a7 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -167,7 +167,7 @@ def get_sql_flush(style, tables, sequences): sql.append("%s %s %s %s %s %s;" % \ (style.SQL_KEYWORD('ALTER'), style.SQL_KEYWORD('SEQUENCE'), - style.SQL_FIELD('%s_%s_seq' % (table_name, column_name)), + style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))), style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('WITH'), style.SQL_FIELD('1') @@ -178,7 +178,7 @@ def get_sql_flush(style, tables, sequences): sql.append("%s %s %s %s %s %s;" % \ (style.SQL_KEYWORD('ALTER'), style.SQL_KEYWORD('SEQUENCE'), - style.SQL_FIELD('%s_id_seq' % table_name), + style.SQL_FIELD(quote_name('%s_id_seq' % table_name)), style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('WITH'), style.SQL_FIELD('1') diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index f9d4d35045..dd407df353 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -7,6 +7,13 @@ class Animal(models.Model): def __str__(self): return self.common_name +class Plant(models.Model): + name = models.CharField(maxlength=150) + + class Meta: + # For testing when upper case letter in app name; regression for #4057 + db_table = "Fixtures_regress_plant" + __test__ = {'API_TESTS':""" >>> from django.core import management diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py index 2f54fcd109..3f4f41ae8d 100644 --- a/tests/regressiontests/forms/localflavor.py +++ b/tests/regressiontests/forms/localflavor.py @@ -633,7 +633,7 @@ u'00100' >>> f.clean(' 00100') Traceback (most recent call last): ... -ValidationError: [u'Enter a zip code in the format XXXXX.'] +ValidationError: [u'Enter a valid zip code.'] # ITRegionSelect ############################################################# @@ -642,6 +642,46 @@ ValidationError: [u'Enter a zip code in the format XXXXX.'] >>> w.render('regions', 'PMN') u'<select name="regions">\n<option value="ABR">Abruzzo</option>\n<option value="BAS">Basilicata</option>\n<option value="CAL">Calabria</option>\n<option value="CAM">Campania</option>\n<option value="EMR">Emilia-Romagna</option>\n<option value="FVG">Friuli-Venezia Giulia</option>\n<option value="LAZ">Lazio</option>\n<option value="LIG">Liguria</option>\n<option value="LOM">Lombardia</option>\n<option value="MAR">Marche</option>\n<option value="MOL">Molise</option>\n<option value="PMN" selected="selected">Piemonte</option>\n<option value="PUG">Puglia</option>\n<option value="SAR">Sardegna</option>\n<option value="SIC">Sicilia</option>\n<option value="TOS">Toscana</option>\n<option value="TAA">Trentino-Alto Adige</option>\n<option value="UMB">Umbria</option>\n<option value="VAO">Valle d\u2019Aosta</option>\n<option value="VEN">Veneto</option>\n</select>' +# ITSocialSecurityNumberField ################################################# + +>>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField +>>> f = ITSocialSecurityNumberField() +>>> f.clean('LVSGDU99T71H501L') +u'LVSGDU99T71H501L' +>>> f.clean('LBRRME11A01L736W') +u'LBRRME11A01L736W' +>>> f.clean('lbrrme11a01l736w') +u'LBRRME11A01L736W' +>>> f.clean('LBR RME 11A01 L736W') +u'LBRRME11A01L736W' +>>> f.clean('LBRRME11A01L736A') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Social Security number.'] +>>> f.clean('%BRRME11A01L736W') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid Social Security number.'] + +# ITVatNumberField ########################################################### + +>>> from django.contrib.localflavor.it.forms import ITVatNumberField +>>> f = ITVatNumberField() +>>> f.clean('07973780013') +u'07973780013' +>>> f.clean('7973780013') +u'07973780013' +>>> f.clean(7973780013) +u'07973780013' +>>> f.clean('07973780014') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid VAT number.'] +>>> f.clean('A7973780013') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid VAT number.'] + # FIZipCodeField ############################################################# FIZipCodeField validates that the data is a valid FI zipcode. |