PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/source/questions/forms/__init__.py

https://github.com/openstate/Wiekiesjij
Python | 294 lines | 232 code | 33 blank | 29 comment | 15 complexity | c892b0cacca1e6ebc6537eb167fada65 MD5 | raw file
  1. import copy
  2. from django import forms
  3. from django.utils.translation import ugettext_lazy as _
  4. from django.forms import widgets
  5. from django.template.loader import render_to_string
  6. from political_profiles.models import RELIGION, GENDERS
  7. from form_utils.forms import BetterModelForm, BetterForm
  8. from utils.formutils import TemplateForm
  9. # TODO make better imports
  10. from questions.exceptions import ModelAnswerFormError
  11. from questions.models import Question, Answer
  12. from questions.settings import MULTIPLE_ANSWER_TYPES, QTYPE_NORM_POLONECHOICE_VISONECHOICE_RANGE, QTYPE_MODEL_POLITICAL_EXPERIENCE_YEARS, QTYPE_MODEL_EDUCATION_LEVEL, QTYPE_MODEL_PROFILE_RELIGION, QTYPE_MODEL_PROFILE_AGE, QTYPE_MODEL_PROFILE_GENDER, QTYPE_NORM_POLONECHOICE_VISONECHOICE_SECRET, QTYPE_NORM_POLONECHOICE_VISONECHOICE, QTYPE_NORM_POLMULTICHOICE_VISMULTICHOICE, QTYPE_NORM_POLBOOL_VISBOOL, QUESTION_TYPE_CHOICES, QTYPE_NORM_POLMULTICHOICE_VISMULTICHOICE_MIN_THREE
  13. from django.core import validators
  14. class MinNumAnswersValidator(validators.BaseValidator):
  15. compare = lambda self, a, b: a < b
  16. clean = lambda self, x: len(x)
  17. message = _('Zorg dat tenminste %(limit_value)d keuzes geselecteerd zijn.')
  18. code = 'min_length'
  19. class SelectQuestionForm(BetterModelForm, TemplateForm):
  20. '''
  21. Step 1 - we first select a question, then fill the answer.
  22. Based on the type of the question, we are able to add one or more answers to the question.
  23. For example, if we try to add more answer to the BooleanField question type, we shall get an exception, because it
  24. should not be possible.
  25. For MultipleChoice and MultipleAnswer fields choices shall be unlimited.
  26. '''
  27. def __init__(self, *args, **kwargs):
  28. super(self.__class__, self).__init__(*args, **kwargs)
  29. #self.fields['value'].widget = widgets.CheckboxSelectMultiple
  30. class Meta:
  31. model = Answer
  32. fields = ('question',)
  33. class AnswerQuestionForm(BetterForm, TemplateForm):
  34. '''
  35. Form which displays possible answers, coupled to the question given. It makes sure the answer has the
  36. right widget, which depends on the question type.
  37. '''
  38. def __init__(self, question_instance_id, *args, **kwargs):
  39. question_types = dict(QUESTION_TYPE_CHOICES)
  40. question_instance = Question.objects.get(id=question_instance_id)
  41. if not question_instance:
  42. return
  43. if question_instance.question_type in question_types:
  44. choices = map(lambda x: (x.id, x.value), question_instance.answers.all())
  45. #if question_instance.has_no_preference:
  46. #choices.append(('no_pref', _('Geen voorkeur')))
  47. if question_instance.question_type in MULTIPLE_ANSWER_TYPES:
  48. myValidators = []
  49. if (QTYPE_NORM_POLMULTICHOICE_VISMULTICHOICE_MIN_THREE == question_instance.question_type):
  50. myValidators.append(MinNumAnswersValidator(3))
  51. self.base_fields.update({'value': forms.MultipleChoiceField(label=_('Answer'), widget=widgets.CheckboxSelectMultiple(choices=choices), choices=choices, validators=myValidators)})
  52. elif QTYPE_NORM_POLONECHOICE_VISONECHOICE == question_instance.question_type:
  53. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  54. elif QTYPE_NORM_POLBOOL_VISBOOL == question_instance.question_type:
  55. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)}) #RadioBoolean() #widgets.NullBooleanSelect()
  56. elif QTYPE_NORM_POLONECHOICE_VISONECHOICE_RANGE == question_instance.question_type:
  57. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  58. elif QTYPE_MODEL_EDUCATION_LEVEL == question_instance.question_type:
  59. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  60. elif QTYPE_NORM_POLONECHOICE_VISONECHOICE_SECRET == question_instance.question_type:
  61. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  62. else:
  63. #print "This question type doenst know what type of form to show"
  64. #print question_instance.question_type
  65. pass #TODO raise error
  66. else:
  67. #print "This question type isnt in question type choices"
  68. pass #TODO raise error
  69. super(AnswerQuestionForm, self).__init__(*args, **kwargs)
  70. class Meta:
  71. fields = ('value',)
  72. class PartyMultipleModelChoiceField(forms.ModelMultipleChoiceField):
  73. def __init__(self, *args, **kwargs):
  74. super(self.__class__, self).__init__(*args, **kwargs)
  75. def label_from_instance(self, obj):
  76. return render_to_string('questions/_party_item.html', {'party': obj})
  77. class PartyQuestionForm(BetterForm, TemplateForm):
  78. value = PartyMultipleModelChoiceField(label=_('Answer'), queryset=None, widget=widgets.CheckboxSelectMultiple)
  79. class Meta:
  80. fieldsets = (('main', {'fields': ('value',), 'legend': '', 'classes': ('default','party-selection')}),)
  81. def __init__(self, queryset=None, empty_label=_('Geen voorkeur'), *args, **kwargs):
  82. super(self.__class__, self).__init__(*args, **kwargs)
  83. try:
  84. self.fields['value'].empty_label = empty_label
  85. self.fields['value'].queryset = queryset
  86. except Exception:
  87. raise ModelAnswerFormError('You need to provide a model to the ModelAnswerForm')
  88. class MyNoPrefModelChoiceIterator(object):
  89. def __init__(self, field):
  90. self.field = field
  91. self.queryset = field.queryset
  92. def __iter__(self):
  93. if self.field.cache_choices:
  94. if self.field.choice_cache is None:
  95. self.field.choice_cache = [
  96. self.choice(obj) for obj in self.queryset.all()
  97. ]
  98. for choice in self.field.choice_cache:
  99. yield choice
  100. else:
  101. for obj in self.queryset.all():
  102. yield self.choice(obj)
  103. if self.field.empty_label is not None:
  104. yield (u"no_pref", self.field.empty_label)
  105. def choice(self, obj):
  106. if self.field.to_field_name:
  107. key = obj.serializable_value(self.field.to_field_name)
  108. else:
  109. key = obj.pk
  110. return (key, self.field.label_from_instance(obj))
  111. class WorkExpMultipleModelChoiceField(forms.ModelMultipleChoiceField):
  112. def __init__(self, *args, **kwargs):
  113. super(self.__class__, self).__init__(*args, **kwargs)
  114. def label_from_instance(self, obj):
  115. return obj.sector
  116. def _get_choices(self):
  117. # If self._choices is set, then somebody must have manually set
  118. # the property self.choices. In this case, just return self._choices.
  119. if hasattr(self, '_choices'):
  120. return self._choices
  121. # Otherwise, execute the QuerySet in self.queryset to determine the
  122. # choices dynamically. Return a fresh QuerySetIterator that has not been
  123. # consumed. Note that we're instantiating a new QuerySetIterator *each*
  124. # time _get_choices() is called (and, thus, each time self.choices is
  125. # accessed) so that we can ensure the QuerySet has not been consumed. This
  126. # construct might look complicated but it allows for lazy evaluation of
  127. # the queryset.
  128. return MyNoPrefModelChoiceIterator(self)
  129. def clean(self, value):
  130. if 'no_pref' in value:
  131. return ['no_pref']
  132. else:
  133. return super(self.__class__, self).clean(value)
  134. choices = property(_get_choices, forms.ChoiceField._set_choices)
  135. class WorkTypeQuestionForm(BetterForm, TemplateForm):
  136. value = WorkExpMultipleModelChoiceField(label=_('Answer'), queryset=None, widget=widgets.CheckboxSelectMultiple)
  137. class Meta:
  138. fieldsets = (('main', {'fields': ('value',), 'legend': '', 'classes': ('default',)}),)
  139. def __init__(self, queryset=None, empty_label=_('Geen voorkeur'), *args, **kwargs):
  140. super(self.__class__, self).__init__(*args, **kwargs)
  141. try:
  142. self.fields['value'].empty_label = empty_label
  143. self.fields['value'].queryset = queryset
  144. except Exception:
  145. raise ModelAnswerFormError('You need to provide a model to the ModelAnswerForm')
  146. class PolExpMultipleModelChoiceField(forms.ModelMultipleChoiceField):
  147. def __init__(self, *args, **kwargs):
  148. super(self.__class__, self).__init__(*args, **kwargs)
  149. def label_from_instance(self, obj):
  150. return obj.type
  151. def _get_choices(self):
  152. # If self._choices is set, then somebody must have manually set
  153. # the property self.choices. In this case, just return self._choices.
  154. if hasattr(self, '_choices'):
  155. return self._choices
  156. # Otherwise, execute the QuerySet in self.queryset to determine the
  157. # choices dynamically. Return a fresh QuerySetIterator that has not been
  158. # consumed. Note that we're instantiating a new QuerySetIterator *each*
  159. # time _get_choices() is called (and, thus, each time self.choices is
  160. # accessed) so that we can ensure the QuerySet has not been consumed. This
  161. # construct might look complicated but it allows for lazy evaluation of
  162. # the queryset.
  163. return MyNoPrefModelChoiceIterator(self)
  164. def clean(self, value):
  165. if 'no_pref' in value:
  166. return ['no_pref']
  167. else:
  168. return super(self.__class__, self).clean(value)
  169. choices = property(_get_choices, forms.ChoiceField._set_choices)
  170. class PolTypeQuestionForm(BetterForm, TemplateForm):
  171. value = PolExpMultipleModelChoiceField(label=_('Answer'), queryset=None, widget=widgets.CheckboxSelectMultiple)
  172. class Meta:
  173. fieldsets = (('main', {'fields': ('value',), 'legend': '', 'classes': ('default',)}),)
  174. def __init__(self, queryset=None, empty_label=_('Geen voorkeur'), *args, **kwargs):
  175. super(self.__class__, self).__init__(*args, **kwargs)
  176. try:
  177. self.fields['value'].empty_label = empty_label
  178. self.fields['value'].queryset = queryset
  179. except Exception:
  180. raise ModelAnswerFormError('You need to provide a model to the ModelAnswerForm')
  181. class VisitorAnswerQuestionForm(BetterForm, TemplateForm):
  182. '''
  183. Form which displays possible answers, coupled to the question given (for Vistiors). It makes sure the answer has the
  184. right widget, which depends on the question type.
  185. '''
  186. def __init__(self, question_instance_id, *args, **kwargs):
  187. question_types = dict(QUESTION_TYPE_CHOICES)
  188. question_instance = Question.objects.get(id=question_instance_id)
  189. if not question_instance:
  190. return
  191. if question_instance.question_type in question_types:
  192. choices = map(lambda x: (x.id, x.get_frontoffice_value()), question_instance.answers.all())
  193. if question_instance.has_no_preference:
  194. choices.append(('no_pref', _('Geen voorkeur')))
  195. if QTYPE_NORM_POLMULTICHOICE_VISMULTICHOICE == question_instance.question_type:
  196. self.base_fields.update({'value': forms.MultipleChoiceField(label=_('Answer'), widget=widgets.CheckboxSelectMultiple(choices=choices), choices=choices)})
  197. elif QTYPE_NORM_POLMULTICHOICE_VISMULTICHOICE_MIN_THREE == question_instance.question_type:
  198. myValidators = []
  199. myValidators.append(MinNumAnswersValidator(3))
  200. self.base_fields.update({'value': forms.MultipleChoiceField(label=_('Answer'), widget=widgets.CheckboxSelectMultiple(choices=choices), choices=choices, validators=myValidators)})
  201. elif QTYPE_NORM_POLONECHOICE_VISONECHOICE == question_instance.question_type:
  202. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  203. elif QTYPE_NORM_POLONECHOICE_VISONECHOICE_RANGE == question_instance.question_type:
  204. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  205. elif QTYPE_NORM_POLBOOL_VISBOOL == question_instance.question_type:
  206. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)}) #RadioBoolean() #widgets.NullBooleanSelect()
  207. elif QTYPE_MODEL_POLITICAL_EXPERIENCE_YEARS == question_instance.question_type:
  208. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  209. elif QTYPE_MODEL_PROFILE_RELIGION == question_instance.question_type:
  210. RELIGION_A = copy.deepcopy(RELIGION)
  211. RELIGION_A.append(('no_pref', _('Geen voorkeur')))
  212. self.base_fields.update({'value': forms.MultipleChoiceField(label=_('Answer'), widget=widgets.CheckboxSelectMultiple(choices=RELIGION_A), choices=RELIGION_A)})
  213. elif QTYPE_MODEL_PROFILE_AGE == question_instance.question_type:
  214. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  215. elif QTYPE_MODEL_PROFILE_GENDER == question_instance.question_type:
  216. GENDERS_A = copy.deepcopy(GENDERS)
  217. GENDERS_A.append(('no_pref', _('Geen voorkeur')))
  218. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=GENDERS_A), choices=GENDERS_A)})
  219. elif QTYPE_MODEL_EDUCATION_LEVEL == question_instance.question_type:
  220. self.base_fields.update({'value': forms.ChoiceField(label=_('Answer'), widget=widgets.RadioSelect(choices=choices), choices=choices)})
  221. else:
  222. pass #TODO raise error
  223. else:
  224. pass #TODO raise error
  225. super(VisitorAnswerQuestionForm, self).__init__(*args, **kwargs)
  226. class Meta:
  227. fields = ('value',)