forms.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. from django import forms
  2. from django.utils.translation import ugettext as _
  3. from django.utils.translation import ungettext
  4. from misago.core.forms import YesNoSwitch
  5. __ALL__ = ['ChangeSettingsForm']
  6. class ValidateChoicesNum(object):
  7. def __init__(self, min_choices=0, max_choices=0):
  8. self.min_choices = min_choices
  9. self.max_choices = max_choices
  10. def __call__(self, data):
  11. data_len = len(data)
  12. if self.min_choices and self.min_choices > data_len:
  13. message = ungettext(
  14. 'You have to select at least %(choices)d option.',
  15. 'You have to select at least %(choices)d options.', self.min_choices
  16. )
  17. raise forms.ValidationError(message % {'choices': self.min_choices})
  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.', self.max_choices
  22. )
  23. raise forms.ValidationError(message % {'choices': self.max_choices})
  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 localise_choices(extra):
  45. return [(v, _(l)) for v, l in extra.get('choices', [])]
  46. def create_checkbox(setting, kwargs, extra):
  47. kwargs['widget'] = forms.CheckboxSelectMultiple()
  48. kwargs['choices'] = localise_choices(extra)
  49. if extra.get('min') or extra.get('max'):
  50. kwargs['validators'] = [ValidateChoicesNum(extra.pop('min', 0), extra.pop('max', 0))]
  51. if setting.python_type == 'int':
  52. return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
  53. else:
  54. return forms.MultipleChoiceField(**kwargs)
  55. def create_choice(setting, kwargs, extra):
  56. if setting.form_field == 'choice':
  57. kwargs['widget'] = forms.RadioSelect()
  58. else:
  59. kwargs['widget'] = forms.Select()
  60. kwargs['choices'] = localise_choices(extra)
  61. if setting.python_type == 'int':
  62. return forms.TypedChoiceField(coerce='int', **kwargs)
  63. else:
  64. return forms.ChoiceField(**kwargs)
  65. def create_text(setting, kwargs, extra):
  66. kwargs.update(extra)
  67. if setting.python_type == 'int':
  68. return forms.IntegerField(**kwargs)
  69. else:
  70. return forms.CharField(**kwargs)
  71. def create_textarea(setting, kwargs, extra):
  72. widget_kwargs = {}
  73. if extra.get('min_length', 0) == 0:
  74. kwargs['required'] = False
  75. if extra.get('rows', 0):
  76. widget_kwargs['attrs'] = {'rows': extra.pop('rows')}
  77. kwargs['widget'] = forms.Textarea(**widget_kwargs)
  78. return forms.CharField(**kwargs)
  79. def create_yesno(setting, kwargs, extra):
  80. return YesNoSwitch(**kwargs)
  81. FIELD_STYPES = {
  82. 'checkbox': create_checkbox,
  83. 'radio': create_choice,
  84. 'select': create_choice,
  85. 'text': create_text,
  86. 'textarea': create_textarea,
  87. 'yesno': create_yesno,
  88. }
  89. def setting_field(FormType, setting):
  90. field_factory = FIELD_STYPES[setting.form_field]
  91. field_extra = setting.field_extra
  92. form_field = field_factory(setting, basic_kwargs(setting, field_extra), field_extra)
  93. FormType = type('FormType%s' % setting.pk, (FormType, ), {setting.setting: form_field})
  94. return FormType
  95. def ChangeSettingsForm(data=None, group=None):
  96. """
  97. Factory method that builds valid form for settings group
  98. """
  99. class FormType(forms.Form):
  100. pass
  101. fieldsets = []
  102. fieldset_legend = None
  103. fieldset_form = FormType
  104. fieldset_fields = False
  105. for setting in group.setting_set.order_by('order'):
  106. if setting.legend and setting.legend != fieldset_legend:
  107. if fieldset_fields:
  108. fieldsets.append({'legend': fieldset_legend, 'form': fieldset_form(data)})
  109. fieldset_legend = setting.legend
  110. fieldset_form = FormType
  111. fieldset_fields = False
  112. fieldset_fields = True
  113. fieldset_form = setting_field(fieldset_form, setting)
  114. if fieldset_fields:
  115. fieldsets.append({'legend': fieldset_legend, 'form': fieldset_form(data)})
  116. return fieldsets