We love designing and developing websites, but what really drives us is solving problems and cultivating strong relationships with our clients
Dynamic forms with Django
By : shabda
Newforms, (or forms now) are without doubt one of the coolest features of Django. (Of course after Admin, Localflavor, and many others). Here is some sample code.
class EmployeeForm(forms.Form):
name = forms.CharField()
age = forms.IntegerField()
resume = forms.FileField()
Just this code gives you
- A form which knows how to render itself as Html.
- A form which knows how to validate data on the server side.
- A form which knows how to show the relevant errors.
However think of this scenario,
You need to customise your form depending on values in the Database.
What you want to do is
class EmployeeForm(forms.Form):
name = forms.CharField()
"Show more fields depending on the Values in DB for a specific employees."
#....
#....
#....
You can do this without resorting to any black magic. Here is the code to do so,
#in models.py
type_mapping = {'CharField':forms.CharField(max_length = 100), 'TextField': forms.CharField(widget = forms.Textarea),
'BooleanField':forms.BooleanField(required = False),
'URLField': forms.URLField(), 'EmailField': forms.EmailField()
}
class EmployeeFieldModel(models.Model):
"Model for employee form fields for a specific Job board."
employee = models.ForeignKey(Employee)
name = models.CharField(max_length = 100)
type = models.CharField(max_length = 100)
order = models.IntegerField()
#in forms.py
def get_employee_form(employee):
"""Return the form for a specific Board."""
employee_fields = EmployeeFieldModel.objects.filter(employee = employee).order_by('order')
class EmployeeForm(forms.Form):
def __init__(self, *args, **kwargs):
forms.Form.__init__(self, *args, **kwargs)
self.employee = employee
def save(self):
"Do the save"
for field in employee_fields:
setattr(EmployeeForm, field.name, copy(type_mapping[field.type]))
return type('EmployeeForm', (forms.Form, ), dict(EmployeeForm.__dict__))
#in views.py
employee = Employee.objects.get(employee_slug)
get_employee_form(employee)
PS. A similar techniques works for Dynamic models.
PPS. Yes I have worked with Oracle. Yes, all my data models start with Employee and Departments.
Want to build an Web Application. Talk to Usware
Comments
On second thought, you're not storing the values vertically so it really is just a dynamic form description.
Many thanks. This saved me a lot of digging through the Django source code.
Do you think you could give a demo of what it looks like so I can see it?
You have "do the save". Does it need an override and you just haven't written it? What does your views.py look like if so?
Also, are the fields that are put in dynamically in the "type_mapping" variable?
Chris:
Chris: Cant give a demo, its a intranet only app.
>You have “do the saveâ€. Does it need an override and you just haven’t written it? What does your views.py look like if so?
Yes, override saving the form data to the db.
> Also, are the fields that are put in dynamically in the “type_mapping†variable?
Db has `type`(bad name btw, type is a builtin, mea culpa), which decides what form filed to show using type_mapping
type_mapping = {'CharField':forms.CharField(max_length = 100), 'TextField': forms.CharField(widget = forms.Textarea),
'BooleanField':forms.BooleanField(required = False),
'URLField': forms.URLField(), 'EmailField': forms.EmailField()
}
in the drupal world there is a powerful pattern, where one app (they call module) can (1) extend the form of another app before rendering, and (2) catch the form values from the post.
this might be an essential part for doing this in django.
if i understand it right to do the same we just would need the form to send "before render" and "before save" signals. right?
Thanks. This was what I was looking for exactly.
I have one small addition: James Bennett suggests to use forms.BaseForm instead of forms.Form as base class for dynamically generated Form classes due to some technical reasons.
Thats a really useful trick, thanks for that!
Just out of curiosity, is it necessary to use copy on the field that is looked up in type_mapping?
Yes. Django sets ordering on fields, when they are instantaited. If you do not copy, the fileds will be out of order.
Hi,
How can we dynamically add a fileField to the dynamic form. I tried doing that using the following code but it is throwing errors.
from django import forms
class QuestionsForm(forms.Form):
def <strong>init</strong>(self, questions, <em>args, **kwargs):
super(QuestionsForm, self).<strong>init</strong>(</em>args, **kwargs)
for question in questions:
if question.answer_type == 'textbox':
self.fields['question_%d' % question.id] = forms.CharField(widget = forms.Textarea( attrs={'rows':5, 'cols':60}))
elif question.answer_type == 'file':
self.fields['question_%d' % question.id] = forms.FileField(upload_to='some_dir/')
The error message is:
__init__ got an unexpected keyword argument 'upload_to'
- How to use pep8.py to write better Django code
- Screencast: Django Tutorial Part 1
- How and why to use pyflakes to write better Python
- Getting started with South for Django DB migrations
- A brief overview of Vagrant
- Writing jQuery plugins using Coffeescript
- Behind the Scenes: Request to Response
- Using SQLite Database with Android
- Haml for Django developers
- Coffeescript for Python programmers
- rails
- django
- linkroundup
- django opinion
- opinion
- business
- API
- appengine
- python
- satire
- startup
- Uncategorized
- marketing
- personal
- rambling
- search
- interviews
- seo-interviews
- 5startupideas
- ideas
- seo
- tips
- forms
- paypal
- utilities
- datetime
- web2.0
- Amazon
- algorithms
- presentations
- products
- pinax
- satchmo
- ecommerce
- microsoft
- yahoo
- book
- tutorial
- models
- aggreagtion
- meta
- India
- apps
- about
- CSS
- Design
- wordpress
- test slug
- vim
- urls
- reviews
- javascript
- xmpp
- emacs
- Typography
- Grid Theory
- Color Theory
- iphone
- android
- titanium
- mobile applications
- CSS3
- Browser Compatibility
- mobile
- jobs
- lamson
- django setup
- files
- upload
- jsTree
- hierarchical view
- web page
- Treeview
- coffeescript
- request
- response
- South
- django south
- django migration
- --fake
- screencasts
- February 2012
- January 2012
- December 2011
- October 2011
- September 2011
- July 2011
- June 2011
- April 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- June 2010
- April 2010
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- April 2009
- March 2009
- February 2009
- November 2008
- October 2008
- June 2008
- May 2008
- April 2008
Cool. Just a note, 'dynamic form' is a bit general, I think an accurate description of what you're doing is generating a form for a "vertical" model.