Login

Dynamic Django form

Author:
rufman
Posted:
April 21, 2008
Language:
Python
Version:
.96
Score:
5 (after 5 ratings)

This is a little snippet that you can use to make your Django newforms dynamic at runtime. You can define an arbitrary number of fields of the form without loosing newforms capibilites. You can render the form dynamically be "misusing" the "help_text" attribute of the form fields (Every form field allows the definition of this attribute). This way you can search for changes in the help_text of every field and render the form accordingly.

The form itself is dynamically defined in the view.

The form state can be saved in a Django Session Variable (specifically for Linux users with a process-based Apache Server), so that you can rebuild and verify a submitted form.

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from django import newforms as forms

class DynForm(forms.Form):    
    """
    Dynamic form that allows the user to change and then verify the data that was parsed
    """
    def setFields(self, kwds):
        """
        Set the fields in the form
        """
        keys = kwds.keys()
        keys.sort()
        for k in keys:
            self.fields[k] = kwds[k]
            
    def setData(self, kwds):
        """
        Set the data to include in the form
        """
        keys = kwds.keys()
        keys.sort()
        for k in keys:
            self.data[k] = kwds[k]
            
    def validate(self, post):
        """
        Validate the contents of the form
        """
        for name,field in self.fields.items():
            try:
                field.clean(post[name])
            except ValidationError, e:
                self.errors[name] = e.messages

#### In the view ########################################################

# Form definition
# kwargs is a dictionary. The key being the name of the field and the value 
# being the type (CharField(kwargs*))
kwargs['a_name'] = forms.CharField(label="Name", max_length=25, help_text="name")
kwargs['b_lname'] = forms.CharField(label="Last Name", help_text="lname")
kwargs['c_bday'] = forms.DateField(label="Birthday", help_text="birthday")

# Creating the form object and manipulating/validating it
form = DynForm() # Create the form
form.setFields(kwargs) # Set the fields as defined in the kwargs dictionary
form.setData(request.POST) # Set the form data
form.validate(request.POST) # validate the from 

##########################################################################

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 9 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 10 months, 3 weeks ago

Comments

mdales (on July 18, 2008):

This is great, but to make it work you need to modify setData to add the line:

self.is_bound = True

Otherwise when you display the form it ignores the data

#

balsagoth (on August 1, 2008):

How can i use this? thanks

#

mikeshantz (on August 12, 2008):

Nice. This came in handy, but it doesn't play well with multivalue fields.

I had to modify setData and validate to deal with this situation:

def setData(self, kwds):
    """Set the data to include in the form"""
    for name,field in self.fields.items():
        self.data[name] = field.widget.value_from_datadict(
                            kwds, self.files, self.add_prefix(name))
    self.is_bound = True

def validate(self, post):
    """Validate the contents of the form"""
    for name,field in self.fields.items():
        value = field.widget.value_from_datadict(
                            post, self.files, self.add_prefix(name))
        try:
            field.clean(value)
        except forms.ValidationError, e:
            self.errors[name] = e.messages

#

curaloucura (on August 19, 2008):

I couldn't find how I can access the cleaned_data and in fact why you are creating a different method validate instead of using self.full_clean() or something similar. I just changed the validate to:

def validate(self): self.full_clean()

for readability sake and now I can access:

dynform_instance.cleaned_data['myfield']

#

shreyankg (on May 19, 2011):

My modifications for accessing cleaned_data:

def validate(self, post):
    """
    Validate the contents of the form
    """
    self.cleaned_data = {}
    for name,field in self.fields.items():
        try:
            self.cleaned_data[name] = field.clean(post[name])
        except ValidationError, e:
            self.errors[name] = e.messages

#

vsergeyev (on October 6, 2011):

Hi, imho it is good to add to it a function "is_valid". So form can be used as always.

if form.is_valid():
    # process it

#

iceman3710 (on January 29, 2012):

Could you please explain, how can change repesentation of form in html?

I can easily wright {{form}} or {{form.as_table}}, but I want locate them by myself.

Should I do smth like {{form.fields[k]}} ? (I can't make this work)

#

Please login first before commenting.