web/views/forms.py
changeset 7875 65e460690139
parent 7815 2a164a9cf81c
child 7889 6cebeb1f386a
--- a/web/views/forms.py	Mon Sep 26 19:46:04 2011 +0200
+++ b/web/views/forms.py	Tue Sep 27 18:46:36 2011 +0200
@@ -47,7 +47,7 @@
 from warnings import warn
 
 from logilab.common import dictattr, tempattr
-from logilab.common.decorators import iclassmethod
+from logilab.common.decorators import iclassmethod, cached
 from logilab.common.compat import any
 from logilab.common.textutils import splitstrip
 from logilab.common.deprecation import deprecated
@@ -57,7 +57,7 @@
 from cubicweb.selectors import non_final_entity, match_kwargs, one_line_rset
 from cubicweb.web import RequestError, ProcessFormError
 from cubicweb.web import uicfg, form, formwidgets as fwdgs
-from cubicweb.web.formfields import relvoc_unrelated, guess_field
+from cubicweb.web.formfields import guess_field
 
 
 class FieldsForm(form.Form):
@@ -376,9 +376,7 @@
         if kwargs.get('mainform', True) or kwargs.get('mainentity', False):
             self.add_hidden(u'__maineid', self.edited_entity.eid)
             # If we need to directly attach the new object to another one
-            if self._cw.list_form_param('__linkto'):
-                for linkto in self._cw.list_form_param('__linkto'):
-                    self.add_hidden('__linkto', linkto)
+            if '__linkto' in self._cw.form:
                 if msg:
                     msg = '%s %s' % (msg, self._cw._('and linked'))
                 else:
@@ -387,6 +385,38 @@
             msgid = self._cw.set_redirect_message(msg)
             self.add_hidden('_cwmsgid', msgid)
 
+    def add_linkto_hidden(self):
+        '''add the __linkto hidden field used to directly attach the new object
+        to an existing other one when the relation between those two is not
+        already present in the form.
+        Warning: this method must be called only when all form fields are setup'''
+        # if current form is not the main form, exit immediately
+        try:
+            self.field_by_name('__maineid')
+        except form.FieldNotFound:
+            return
+        for (rtype, role), eids in self.linked_to.iteritems():
+            # if the relation is already setup by a form field, do not add it
+            # in a __linkto hidden to avoid setting it twice in the controller
+            try:
+                self.field_by_name(rtype, role)
+            except form.FieldNotFound:
+                for eid in eids:
+                    self.add_hidden('__linkto', '%s:%s:%s' % (rtype, role, eid))
+
+    def render(self, *args, **kwargs):
+        self.add_linkto_hidden()
+        return super(EntityFieldsForm, self).render(*args, **kwargs)
+
+    @property
+    @cached
+    def linked_to(self):
+        linked_to = {}
+        for linkto in self._cw.list_form_param('__linkto'):
+            ltrtype, eid, ltrole = linkto.split(':')
+            linked_to.setdefault((ltrtype, ltrole), []).append(typed_eid(eid))
+        return linked_to
+
     def session_key(self):
         """return the key that may be used to store / retreive data about a
         previous post which failed because of a validation error
@@ -427,16 +457,18 @@
     def editable_relations(self):
         return ()
 
-    @deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')
+    @deprecated('[3.6] use cw.web.formfields.RelationField.relvoc_unrelated method')
     def subject_relation_vocabulary(self, rtype, limit=None):
         """defaut vocabulary method for the given relation, looking for
         relation's object entities (i.e. self is the subject)
         """
-        return relvoc_unrelated(self.edited_entity, rtype, 'subject', limit=None)
+        field = self.field_by_name(rtype, 'subject')
+        return field.relvoc_unrelated(form, limit=None)
 
-    @deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')
+    @deprecated('[3.6] use cw.web.formfields.relvoc_unrelated method')
     def object_relation_vocabulary(self, rtype, limit=None):
-        return relvoc_unrelated(self.edited_entity, rtype, 'object', limit=None)
+        field = self.field_by_name(rtype, 'object')
+        return field.relvoc_unrelated(form, limit=None)
 
 
 class CompositeFormMixIn(object):