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.

  • Participants
  • Parent commits d4e3d76

Comments (0)

Files changed (1)

File 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)