1. nitin
  2. FormAlchemy

Commits

Alexandre Bourget  committed d779de5

#84 Make sure we can call .configure() multiple times, with consistent and predictable results.

Before this patch, the outcome of calling configure() twice was unpredictable, thus
no old code should be broken.

Removed some documentation to ModelRenderer for params it didn't have.
NOTE: there is duplication with documentation in docs/forms.txt from ModelRenderer.

It is now possible to call a fs.configure(options=[fs.field1.required()]) and it
will simply replace the `field1` in the _render_fields. This will work only if
you do not specify `include` and `exclude`.

Using this feature, you can create FieldSet configured with the full fields. Then
go back and tweak certain fields. NOTE: This is a little bit less useful since we
have set(option=blah) on the Fields, that modify fields in-place.

Also, it will save focus=True/False and readonly=True/False between calls to
configure(). You'd have to specify it explicitly to change the values. The default
for each remains the same as before. The same is true for global_validator on
AbstractFieldSet and FieldSet.

  • Participants
  • Parent commits b980b3a
  • Branches default

Comments (0)

Files changed (2)

File formalchemy/base.py

View file
  • Ignore whitespace
           * `options=[]`:
                 an iterable of modified attributes.  The set of attributes to
                 be rendered is unaffected
-          * `global_validator=None`:
-                global_validator` should be a function that performs
-                validations that need to know about the entire form.
-          * `focus=True`:
-                the attribute (e.g., `fs.orders`) whose rendered input element
-                gets focus. Default value is True, meaning, focus the first
-                element. False means do not focus at all.
 
         Only one of {`include`, `exclude`} may be specified.
 
             raise ValueError('pk option must be True or False, not %s' % pk)
 
         # verify that options that should be lists of Fields, are
-        for iterable in ['include', 'exclude', 'options']:
+        fields_vals = self._fields.values()
+        for iterable, itername in ((include, 'include'), (exclude, 'exclude'), (options, 'options')):
             try:
-                L = list(eval(iterable))
-            except:
-                raise ValueError('`%s` parameter should be an iterable' % iterable)
-            for field in L:
+                iterator = iter(iterable)
+            except TypeError, e:
+                raise ValueError('`%s` parameter should be an iterable' % itername)
+            for field in iterator:
                 if not isinstance(field, fields.AbstractField):
-                    raise TypeError('non-AbstractField object `%s` found in `%s`' % (field, iterable))
-                if field not in self._fields.values():
-                    raise ValueError('Unrecognized Field `%s` in `%s` -- did you mean to call append() first?' % (field, iterable))
+                    raise TypeError('non-AbstractField object `%s` found in `%s`' % (field, itername))
+                if field not in fields_vals:
+                    raise ValueError('Unrecognized Field `%s` in `%s` -- did you mean to call append() first?' % (field, itername))
 
-        # if include is given, those are the fields used.  otherwise, include those not explicitly (or implicitly) excluded.
-        if not include:
+        if not include and not exclude:
+            # Don't modify fields to be rendered, just apply options
+            include = self._render_fields.values()
+        elif not include:
+            # if include is given, those are the fields used.  otherwise, include those not explicitly (or implicitly) excluded.
             ignore = list(exclude) # don't modify `exclude` directly to avoid surprising caller
             if not pk:
                 ignore.extend([wrapper for wrapper in self._raw_fields() if wrapper.is_pk and not wrapper.is_collection])
             ignore.extend([wrapper for wrapper in self._raw_fields() if wrapper.is_raw_foreign_key])
             include = [field for field in self._raw_fields() if field not in ignore]
-
-        # in the returned list, replace any fields in `include` w/ the corresponding one in `options`, if present.
-        # this is a bit clunky because we want to
-        #   1. preserve the order given in `include`
-        #   2. not modify `include` (or `options`) directly; that could surprise the caller
-        options_dict = {} # create + update for 2.3's benefit
-        options_dict.update(dict([(wrapper, wrapper) for wrapper in options]))
-        L = []
-        for wrapper in include:
-            if wrapper in options_dict:
-                L.append(options_dict[wrapper])
-            else:
-                L.append(wrapper)
-        return L
+            
+        # Override with options, keeping order in `include`, based on the `name` of the field.
+        # Beware not to modify `include` or `options`' content directly; that could surprise the caller.
+        new_render_fields = include[:]
+        for override in options:
+            for i, field in enumerate(new_render_fields):
+                if field.key == override.key:
+                    new_render_fields[i] = override
+        return new_render_fields
 
     def __getattr__(self, attrname):
         try:

File formalchemy/forms.py

View file
  • Ignore whitespace
 
         """
         base.EditableRenderer.configure(self, pk, exclude, include, options)
-        self.validator = global_validator
+        if global_validator is not None:
+            self.validator = global_validator
 
     def validate(self):
         """
         self.focus = True
         self.readonly = False
 
-    def configure(self, pk=False, exclude=[], include=[], options=[], global_validator=None, focus=True, readonly=False):
+    def configure(self, pk=False, exclude=[], include=[], options=[], global_validator=None, focus=None, readonly=None):
         """
         Besides the options in :meth:`AbstractFieldSet.configure`,
         `FieldSet.configure` takes the `focus` parameter, which should be the
 
         """
         AbstractFieldSet.configure(self, pk, exclude, include, options, global_validator)
-        self.focus = focus
-        self.readonly = readonly
+        if focus is not None:
+            self.focus = focus
+        if readonly is not None:
+            self.readonly = readonly
 
     def validate(self):
         if self.readonly: