Source code for django_auxilium.forms.range

from __future__ import print_function, unicode_literals
import re

from django import forms
from django.utils.translation import ugettext_lazy as _

from django_auxilium.utils.range import AlphabeticNumbers, Range


[docs]class RangeSelectorField(forms.CharField): """ Range field which supports Excel-type rangeconfig selectors. The rangeconfig selection is made using the following format:: <Column><Row>:<Column><Row> Examples -------- :: A:A A1:A50 1:50 Parameters ---------- max_rows : int, optional The maximum number of rows the range can have max_columns : int, optional The maximum number of columns the range can have max_either : int, optional The maximum number of rows and columns the range can have. For example if the value is 1 then either a single column or a single row can be selected. required_rows : bool, optional Whether rows must be supplied in the rangeconfig required_columns : bool, optional Whether columns must be supplied in the rangeconfig """ default_error_messages = { "invalid": _("Invalid range value."), "values": _("Top-left coordinate must be first."), "max_rows": _("Too many rows selected. Maximum is {0}."), "max_columns": _("Too many columns selected. Maximum is {0}."), "max_either": _("Too many rows or columns selected. Maximum is {0}."), "max_total": _("Too many total cells selected. Maximum is {0}."), "required_rows": _("Row selection is required."), "required_columns": _("Column selection is required."), } def __init__(self, *args, **kwargs): self.max_rows = kwargs.pop('max_rows', None) self.max_columns = kwargs.pop('max_columns', None) self.max_either = kwargs.pop('max_either', None) self.required_rows = kwargs.pop('required_rows', False) self.required_columns = kwargs.pop('required_columns', False) super(RangeSelectorField, self).__init__(*args, **kwargs)
[docs] def to_python(self, value): """ Convert range string value to ``Range`` rangeconfig value. Returns ------- Range """ value = super(RangeSelectorField, self).to_python(value) if value in self.empty_values: return # extract all components r = re.compile( r'^(?P<A>(?P<A1>[A-Z]+):(?P<A2>[A-Z]+))$' r'|^(?P<N>(?P<N1>\d+):(?P<N2>\d+))$' r'|^(?P<AN>(?P<AN_A1>[A-Z]+)(?P<AN_N1>\d+):(?P<AN_A2>[A-Z]+)(?P<AN_N2>\d+))$' ) # make sure overall pattern is valid if not r.findall(value): raise forms.ValidationError(self.error_messages['invalid']) datarange = None # extract rangeconfig values m = r.match(value) for group in ['A', 'N', 'AN']: if not m.group(group): continue if group == 'A': datarange = Range( AlphabeticNumbers.int_from_str(m.group('A1')), None, AlphabeticNumbers.int_from_str(m.group('A2')), None ) elif group == 'N': datarange = Range( None, int(m.group('N1')), None, int(m.group('N2')) ) else: datarange = Range( AlphabeticNumbers.int_from_str(m.group('AN_A1')), int(m.group('AN_N1')), AlphabeticNumbers.int_from_str(m.group('AN_A2')), int(m.group('AN_N2')) ) return datarange
[docs] def validate(self, value): """ Validate the rangeconfig value. Following is validated: * rows or columns are supplied depending on ``required_row`` and ``required_columns`` parameters * rangeconfig is given as top-left to bottom-right * columns range is within ``max_columns`` * rows range is within ``max_rows`` * both columns and rows range is within ``max_either`` """ if value in self.empty_values: return if self.required_columns and not value.first_column: raise forms.ValidationError( self.error_messages['required_columns'] ) if self.required_rows and not value.first_row: raise forms.ValidationError( self.error_messages['required_rows'] ) # make sure the first rangeconfig coordinate is top-left for i, j in zip(value[:2], value[2:]): if i and j and i > j: raise forms.ValidationError(self.error_messages['values']) if self.max_columns and value.columns > self.max_columns: raise forms.ValidationError( self.error_messages['max_columns'].format(self.max_columns) ) if self.max_rows and value.rows > self.max_rows: raise forms.ValidationError( self.error_messages['max_rows'].format(self.max_rows) ) if self.max_either: if all([value.columns > self.max_either, value.rows > self.max_either]): raise forms.ValidationError( self.error_messages['max_either'].format(self.max_either) )