web/views/forms.py
changeset 4159 6b2b20c73d59
parent 4156 1bbb0ee42c8e
child 4161 4273f5094651
--- a/web/views/forms.py	Mon Dec 21 19:25:07 2009 +0100
+++ b/web/views/forms.py	Mon Dec 21 19:45:24 2009 +0100
@@ -12,6 +12,7 @@
 from logilab.common.compat import any
 from logilab.common.deprecation import deprecated
 
+from cubicweb import typed_eid
 from cubicweb.selectors import non_final_entity, match_kwargs, one_line_rset
 from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param
 from cubicweb.web import form, formwidgets as fwdgs
@@ -113,7 +114,7 @@
     def form_add_hidden(self, name, value=None, **kwargs):
         """add an hidden field to the form"""
         kwargs.setdefault('widget', fwdgs.HiddenInput)
-        field = StringField(name=name, initial=value, **kwargs)
+        field = StringField(name=name, value=value, **kwargs)
         if 'id' in kwargs:
             # by default, hidden input don't set id attribute. If one is
             # explicitly specified, ensure it will be set
@@ -142,77 +143,21 @@
                                                      self._cw, rset=self.cw_rset,
                                                      row=self.cw_row, col=self.cw_col)
 
-    def build_context(self, rendervalues=None):
+    formvalues = None
+    def build_context(self, formvalues=None):
         """build form context values (the .context attribute which is a
         dictionary with field instance as key associated to a dictionary
         containing field 'name' (qualified), 'id', 'value' (for display, always
         a string).
-
-        rendervalues is an optional dictionary containing extra form values
-        given to render()
         """
-        if self.context is not None:
+        if self.formvalues is not None:
             return # already built
-        self.context = context = {}
-        # ensure rendervalues is a dict
-        if rendervalues is None:
-            rendervalues = {}
+        self.formvalues = formvalues or {}
         # use a copy in case fields are modified while context is build (eg
         # __linkto handling for instance)
         for field in self.fields[:]:
             for field in field.actual_fields(self):
                 field.form_init(self)
-                value = self.form_field_display_value(field, rendervalues)
-                context[field] = {'value': value,
-                                  'name': self.form_field_name(field),
-                                  'id': self.form_field_id(field),
-                                  }
-
-    def form_field_display_value(self, field, rendervalues, load_bytes=False):
-        """return field's *string* value to use for display
-
-        looks in
-        1. previously submitted form values if any (eg on validation error)
-        2. req.form
-        3. extra kw args given to render_form
-        4. field's typed value
-
-        values found in 1. and 2. are expected te be already some 'display'
-        value while those found in 3. and 4. are expected to be correctly typed.
-        """
-        value = self._req_display_value(field)
-        if value is None:
-            if field.name in rendervalues:
-                value = rendervalues[field.name]
-            elif field.name in self.cw_extra_kwargs:
-                value = self.cw_extra_kwargs[field.name]
-            else:
-                value = self.form_field_value(field, load_bytes)
-                if callable(value):
-                    value = value(self)
-            if value != INTERNAL_FIELD_VALUE:
-                value = field.format_value(self._cw, value)
-        return value
-
-    def _req_display_value(self, field):
-        qname = self.form_field_name(field)
-        if qname in self.form_previous_values:
-            return self.form_previous_values[qname]
-        if qname in self._cw.form:
-            return self._cw.form[qname]
-        if field.name in self._cw.form:
-            return self._cw.form[field.name]
-        return None
-
-    def form_field_value(self, field, load_bytes=False):
-        """return field's *typed* value"""
-        myattr = '%s_%s_default' % (field.role, field.name)
-        if hasattr(self, myattr):
-            return getattr(self, myattr)()
-        value = field.initial
-        if callable(value):
-            value = value(self)
-        return value
 
     def form_field_error(self, field):
         """return validation error for widget's field, if any"""
@@ -297,6 +242,15 @@
                 return '%s#%s' % (self.edited_entity.absolute_url(), self.domid)
             return '%s#%s' % (self.req.url(), self.domid)
 
+    def build_context(self, formvalues=None):
+        super(EntityFieldsForm, self).build_context(formvalues)
+        edited = set()
+        for field in self.fields:
+            if field.eidparam:
+                edited.add(field.role_name())
+        self.add_hidden('_cw_edited_fields', u','.join(edited),
+                        eidparam=True)
+
     def _field_has_error(self, field):
         """return true if the field has some error in given validation exception
         """
@@ -353,43 +307,7 @@
             self.form_renderer_id, self._cw, rset=self.cw_rset, row=self.cw_row,
             col=self.cw_col, entity=self.edited_entity)
 
-    def form_field_value(self, field, load_bytes=False):
-        """return field's *typed* value
 
-        overriden to deal with
-        * special eid / __type
-        * lookup for values on edited entities
-        """
-        attr = field.name
-        entity = self.edited_entity
-        if attr == 'eid':
-            return entity.eid
-        if not field.eidparam:
-            return super(EntityFieldsForm, self).form_field_value(field, load_bytes)
-        if attr == '__type':
-            return entity.__regid__
-        if self._cw.vreg.schema.rschema(attr).final:
-            attrtype = entity.e_schema.destination(attr)
-            if attrtype == 'Password':
-                return entity.has_eid() and INTERNAL_FIELD_VALUE or ''
-            if attrtype == 'Bytes':
-                if entity.has_eid():
-                    if load_bytes:
-                        return getattr(entity, attr)
-                    # XXX value should reflect if some file is already attached
-                    return True
-                return False
-            if entity.has_eid() or attr in entity:
-                value = getattr(entity, attr)
-            else:
-                value = self._form_field_default_value(field, load_bytes)
-            return value
-        # non final relation field
-        if entity.has_eid() or entity.relation_cached(attr, field.role):
-            value = [r[0] for r in entity.related(attr, field.role)]
-        else:
-            value = self._form_field_default_value(field, load_bytes)
-        return value
 
     def form_field_format(self, field):
         """return MIME type used for the given (text or bytes) field"""
@@ -406,28 +324,21 @@
             entity.has_eid() or '%s_encoding' % field.name in entity):
             return self.edited_entity.attr_metadata(field.name, 'encoding')
         return super(EntityFieldsForm, self).form_field_encoding(field)
-
-    def form_field_name(self, field):
-        """return qualified name for the given field"""
-        if field.eidparam:
-            return eid_param(field.name, self.edited_entity.eid)
-        return field.name
-
-    def form_field_id(self, field):
-        """return dom id for the given field"""
-        if field.eidparam:
-            return eid_param(field.id, self.edited_entity.eid)
-        return field.id
-
     # XXX all this vocabulary handling should be on the field, no?
 
     def form_field_vocabulary(self, field, limit=None):
         """return vocabulary for the given field"""
         role, rtype = field.role, field.name
         method = '%s_%s_vocabulary' % (role, rtype)
+    def actual_eid(self, eid):
+        # should be either an int (existant entity) or a variable (to be
+        # created entity)
+        assert eid or eid == 0, repr(eid) # 0 is a valid eid
         try:
             vocabfunc = getattr(self, method)
         except AttributeError:
+            return typed_eid(eid)
+        except ValueError:
             try:
                 # XXX bw compat, <role>_<rtype>_vocabulary on the entity
                 vocabfunc = getattr(self.edited_entity, method)
@@ -511,6 +422,10 @@
             if limit is not None and len(result) >= limit:
                 break
         return result
+                return self._cw.data['eidmap'][eid]
+            except KeyError:
+                self._cw.data['eidmap'][eid] = None
+                return None
 
     def editable_relations(self):
         return ()
@@ -533,10 +448,10 @@
         subform.parent_form = self
         self.forms.append(subform)
 
-    def build_context(self, rendervalues=None):
-        super(CompositeFormMixIn, self).build_context(rendervalues)
+    def build_context(self, formvalues=None):
+        super(CompositeFormMixIn, self).build_context(formvalues)
         for form in self.forms:
-            form.build_context(rendervalues)
+            form.build_context(formvalues)
 
 
 class CompositeForm(CompositeFormMixIn, FieldsForm):