forms.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. from django.utils.translation import ugettext as _
  2. from django.utils.translation import ungettext
  3. from misago.core import forms
  4. __ALL__ = ['ChangeSettingsForm']
  5. class ValidateChoicesNum(object):
  6. def __init__(self, min_choices=0, max_choices=0):
  7. self.min_choices = min_choices
  8. self.max_choices = max_choices
  9. def __call__(self, data):
  10. data_len = len(data)
  11. if self.min_choices and self.min_choices > data_len:
  12. message = ungettext(
  13. 'You have to select at least %(choices)d option.',
  14. 'You have to select at least %(choices)d options.',
  15. self.min_choices)
  16. message = message % {'choices': self.min_choices}
  17. raise forms.ValidationError(message)
  18. if self.max_choices and self.max_choices < data_len:
  19. message = ungettext(
  20. 'You cannot select more than %(choices)d option.',
  21. 'You cannot select more than %(choices)d options.',
  22. self.max_choices)
  23. message = message % {'choices': self.max_choices}
  24. raise forms.ValidationError(message)
  25. return data
  26. def basic_kwargs(setting, extra):
  27. kwargs = {
  28. 'label': _(setting.name),
  29. 'initial': setting.value,
  30. 'required': extra.get('min_length') or extra.get('min'),
  31. }
  32. if setting.description:
  33. kwargs['help_text'] = _(setting.description)
  34. if setting.form_field == 'yesno':
  35. # YesNoSwitch is int-base and setting is bool based
  36. # this means we need to do quick conversion
  37. kwargs['initial'] = 1 if kwargs['initial'] else 0
  38. if kwargs['required']:
  39. if kwargs.get('help_text'):
  40. format = {'help_text': kwargs['help_text']}
  41. kwargs['help_text'] = _('Required. %(help_text)s') % format
  42. else:
  43. kwargs['help_text'] = _('This field is required.')
  44. return kwargs
  45. def localise_choices(extra):
  46. return [(v, _(l)) for v, l in extra.get('choices', [])]
  47. def create_checkbox(setting, kwargs, extra):
  48. kwargs['widget'] = forms.CheckboxSelectMultiple()
  49. kwargs['choices'] = localise_choices(extra)
  50. if extra.get('min') or extra.get('max'):
  51. kwargs['validators'] = [
  52. ValidateChoicesNum(extra.pop('min', 0), extra.pop('max', 0))
  53. ]
  54. if setting.python_type == 'int':
  55. return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
  56. else:
  57. return forms.MultipleChoiceField(**kwargs)
  58. def create_choice(setting, kwargs, extra):
  59. if setting.form_field == 'choice':
  60. kwargs['widget'] = forms.RadioSelect()
  61. else:
  62. kwargs['widget'] = forms.Select()
  63. kwargs['choices'] = localise_choices(extra)
  64. if setting.python_type == 'int':
  65. return forms.TypedChoiceField(coerce='int', **kwargs)
  66. else:
  67. return forms.ChoiceField(**kwargs)
  68. def create_text(setting, kwargs, extra):
  69. kwargs.update(extra)
  70. if setting.python_type == 'int':
  71. return forms.IntegerField(**kwargs)
  72. else:
  73. return forms.CharField(**kwargs)
  74. def create_textarea(setting, kwargs, extra):
  75. widget_kwargs = {}
  76. if extra.get('min_length', 0) == 0:
  77. kwargs['required'] = False
  78. if extra.get('rows', 0):
  79. widget_kwargs['attrs'] = {'rows': extra.pop('rows')}
  80. kwargs['widget'] = forms.Textarea(**widget_kwargs)
  81. return forms.CharField(**kwargs)
  82. def create_yesno(setting, kwargs, extra):
  83. return forms.YesNoSwitch(**kwargs)
  84. FIELD_STYPES = {
  85. 'checkbox': create_checkbox,
  86. 'radio': create_choice,
  87. 'select': create_choice,
  88. 'text': create_text,
  89. 'textarea': create_textarea,
  90. 'yesno': create_yesno,
  91. }
  92. def setting_field(FormType, setting):
  93. field_factory = FIELD_STYPES[setting.form_field]
  94. field_extra = setting.field_extra
  95. form_field = field_factory(
  96. setting, basic_kwargs(setting, field_extra), field_extra)
  97. FormType = type('FormType%s' % setting.pk, (FormType,), {
  98. setting.setting: form_field
  99. })
  100. return FormType
  101. def ChangeSettingsForm(data=None, group=None):
  102. """
  103. Factory method that builds valid form for settings group
  104. """
  105. class FormType(forms.Form):
  106. pass
  107. fieldsets = []
  108. fieldset_legend = None
  109. fieldset_form = FormType
  110. fieldset_fields = False
  111. for setting in group.setting_set.order_by('order'):
  112. if setting.legend and setting.legend != fieldset_legend:
  113. if fieldset_fields:
  114. fieldsets.append({
  115. 'legend': fieldset_legend,
  116. 'form': fieldset_form(data)
  117. })
  118. fieldset_legend = setting.legend
  119. fieldset_form = FormType
  120. fieldset_fields = False
  121. fieldset_fields = True
  122. fieldset_form = setting_field(fieldset_form, setting)
  123. if fieldset_fields:
  124. fieldsets.append({
  125. 'legend': fieldset_legend,
  126. 'form': fieldset_form(data)
  127. })
  128. return fieldsets