/apps/survey/forms/fields.py

https://github.com/asdahlborg/epiwork-website · Python · 182 lines · 170 code · 7 blank · 5 comment · 0 complexity · 58df0ae8cb0ea3dafbd87e2603dada40 MD5 · raw file

  1. """In the pollster approach we no longer see Postalcodes as a separate field
  2. These files are kept for backwards compatability"""
  3. import datetime
  4. import re
  5. from django import forms
  6. from django.utils.safestring import mark_safe
  7. from django.conf import settings
  8. from django.contrib.localflavor.it.forms import ITZipCodeField
  9. from django.contrib.localflavor.nl.forms import NLZipCodeField
  10. from django.contrib.localflavor.uk.forms \
  11. import UKPostcodeField as fullUKPostcodeField
  12. from django.contrib.localflavor.be.forms import BEPostalCodeField
  13. from django.contrib.localflavor.pt.forms import PTZipCodeField
  14. from django.contrib.localflavor.se.forms import SEPostalCodeField
  15. from .widgets import ( AdviseWidget, MonthYearWidget,
  16. DatePickerWidget, DateOrOptionPickerWidget,
  17. TableOptionsSingleWidget, TableOfSelectsWidget, )
  18. __all__ = ['AdviseField', 'MonthYearField', 'PostCodeField', 'DateOrOptionField',
  19. 'TableOptionsSingleField', 'TableOfSelectsField', ]
  20. class AdviseField(forms.Field):
  21. widget = AdviseWidget
  22. required = False
  23. def clean(self, value):
  24. return True
  25. class MonthYearField(forms.Field):
  26. widget = MonthYearWidget
  27. def clean(self, value):
  28. """
  29. Validate month and year values.
  30. This method is derived from Django's DateField's clean()
  31. """
  32. super(MonthYearField, self).clean(value)
  33. if value in (None, ''):
  34. return None
  35. if isinstance(value, datetime.datetime):
  36. return value.date()
  37. if isinstance(value, datetime.date):
  38. return value
  39. try:
  40. year, month = value.split('-')
  41. year = int(year)
  42. month = int(month)
  43. return datetime.datetime(year, month, 1).date()
  44. except ValueError:
  45. pass
  46. raise forms.ValidationError(self.error_messages['invalid'])
  47. class UKPostcodeField(fullUKPostcodeField):
  48. """Accept and check only the outcode_pattern of the UK postcode. This is
  49. necessary for privacy reasons since the full post code gives too accurate a
  50. fix on the participant.
  51. """
  52. outcode_pattern = fullUKPostcodeField.outcode_pattern
  53. postcode_regex = re.compile(r'^(GIR|%s)$' % outcode_pattern)
  54. def clean(self, value):
  55. value = super(UKPostcodeField, self).clean(value)
  56. if value == u'':
  57. return value
  58. postcode = value.upper().strip()
  59. if not self.postcode_regex.search(postcode):
  60. raise ValidationError(self.default_error_messages['invalid'])
  61. return postcode
  62. class PostCodeField(forms.RegexField):
  63. country_fields = {
  64. 'be': BEPostalCodeField,
  65. 'it': ITZipCodeField,
  66. 'nl': NLZipCodeField,
  67. 'pt': PTZipCodeField,
  68. 'se': SEPostalCodeField,
  69. 'uk': UKPostcodeField,
  70. }
  71. def __init__(self, *args, **kwargs):
  72. self.country = kwargs.pop('country', settings.COUNTRY)
  73. super(PostCodeField, self).__init__(self.country, *args, **kwargs)
  74. def clean(self, value):
  75. klass = self.country_fields.get(self.country, None)
  76. if klass is None:
  77. klass = self.country_fields['nl']
  78. field = klass()
  79. return field.clean(value)
  80. class DateOrOptionField(forms.MultiValueField):
  81. def __init__(self, *args, **kwargs):
  82. self.option = kwargs.pop('option', '')
  83. self.widget=DateOrOptionPickerWidget(choices=[(0, self.option)])
  84. datefield = forms.DateField(required=False,
  85. help_text="Date format: day/month/year",
  86. input_formats=['%Y-%m-%d', '%d/%m/%Y',
  87. '%d/%m/%y', '%d-%m-%y',
  88. '%d-%m-%Y', '%b %d %Y',
  89. '%b %d, %Y', '%d %b %Y',
  90. '%d %b, %Y', '%B %d %Y',
  91. '%B %d, %Y', '%d %B %Y',
  92. '%d %B, %Y'])
  93. self.datefield = datefield
  94. self.fields=[datefield,
  95. forms.ChoiceField(required=False)]
  96. super(DateOrOptionField, self).__init__(fields=self.fields,
  97. widget=self.widget,
  98. *args, **kwargs)
  99. def compress(self, v):
  100. return v
  101. def clean(self, value):
  102. date, choice = value
  103. if len(choice) > 0: # option was chosen
  104. return choice[0]
  105. else: # use the date
  106. date = self.datefield.clean(date)
  107. if date is None:
  108. if self.required:
  109. raise forms.ValidationError(self.error_messages['required'])
  110. return None
  111. return date
  112. class TableOfSelectsField(forms.MultiValueField):
  113. def __init__(self, rows, columns, choices, *args, **kwargs):
  114. fields = [forms.ChoiceField(label=row, choices=choices, required=False)
  115. for row in rows
  116. for column in columns]
  117. kwargs['widget'] = TableOfSelectsWidget(rows, columns, choices)
  118. super(TableOfSelectsField, self).__init__(fields, *args, **kwargs)
  119. def compress(self, v):
  120. return v
  121. def clean(self, value):
  122. return value
  123. class TableOptionsSingleField(forms.MultiValueField):
  124. def __init__(self, options, rows, required_rows=None, *args, **kwargs):
  125. self.options = options
  126. self.rows = rows
  127. self.required_rows = required_rows
  128. if not 'widget' in kwargs:
  129. widget = TableOptionsSingleWidget(options=self.options,
  130. rows=self.rows)
  131. kwargs['widget'] = widget
  132. if not 'fields' in kwargs:
  133. fields = []
  134. for key, label in self.rows:
  135. field = forms.ChoiceField(label=label,
  136. required=False,
  137. choices=list(self.options))
  138. fields.append(field)
  139. kwargs['fields'] = fields
  140. super(TableOptionsSingleField, self).__init__(**kwargs)
  141. def compress(self, value):
  142. return value
  143. def clean(self, value):
  144. return value
  145. def clean_all(self, field, values):
  146. required = self.required_rows
  147. if required is None:
  148. required = range(0, len(self.rows))
  149. elif callable(required):
  150. required = required(values)
  151. filled = []
  152. if values[field] is not None:
  153. for index, value in enumerate(values[field]):
  154. if value is not None:
  155. filled.append(index)
  156. for index in required:
  157. if not index in filled:
  158. raise forms.ValidationError('Incomplete answer')
  159. return values[field]