fix Bytes submission pb on POST, due to multiple call to field.process_form_value
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 26 Jan 2010 10:34:29 +0100
changeset 4359 fabc680bb0bf
parent 4358 9a902670e4ff
child 4360 5fdb9da1fab0
fix Bytes submission pb on POST, due to multiple call to field.process_form_value for a same field. In the case of file, stream.read() doesn't return file's data the second time (since the cursor is at the end of the file). Fix this by having a generic process_form_value method that cache field's value in form.formvalues[field] and so _process_form_value is only called once. You should then override that later method on custom fields.
web/formfields.py
web/views/editcontroller.py
--- a/web/formfields.py	Tue Jan 26 10:30:57 2010 +0100
+++ b/web/formfields.py	Tue Jan 26 10:34:29 2010 +0100
@@ -337,6 +337,13 @@
 
     def process_form_value(self, form):
         """process posted form and return correctly typed value"""
+        try:
+            return form.formvalues[self]
+        except KeyError:
+            value = form.formvalues[self] = self._process_form_value(form)
+            return value
+
+    def _process_form_value(self, form):
         widget = self.get_widget(form)
         return widget.process_field_data(form, self)
 
@@ -533,7 +540,7 @@
                 + renderer.render_help(form, field)
                 + u'<br/>')
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         posted = form._cw.form
         if self.input_name(form, u'__detach') in posted:
             # drop current file value on explictily asked to detach
@@ -585,12 +592,12 @@
                     # XXX restore form context?
         return '\n'.join(wdgs)
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         value = form._cw.form.get(self.input_name(form))
         if isinstance(value, unicode):
             # file modified using a text widget
             return Binary(value.encode(self.encoding(form)))
-        return super(EditableFileField, self).process_form_value(form)
+        return super(EditableFileField, self)._process_form_value(form)
 
 
 class IntField(Field):
@@ -602,8 +609,8 @@
             self.widget.attrs.setdefault('size', 5)
             self.widget.attrs.setdefault('maxlength', 15)
 
-    def process_form_value(self, form):
-        value = Field.process_form_value(self, form)
+    def _process_form_value(self, form):
+        value = Field._process_form_value(self, form)
         if value:
             try:
                 return int(value)
@@ -620,8 +627,8 @@
             return super(BooleanField, self).vocabulary(form)
         return [(form._cw._('yes'), '1'), (form._cw._('no'), '')]
 
-    def process_form_value(self, form):
-        return bool(Field.process_form_value(self, form))
+    def _process_form_value(self, form):
+        return bool(Field._process_form_value(self, form))
 
 
 class FloatField(IntField):
@@ -634,8 +641,8 @@
     def render_example(self, req):
         return self.format_single_value(req, 1.234)
 
-    def process_form_value(self, form):
-        value = Field.process_form_value(self, form)
+    def _process_form_value(self, form):
+        value = Field._process_form_value(self, form)
         if value:
             try:
                 return float(value)
@@ -654,9 +661,9 @@
     def render_example(self, req):
         return self.format_single_value(req, datetime.now())
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         # widget is supposed to return a date as a correctly formatted string
-        date = Field.process_form_value(self, form)
+        date = Field._process_form_value(self, form)
         # but for some widgets, it might be simpler to return date objects
         # directly, so handle that case :
         if isinstance(date, basestring):
@@ -670,9 +677,9 @@
 class DateTimeField(DateField):
     format_prop = 'ui.datetime-format'
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         # widget is supposed to return a date as a correctly formatted string
-        date = Field.process_form_value(self, form)
+        date = Field._process_form_value(self, form)
         # but for some widgets, it might be simpler to return date objects
         # directly, so handle that case :
         if isinstance(date, basestring):
@@ -687,9 +694,9 @@
     format_prop = 'ui.time-format'
     widget = TextInput
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         # widget is supposed to return a date as a correctly formatted string
-        time = Field.process_form_value(self, form)
+        time = Field._process_form_value(self, form)
         # but for some widgets, it might be simpler to return time objects
         # directly, so handle that case :
         if isinstance(time, basestring):
@@ -801,7 +808,7 @@
     def format_single_value(self, req, value):
         return value
 
-    def process_form_value(self, form):
+    def _process_form_value(self, form):
         """process posted form and return correctly typed value"""
         widget = self.get_widget(form)
         values = widget.process_field_data(form, self)
--- a/web/views/editcontroller.py	Tue Jan 26 10:30:57 2010 +0100
+++ b/web/views/editcontroller.py	Tue Jan 26 10:34:29 2010 +0100
@@ -145,6 +145,7 @@
         formid = self._cw.form.get('__form_id', 'edition')
         form = self._cw.vreg['forms'].select(formid, self._cw, entity=entity)
         eid = form.actual_eid(entity.eid)
+        form.formvalues = {} # init fields value cache
         try:
             editedfields = formparams['_cw_edited_fields']
         except KeyError: