forms.py 4.9 KB

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