forms.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import re
  2. from django import forms
  3. from django.utils.translation import gettext as _
  4. from .mixins import BootstrapMixin
  5. __all__ = (
  6. 'BulkEditForm',
  7. 'BulkRenameForm',
  8. 'ConfirmationForm',
  9. 'CSVModelForm',
  10. 'FilterForm',
  11. 'TableConfigForm',
  12. )
  13. class ConfirmationForm(BootstrapMixin, forms.Form):
  14. """
  15. A generic confirmation form. The form is not valid unless the `confirm` field is checked.
  16. """
  17. return_url = forms.CharField(
  18. required=False,
  19. widget=forms.HiddenInput()
  20. )
  21. confirm = forms.BooleanField(
  22. required=True,
  23. widget=forms.HiddenInput(),
  24. initial=True
  25. )
  26. class BulkEditForm(BootstrapMixin, forms.Form):
  27. """
  28. Provides bulk edit support for objects.
  29. """
  30. nullable_fields = ()
  31. class BulkRenameForm(BootstrapMixin, forms.Form):
  32. """
  33. An extendable form to be used for renaming objects in bulk.
  34. """
  35. find = forms.CharField(
  36. strip=False
  37. )
  38. replace = forms.CharField(
  39. strip=False,
  40. required=False
  41. )
  42. use_regex = forms.BooleanField(
  43. required=False,
  44. initial=True,
  45. label=_('Use regular expressions')
  46. )
  47. def clean(self):
  48. super().clean()
  49. # Validate regular expression in "find" field
  50. if self.cleaned_data['use_regex']:
  51. try:
  52. re.compile(self.cleaned_data['find'])
  53. except re.error:
  54. raise forms.ValidationError({
  55. 'find': "Invalid regular expression"
  56. })
  57. class CSVModelForm(forms.ModelForm):
  58. """
  59. ModelForm used for the import of objects in CSV format.
  60. """
  61. id = forms.IntegerField(
  62. label=_('ID'),
  63. required=False,
  64. help_text=_('Numeric ID of an existing object to update (if not creating a new object)')
  65. )
  66. def __init__(self, *args, headers=None, **kwargs):
  67. self.headers = headers or {}
  68. super().__init__(*args, **kwargs)
  69. # Modify the model form to accommodate any customized to_field_name properties
  70. for field, to_field in self.headers.items():
  71. if to_field is not None:
  72. self.fields[field].to_field_name = to_field
  73. def clean(self):
  74. # Flag any invalid CSV headers
  75. for header in self.headers:
  76. if header not in self.fields:
  77. raise forms.ValidationError(
  78. _("Unrecognized header: {name}").format(name=header)
  79. )
  80. return super().clean()
  81. class FilterForm(BootstrapMixin, forms.Form):
  82. """
  83. Base Form class for FilterSet forms.
  84. """
  85. q = forms.CharField(
  86. required=False,
  87. label=_('Search')
  88. )
  89. class TableConfigForm(BootstrapMixin, forms.Form):
  90. """
  91. Form for configuring user's table preferences.
  92. """
  93. available_columns = forms.MultipleChoiceField(
  94. choices=[],
  95. required=False,
  96. widget=forms.SelectMultiple(
  97. attrs={'size': 10, 'class': 'form-select'}
  98. ),
  99. label=_('Available Columns')
  100. )
  101. columns = forms.MultipleChoiceField(
  102. choices=[],
  103. required=False,
  104. widget=forms.SelectMultiple(
  105. attrs={'size': 10, 'class': 'form-select'}
  106. ),
  107. label=_('Selected Columns')
  108. )
  109. def __init__(self, table, *args, **kwargs):
  110. self.table = table
  111. super().__init__(*args, **kwargs)
  112. # Initialize columns field based on table attributes
  113. self.fields['available_columns'].choices = table.available_columns
  114. self.fields['columns'].choices = table.selected_columns
  115. @property
  116. def table_name(self):
  117. return self.table.__class__.__name__