forms.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. message = message % {'choices': self.min_choices}
  18. raise forms.ValidationError(message)
  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. message = message % {'choices': self.max_choices}
  25. raise forms.ValidationError(message)
  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'] = [
  53. ValidateChoicesNum(extra.pop('min', 0), extra.pop('max', 0))
  54. ]
  55. if setting.python_type == 'int':
  56. return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
  57. else:
  58. return forms.MultipleChoiceField(**kwargs)
  59. def create_choice(setting, kwargs, extra):
  60. if setting.form_field == 'choice':
  61. kwargs['widget'] = forms.RadioSelect()
  62. else:
  63. kwargs['widget'] = forms.Select()
  64. kwargs['choices'] = localise_choices(extra)
  65. if setting.python_type == 'int':
  66. return forms.TypedChoiceField(coerce='int', **kwargs)
  67. else:
  68. return forms.ChoiceField(**kwargs)
  69. def create_text(setting, kwargs, extra):
  70. kwargs.update(extra)
  71. if setting.python_type == 'int':
  72. return forms.IntegerField(**kwargs)
  73. else:
  74. return forms.CharField(**kwargs)
  75. def create_textarea(setting, kwargs, extra):
  76. widget_kwargs = {}
  77. if extra.get('min_length', 0) == 0:
  78. kwargs['required'] = False
  79. if extra.get('rows', 0):
  80. widget_kwargs['attrs'] = {'rows': extra.pop('rows')}
  81. kwargs['widget'] = forms.Textarea(**widget_kwargs)
  82. return forms.CharField(**kwargs)
  83. def create_yesno(setting, kwargs, extra):
  84. return YesNoSwitch(**kwargs)
  85. FIELD_STYPES = {
  86. 'checkbox': create_checkbox,
  87. 'radio': create_choice,
  88. 'select': create_choice,
  89. 'text': create_text,
  90. 'textarea': create_textarea,
  91. 'yesno': create_yesno,
  92. }
  93. def setting_field(FormType, setting):
  94. field_factory = FIELD_STYPES[setting.form_field]
  95. field_extra = setting.field_extra
  96. form_field = field_factory(
  97. setting, basic_kwargs(setting, field_extra), field_extra)
  98. FormType = type('FormType%s' % setting.pk, (FormType,), {
  99. setting.setting: form_field
  100. })
  101. return FormType
  102. def ChangeSettingsForm(data=None, group=None):
  103. """
  104. Factory method that builds valid form for settings group
  105. """
  106. class FormType(forms.Form):
  107. pass
  108. fieldsets = []
  109. fieldset_legend = None
  110. fieldset_form = FormType
  111. fieldset_fields = False
  112. for setting in group.setting_set.order_by('order'):
  113. if setting.legend and setting.legend != fieldset_legend:
  114. if fieldset_fields:
  115. fieldsets.append({
  116. 'legend': fieldset_legend,
  117. 'form': fieldset_form(data)
  118. })
  119. fieldset_legend = setting.legend
  120. fieldset_form = FormType
  121. fieldset_fields = False
  122. fieldset_fields = True
  123. fieldset_form = setting_field(fieldset_form, setting)
  124. if fieldset_fields:
  125. fieldsets.append({
  126. 'legend': fieldset_legend,
  127. 'form': fieldset_form(data)
  128. })
  129. return fieldsets