forms.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. from __future__ import unicode_literals
  2. from future.builtins import int
  3. from collections import defaultdict
  4. from django import forms
  5. from django.utils.safestring import mark_safe
  6. from django.utils.translation import activate, get_language, ugettext_lazy as _
  7. from django.template.defaultfilters import urlize
  8. from mezzanine.conf import settings, registry
  9. from mezzanine.conf.models import Setting
  10. if settings.USE_MODELTRANSLATION:
  11. from collections import OrderedDict
  12. from modeltranslation.utils import build_localized_fieldname
  13. FIELD_TYPES = {
  14. bool: forms.BooleanField,
  15. int: forms.IntegerField,
  16. float: forms.FloatField,
  17. }
  18. class SettingsForm(forms.Form):
  19. """
  20. Form for settings - creates a field for each setting in
  21. ``mezzanine.conf`` that is marked as editable.
  22. """
  23. def __init__(self, *args, **kwargs):
  24. super(SettingsForm, self).__init__(*args, **kwargs)
  25. # Create a form field for each editable setting's from its type.
  26. active_language = get_language()
  27. for name in sorted(registry.keys()):
  28. setting = registry[name]
  29. if setting["editable"]:
  30. field_class = FIELD_TYPES.get(setting["type"], forms.CharField)
  31. if settings.USE_MODELTRANSLATION and setting["translatable"]:
  32. for code in OrderedDict(settings.LANGUAGES):
  33. try:
  34. activate(code)
  35. except:
  36. pass
  37. else:
  38. self._init_field(setting, field_class, name, code)
  39. else:
  40. self._init_field(setting, field_class, name)
  41. activate(active_language)
  42. def _init_field(self, setting, field_class, name, code=None):
  43. """
  44. Initialize a field whether it is built with a custom name for a
  45. specific translation language or not.
  46. """
  47. kwargs = {
  48. "label": setting["label"] + ":",
  49. "required": setting["type"] in (int, float),
  50. "initial": getattr(settings, name),
  51. "help_text": self.format_help(setting["description"]),
  52. }
  53. if setting["choices"]:
  54. field_class = forms.ChoiceField
  55. kwargs["choices"] = setting["choices"]
  56. field_instance = field_class(**kwargs)
  57. code_name = ('_modeltranslation_' + code if code else '')
  58. self.fields[name + code_name] = field_instance
  59. css_class = field_class.__name__.lower()
  60. field_instance.widget.attrs["class"] = css_class
  61. if code:
  62. field_instance.widget.attrs["class"] += " modeltranslation"
  63. def __iter__(self):
  64. """
  65. Calculate and apply a group heading to each field and order by
  66. the heading.
  67. """
  68. fields = list(super(SettingsForm, self).__iter__())
  69. group = lambda field: field.name.split("_", 1)[0].title()
  70. misc = _("Miscellaneous")
  71. groups = defaultdict(int)
  72. for field in fields:
  73. groups[group(field)] += 1
  74. for (i, field) in enumerate(fields):
  75. setattr(fields[i], "group", group(field))
  76. if groups[fields[i].group] == 1:
  77. fields[i].group = misc
  78. return iter(sorted(fields, key=lambda x: (x.group == misc, x.group)))
  79. def save(self):
  80. """
  81. Save each of the settings to the DB.
  82. """
  83. active_language = get_language()
  84. for (name, value) in self.cleaned_data.items():
  85. if name not in registry:
  86. name, code = name.rsplit('_modeltranslation_', 1)
  87. else:
  88. code = None
  89. setting_obj, created = Setting.objects.get_or_create(name=name)
  90. if settings.USE_MODELTRANSLATION:
  91. if registry[name]["translatable"]:
  92. try:
  93. activate(code)
  94. except:
  95. pass
  96. finally:
  97. setting_obj.value = value
  98. activate(active_language)
  99. else:
  100. # Duplicate the value of the setting for every language
  101. for code in OrderedDict(settings.LANGUAGES):
  102. setattr(setting_obj,
  103. build_localized_fieldname('value', code),
  104. value)
  105. else:
  106. setting_obj.value = value
  107. setting_obj.save()
  108. def format_help(self, description):
  109. """
  110. Format the setting's description into HTML.
  111. """
  112. for bold in ("``", "*"):
  113. parts = []
  114. if description is None:
  115. description = ""
  116. for i, s in enumerate(description.split(bold)):
  117. parts.append(s if i % 2 == 0 else "<b>%s</b>" % s)
  118. description = "".join(parts)
  119. description = urlize(description, autoescape=False)
  120. return mark_safe(description.replace("\n", "<br>"))