| 100 | |
| 101 | class CLPatenteField(CharField): |
| 102 | """ |
| 103 | Chilean "Patente", Placa Patente Field, support old LL-NNNN and new LLLL-NN |
| 104 | type, where L in new can't be vowel or m,n and q. |
| 105 | """ |
| 106 | |
| 107 | default_error_messages = CharField.default_error_messages |
| 108 | default_error_messages.update({'invalid': _('Enter a valid Chilean Car Plate.'),}) |
| 109 | |
| 110 | def __init__(self, *args, **kwargs): |
| 111 | kwargs['max_length'] = 7 |
| 112 | kwargs['min_length'] = 6 |
| 113 | kwargs['label'] = "Valor" |
| 114 | super(CLPatenteField, self).__init__(*args, **kwargs) |
| 115 | |
| 116 | def clean(self, value): |
| 117 | """ |
| 118 | Check and clean the field for length and type. |
| 119 | """ |
| 120 | super(CLPatenteField, self).clean(value) |
| 121 | if value in EMPTY_VALUES: |
| 122 | return u'' |
| 123 | |
| 124 | value = smart_unicode(value.lower()) |
| 125 | value_length = len(value) |
| 126 | if self.max_length is not None and value_length > self.max_length: |
| 127 | raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) |
| 128 | if self.min_length is not None and value_length < self.min_length: |
| 129 | raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) |
| 130 | |
| 131 | value = self._canonify(value) |
| 132 | _type = self._algorithm(value) |
| 133 | |
| 134 | if _type not in (OLD, NEW): |
| 135 | raise ValidationError(self.error_messages['invalid']) |
| 136 | |
| 137 | return self._format(value.upper(), _type) |
| 138 | |
| 139 | def _algorithm(self, value): |
| 140 | """ |
| 141 | Takes Car Plate in canonical form and verify if it is valid. |
| 142 | Returns the type or None it is not valid. |
| 143 | """ |
| 144 | import re |
| 145 | # Old type patern |
| 146 | op = '^[a-z]{2,2}\d{4,4}$' |
| 147 | op = re.compile(op) |
| 148 | # New type patern |
| 149 | np = '^[bcdfghjklprstvwxyz]{4,4}\d{2,2}$' |
| 150 | np = re.compile(np) |
| 151 | if re.search(op, value): |
| 152 | return OLD |
| 153 | elif re.search(np, value): |
| 154 | return NEW |
| 155 | else: |
| 156 | return None |
| 157 | |
| 158 | def _canonify(self, patente): |
| 159 | """ |
| 160 | Turns the Car Plate into one normalized format. |
| 161 | """ |
| 162 | return patente.replace(' ', '').replace('-', '') |
| 163 | |
| 164 | def _format(self, value, _type): |
| 165 | """ |
| 166 | Formats the Car Plate from canonical form to the common string |
| 167 | representation. LL-DDDD or LLLL-DD |
| 168 | """ |
| 169 | if _type == OLD: |
| 170 | return u'-'.join((value[:2], value[2:])) |
| 171 | if _type == NEW: |
| 172 | return u'-'.join((value[:4], value[4:])) |