forms.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. from django import forms
  2. from django.utils.translation import gettext as _
  3. from django.utils.translation import ngettext
  4. from ..admin.forms import YesNoSwitch
  5. __all__ = ["ChangeSettingsForm"]
  6. class ValidateChoicesNum:
  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 = ngettext(
  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 = ngettext(
  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. help_text = {"help_text": kwargs["help_text"]}
  42. kwargs["help_text"] = _("Required. %(help_text)s") % help_text
  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. 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. 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. 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 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, basic_kwargs(setting, field_extra), field_extra)
  94. FormType = type(
  95. "FormType%s" % setting.pk, (FormType,), {setting.setting: form_field}
  96. )
  97. return FormType
  98. def ChangeSettingsForm(data=None, group=None):
  99. """factory method that builds valid form for settings group"""
  100. class FormType(forms.Form):
  101. pass
  102. fieldsets = []
  103. fieldset_legend = None
  104. fieldset_form = FormType
  105. fieldset_fields = False
  106. for setting in group.setting_set.order_by("order"):
  107. if setting.legend and setting.legend != fieldset_legend:
  108. if fieldset_fields:
  109. fieldsets.append(
  110. {"legend": fieldset_legend, "form": fieldset_form(data)}
  111. )
  112. fieldset_legend = setting.legend
  113. fieldset_form = FormType
  114. fieldset_fields = False
  115. fieldset_fields = True
  116. fieldset_form = setting_field(fieldset_form, setting)
  117. if fieldset_fields:
  118. fieldsets.append({"legend": fieldset_legend, "form": fieldset_form(data)})
  119. return fieldsets