Add NamedMultiWidget class

Works as Django's MultiWidget but instead of a list
of subwidgets, uses a dictionary of subwidgets with names
as the keys. The named nature is less error prone than Django's
index numbered subwidgets.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-08-21 03:52:07 -04:00
parent c51f8d2135
commit e002f317a4

View File

@@ -1,5 +1,7 @@
from __future__ import unicode_literals
from collections import OrderedDict
from django import forms
from django.utils.safestring import mark_safe
@@ -20,6 +22,86 @@ class DisableableSelectWidget(forms.widgets.SelectMultiple):
return result
class NamedMultiWidget(forms.widgets.Widget):
template_name = 'django/forms/widgets/multiwidget.html'
def __init__(self, widgets, attrs=None):
self.widgets = OrderedDict()
for name, widget in widgets.items():
self.widgets[name] = widget() if isinstance(widget, type) else widget
super(NamedMultiWidget, self).__init__(attrs)
def _get_media(self):
"Media for a multiwidget is the combination of all media of the subwidgets"
media = forms.widgets.Media()
for name, widget in self.widgets.items():
media = media + widget.media
return media
media = property(_get_media)
@property
def is_hidden(self):
return all(widget.is_hidden for name, widget in self.widgets.items())
def get_context(self, name, value, attrs):
context = super(NamedMultiWidget, self).get_context(name, value, attrs)
if self.is_localized:
for widget in self.widgets:
widget.is_localized = self.is_localized
value = self.decompress(value)
final_attrs = context['widget']['attrs']
input_type = final_attrs.pop('type', None)
id_ = final_attrs.get('id')
subwidgets = []
for widget_name, widget in self.widgets.items():
if input_type is not None:
widget.input_type = input_type
full_widget_name = '%s_%s' % (name, widget_name)
try:
widget_value = value[widget_name]
except IndexError:
widget_value = None
if id_:
widget_attrs = final_attrs.copy()
widget_attrs['id'] = '%s_%s' % (id_, widget_name)
else:
widget_attrs = final_attrs
subwidgets.append(
widget.get_context(
full_widget_name, widget_value, widget_attrs
)['widget']
)
context['widget']['subwidgets'] = subwidgets
return context
def id_for_label(self, id_):
if id_:
id_ += '_{}'.format(self.widgets.keys()[0])
return id_
def value_from_datadict(self, data, files, name):
return {
name: widget.value_from_datadict(
data, files, name + '_%s' % name
) for name, widget in self.widgets.items()
}
def value_omitted_from_data(self, data, files, name):
return all(
widget.value_omitted_from_data(data, files, name + '_%s' % name)
for name, widget in self.widgets.items()
)
@property
def needs_multipart_form(self):
return any(
widget.needs_multipart_form for name, widget in self.widgets.items()
)
class PlainWidget(forms.widgets.Widget):
"""
Class to define a form widget that effectively nulls the htmls of a