assign fields dynamically in newforms

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from django import newforms as forms

class DynamicFieldSnippetForm(forms.Form):
    """DynamicFieldSnippetForm - declare a field dynamically in a form.

    The weight field is required.  The height field is optional and
    not included on the form unless requested.
    
    >>> print DynamicFieldSnippetForm()
    <tr><th><label for="id_weight">Weight:</label></th><td><input type="text" name="weight" id="id_weight" /></td></tr>

    >>> print DynamicFieldSnippetForm(request_height=True)
    <tr><th><label for="id_weight">Weight:</label></th><td><input type="text" name="weight" id="id_weight" /></td></tr>
    <tr><th><label for="id_height">Height:</label></th><td><input type="text" name="height" id="id_height" /></td></tr>

    >>> print DynamicFieldSnippetForm({'height':174, 'weight':122}, request_height=True)
    <tr><th><label for="id_weight">Weight:</label></th><td><input type="text" name="weight" value="122" id="id_weight" /></td></tr>
    <tr><th><label for="id_height">Height:</label></th><td><input type="text" name="height" value="174" id="id_height" /></td></tr>
    >>> 
    """
    def __init__(self, *args, **kwargs):
        request_height = kwargs.pop('request_height', False)
        super(DynamicFieldSnippetForm, self).__init__(*args, **kwargs)
        if request_height:
            self.fields['height'] = forms.CharField(required=False)
    weight = forms.CharField()
    
if __name__ == '__main__':
    import doctest
    doctest.testmod()

More like this

  1. Render dynamically assigned fields in a template by rubic 6 years, 3 months ago
  2. Complex Formsets, Redux by smagala 3 years, 3 months ago
  3. FieldAccessForm (per-field user access for forms derived from models) by Killarny 4 years, 8 months ago
  4. FieldsetForm by Ciantic 6 years, 2 months ago
  5. A Lazy ChoiceField implementation by lsbardel 3 years, 8 months ago

Comments

whiteinge (on June 11, 2007):

If you are also giving dynamic names to your dynamic fields and thusly need to generate dynamic clean_FOO() methods, the following lambda trick may give you a hint on how to proceed:

setattr(self, 'clean_%s' % FOO, lambda: self._clean_FOO_helper(FOO))

def _clean_FOO_helper(self, your_field_name):
    # normal raise validation error stuff goes here
    return self.cleaned_data.get(field_name)

#

whiteinge (on June 20, 2007):

Apologies for the incomplete example above. If you need self available to your helper function, you'll need an extra wrapper:

def __init__(self, *args, **kwargs):
    # Snippet 82 can be useful here
    # http://www.djangosnippets.org/snippets/82/
    setattr(self, 'clean_%s' % your_field_name, self._lambda_helper(your_field_name))

def _lambda_helper(self, arg):
    return lambda: self._clean_FOOS_helper(arg)

def _clean_FOOS_helper(self, field_name):
    # validation stuff goes here
    return self.cleaned_data.get(field_name)

There may be a better way to accomplish the above. I'm still learning.

#

whiteinge (on September 17, 2007):

There is, and it's called closures. Not much shorter, but certainly more readable.

def __init__(self, *args, **kwargs):
    setattr(self, 'clean_%s' % your_field_name, self.closure_clean(your_field_name))

def closure_clean(self, field_name):
    def generic_clean():
        # your dynamic clean logic here...
        return self.cleaned_data.get(field_name)
    return generic_clean

#

(Forgotten your password?)