Commits

Gunnlaugur Þór Briem committed 16fcfb5

Made ManyToManyField properly supported (submitting a form with ReadOnlyWidget for a ManyToManyField was borking with an error because the form data was expected to be list-valued. Inheriting from MultiHiddenInput instead of HiddenInput turned out to work fine. So I split out the ManyToManyField support into a separate class inheriting from MultiHiddenInput, and had them both inherit the common stuff from ReadOnlyWidgetMixin. Works fine for my ManyToManyField case, haven't tested with the others (but I *think* this does not change behavior in those cases).

Also made ReadOnlyWidgetMixin support subclasses adding their own support more flexibly, and used that to make ReadOnlyWidgetMulti support subclasses of ManyToManyField.

Comments (0)

Files changed (1)

django_readonlywidget/widgets.py

 from django.utils.translation import ugettext as _
 from django.utils.html import escape, conditional_escape
 from django.contrib.admin.templatetags.admin_list import _boolean_icon
+from django.db.models.fields.related import ManyToManyField
 
-class ReadOnlyWidget(forms.HiddenInput):
+class ReadOnlyWidgetMixin(object):
     def __init__(self, db_field, *args, **kwargs):
         self.db_field = db_field
-        super(ReadOnlyWidget, self).__init__()
+        super(ReadOnlyWidgetMixin, self).__init__()
 
     def render(self, *args, **kwargs):
         field_name, value = args
         field_type = self.db_field.__class__.__name__
-        field_value = super(ReadOnlyWidget, self).render(*args, **kwargs)
+        field_value = super(ReadOnlyWidgetMixin, self).render(*args, **kwargs)
         output = value
 
-        if hasattr(self, 'get_%s_value' % field_type.lower()):
+        treat_as_field_type = self.treat_as(field_type)
+        if hasattr(self, 'get_%s_value' % treat_as_field_type.lower()):
             try:
-                func = getattr(self, 'get_%s_value' % field_type.lower())
+                func = getattr(self, 'get_%s_value' % treat_as_field_type.lower())
                 output = func(field_name, value)
             except Exception,e:
                 output = e
         else:
-            raise AttributeError('%s is not supported by ReadOnlyWidget.' % field_type)
+            raise AttributeError('%s is not supported by %s.' % (field_type, type(self).__name__))
 
         return self.render_output(field_name, field_value, output)
 
+    def treat_as(self, field_type):
+        return field_type
+
     def render_output(self, field_name, field_value, output):
         return mark_safe('%s %s' % (output, field_value))
 
+class ReadOnlyWidget(ReadOnlyWidgetMixin, forms.HiddenInput):
     def get_textfield_value(self, field_name, value):
         return '<p style="clear:both;">%s</p>' % value
 
         except:
             return ''
 
-    def get_manytomanyfield_value(self, field_name, value):
-        output = ['<ul class="m2m_list_%s">' % field_name,]
-        for id in value:
-            output.append('<li>%s</li>' % unicode(self.db_field.rel.to.objects.get(pk=id)))
-        output.append('</ul>')
-
-        return ''.join(output)
-
     def get_datetimefield_value(self, field_name, value):
         if value:
             return value.strftime('%x %X')
             return value.strftime('%x')
         else:
             return ''
+
+class ReadOnlyMultiWidget(ReadOnlyWidgetMixin, forms.MultipleHiddenInput):
+
+    def treat_as(self, field_type):
+        if isinstance(field_type, ManyToManyField) and not hasattr(self, 'get_%s_value' % field_type.lower()):
+            return ManyToManyField
+        else:
+            return field_type
+
+    def get_manytomanyfield_value(self, field_name, value):
+        output = ['<ul class="m2m_list_%s">' % field_name,]
+        for id in value:
+            output.append('<li>%s</li>' % unicode(self.db_field.rel.to.objects.get(pk=id)))
+        output.append('</ul>')
+
+        return ''.join(output)