web/views/forms.py
brancholdstable
changeset 8462 a14b6562082b
parent 7990 a673d1d9a738
child 8128 0a927fe4541b
equal deleted inserted replaced
8231:1bb43e31032d 8462:a14b6562082b
    45 __docformat__ = "restructuredtext en"
    45 __docformat__ = "restructuredtext en"
    46 
    46 
    47 from warnings import warn
    47 from warnings import warn
    48 
    48 
    49 from logilab.common import dictattr, tempattr
    49 from logilab.common import dictattr, tempattr
    50 from logilab.common.decorators import iclassmethod
    50 from logilab.common.decorators import iclassmethod, cached
    51 from logilab.common.compat import any
    51 from logilab.common.compat import any
    52 from logilab.common.textutils import splitstrip
    52 from logilab.common.textutils import splitstrip
    53 from logilab.common.deprecation import deprecated
    53 from logilab.common.deprecation import deprecated
    54 
    54 
    55 from cubicweb import ValidationError, typed_eid
    55 from cubicweb import ValidationError, typed_eid
    56 from cubicweb.utils import support_args
    56 from cubicweb.utils import support_args
    57 from cubicweb.selectors import non_final_entity, match_kwargs, one_line_rset
    57 from cubicweb.selectors import non_final_entity, match_kwargs, one_line_rset
    58 from cubicweb.web import RequestError, ProcessFormError
    58 from cubicweb.web import RequestError, ProcessFormError
    59 from cubicweb.web import uicfg, form, formwidgets as fwdgs
    59 from cubicweb.web import uicfg, form, formwidgets as fwdgs
    60 from cubicweb.web.formfields import relvoc_unrelated, guess_field
    60 from cubicweb.web.formfields import guess_field
    61 
    61 
    62 
    62 
    63 class FieldsForm(form.Form):
    63 class FieldsForm(form.Form):
    64     """This is the base class for fields based forms.
    64     """This is the base class for fields based forms.
    65 
    65 
   180         if self.needs_js:
   180         if self.needs_js:
   181             self._cw.add_js(self.needs_js)
   181             self._cw.add_js(self.needs_js)
   182         if self.needs_css:
   182         if self.needs_css:
   183             self._cw.add_css(self.needs_css)
   183             self._cw.add_css(self.needs_css)
   184 
   184 
   185     def render(self, formvalues=None, rendervalues=None, renderer=None, **kwargs):
   185     def render(self, formvalues=None, renderer=None, **kwargs):
   186         """Render this form, using the `renderer` given as argument or the
   186         """Render this form, using the `renderer` given as argument or the
   187         default according to :attr:`form_renderer_id`. The rendered form is
   187         default according to :attr:`form_renderer_id`. The rendered form is
   188         returned as an unicode string.
   188         returned as an unicode string.
   189 
   189 
   190         `formvalues` is an optional dictionary containing values that will be
   190         `formvalues` is an optional dictionary containing values that will be
   191         considered as field's value.
   191         considered as field's value.
   192 
   192 
   193         Extra keyword arguments will be given to renderer's :meth:`render` method.
   193         Extra keyword arguments will be given to renderer's :meth:`render` method.
   194 
   194         """
   195         `rendervalues` is deprecated.
       
   196         """
       
   197         if rendervalues is not None:
       
   198             warn('[3.6] rendervalues argument is deprecated, all named arguments will be given instead',
       
   199                  DeprecationWarning, stacklevel=2)
       
   200             kwargs = rendervalues
       
   201         w = kwargs.pop('w', None)
   195         w = kwargs.pop('w', None)
   202         if w is None:
   196         if w is None:
   203             warn('[3.10] you should specify "w" to form.render() named arguments',
   197             warn('[3.10] you should specify "w" to form.render() named arguments',
   204                  DeprecationWarning, stacklevel=2)
   198                  DeprecationWarning, stacklevel=2)
   205             data = []
   199             data = []
   304             if errors:
   298             if errors:
   305                 errors = dict((f.role_name(), unicode(ex)) for f, ex in errors)
   299                 errors = dict((f.role_name(), unicode(ex)) for f, ex in errors)
   306                 raise ValidationError(None, errors)
   300                 raise ValidationError(None, errors)
   307             return processed
   301             return processed
   308 
   302 
   309     @deprecated('[3.6] use .add_hidden(name, value, **kwargs)')
       
   310     def form_add_hidden(self, name, value=None, **kwargs):
       
   311         return self.add_hidden(name, value, **kwargs)
       
   312 
       
   313     @deprecated('[3.6] use .render(formvalues, **rendervalues)')
       
   314     def form_render(self, **values):
       
   315         """render this form, using the renderer given in args or the default
       
   316         FormRenderer()
       
   317         """
       
   318         self.build_context(values)
       
   319         renderer = values.pop('renderer', None)
       
   320         if renderer is None:
       
   321             renderer = self.default_renderer()
       
   322         return renderer.render(self, values)
       
   323 
       
   324 
   303 
   325 _AFF = uicfg.autoform_field
   304 _AFF = uicfg.autoform_field
   326 _AFF_KWARGS = uicfg.autoform_field_kwargs
   305 _AFF_KWARGS = uicfg.autoform_field_kwargs
   327 
   306 
   328 class EntityFieldsForm(FieldsForm):
   307 class EntityFieldsForm(FieldsForm):
   374         self.add_hidden('eid', self.edited_entity.eid)
   353         self.add_hidden('eid', self.edited_entity.eid)
   375         # mainform default to true in parent, hence default to True
   354         # mainform default to true in parent, hence default to True
   376         if kwargs.get('mainform', True) or kwargs.get('mainentity', False):
   355         if kwargs.get('mainform', True) or kwargs.get('mainentity', False):
   377             self.add_hidden(u'__maineid', self.edited_entity.eid)
   356             self.add_hidden(u'__maineid', self.edited_entity.eid)
   378             # If we need to directly attach the new object to another one
   357             # If we need to directly attach the new object to another one
   379             if self._cw.list_form_param('__linkto'):
   358             if '__linkto' in self._cw.form:
   380                 for linkto in self._cw.list_form_param('__linkto'):
       
   381                     self.add_hidden('__linkto', linkto)
       
   382                 if msg:
   359                 if msg:
   383                     msg = '%s %s' % (msg, self._cw._('and linked'))
   360                     msg = '%s %s' % (msg, self._cw._('and linked'))
   384                 else:
   361                 else:
   385                     msg = self._cw._('entity linked')
   362                     msg = self._cw._('entity linked')
   386         if msg:
   363         if msg:
   387             msgid = self._cw.set_redirect_message(msg)
   364             msgid = self._cw.set_redirect_message(msg)
   388             self.add_hidden('_cwmsgid', msgid)
   365             self.add_hidden('_cwmsgid', msgid)
       
   366 
       
   367     def add_linkto_hidden(self):
       
   368         """add the __linkto hidden field used to directly attach the new object
       
   369         to an existing other one when the relation between those two is not
       
   370         already present in the form.
       
   371 
       
   372         Warning: this method must be called only when all form fields are setup
       
   373         """
       
   374         for (rtype, role), eids in self.linked_to.iteritems():
       
   375             # if the relation is already setup by a form field, do not add it
       
   376             # in a __linkto hidden to avoid setting it twice in the controller
       
   377             try:
       
   378                 self.field_by_name(rtype, role)
       
   379             except form.FieldNotFound:
       
   380                 for eid in eids:
       
   381                     self.add_hidden('__linkto', '%s:%s:%s' % (rtype, eid, role))
       
   382 
       
   383     def render(self, *args, **kwargs):
       
   384         self.add_linkto_hidden()
       
   385         return super(EntityFieldsForm, self).render(*args, **kwargs)
       
   386 
       
   387     @property
       
   388     @cached
       
   389     def linked_to(self):
       
   390         # if current form is not the main form, exit immediately
       
   391         try:
       
   392             self.field_by_name('__maineid')
       
   393         except form.FieldNotFound:
       
   394             return {}
       
   395         linked_to = {}
       
   396         for linkto in self._cw.list_form_param('__linkto'):
       
   397             ltrtype, eid, ltrole = linkto.split(':')
       
   398             linked_to.setdefault((ltrtype, ltrole), []).append(typed_eid(eid))
       
   399         return linked_to
   389 
   400 
   390     def session_key(self):
   401     def session_key(self):
   391         """return the key that may be used to store / retreive data about a
   402         """return the key that may be used to store / retreive data about a
   392         previous post which failed because of a validation error
   403         previous post which failed because of a validation error
   393         """
   404         """
   425                 return None
   436                 return None
   426 
   437 
   427     def editable_relations(self):
   438     def editable_relations(self):
   428         return ()
   439         return ()
   429 
   440 
   430     @deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')
       
   431     def subject_relation_vocabulary(self, rtype, limit=None):
       
   432         """defaut vocabulary method for the given relation, looking for
       
   433         relation's object entities (i.e. self is the subject)
       
   434         """
       
   435         return relvoc_unrelated(self.edited_entity, rtype, 'subject', limit=None)
       
   436 
       
   437     @deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')
       
   438     def object_relation_vocabulary(self, rtype, limit=None):
       
   439         return relvoc_unrelated(self.edited_entity, rtype, 'object', limit=None)
       
   440 
       
   441 
   441 
   442 class CompositeFormMixIn(object):
   442 class CompositeFormMixIn(object):
   443     __regid__ = 'composite'
   443     __regid__ = 'composite'
   444     form_renderer_id = __regid__
   444     form_renderer_id = __regid__
   445 
   445