forms.py 4.8 KB

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