philippe::niquille | regular niche market thoughts

Django newforms issues

Jun 3rd 2007
6 Comments
respond
trackback

Since the newforms module (which should be preferred to oldforms) is still under heavy development the following points could be helpful.

1) excluding fields with form_for_instance()
Although the docs say fields= does work, it doesn’t. Instead use:

def new_callback(exclude=None, include=None):
“”"
Create a form callback which excludes or only includes certain fields.
“”"
def _callback(field, **kwargs):
if include and field.name not in include:
return None
if exclude and field.name in exclude:
return None
return field.formfield(**kwargs)
return _callback
——–
call with:
——–
profile_callback = new_callback(exclude=['user', 'image'])
uform = forms.models.form_for_instance(profile, formfield_callback=profile_callback)

Watch out for indenting in Python. I know, my code box sucks.

2) Use dynamic choices in select boxes
Use:

class UploadDocu(forms.Form):
category = forms.ModelChoiceField(DocumentCategory.objects.all())

Or use choices defined in a model (just reference it):

def my_form(request):
uform = forms.models.form_for_instance(profile)
uform.base_fields['function'].widget = Select(choices=UserProfile.FUNC_CHOICES)

class UserProfile(models.Model):
FUNC_CHOICES = (
(’president’, ‘Presidente’),
(’vice’, ‘Vicepresidente (segretario)’),
)

3) add input_formats for date fields

uform = forms.models.form_for_model(UserProfile)
uform.base_fields['birthday'].input_formats = (’%Y-%m-%d’,'%d.%m.%Y’,'%d %m %Y’)

This way european dates are accepted and django automatically converts them to the US date format upon save().

4) hide a required field and assign it before calling form.save()

uform = forms.models.form_for_model(UserProfile)
uform.base_fields['user'].widget = HiddenInput() # Hide user field
uform.base_fields['user'].required = False # Make user field not required

Later on check wether to save a new record (and set the user_id or just update the record from the instance.

if form.is_valid():

#set user_id and save new record, if applicable
try:
if uform.base_fields['user']:
newItem = form.save(commit=False) # Create the item
newItem.user_id = request.user.id # Add the data required by the model
newItem.save()
except KeyError:
#do regular update
form.save()

See this page for more examples.

5) add a select box for a CharField

uform.base_fields['semester'].widget = Select(choices=[(v,v) for v in range(1,15)])

Build a list with key:value pairs out of a range of 1-15.

6) automatically add confirm_* fields to validate ex. password input

class ConfirmForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ConfirmForm,self).__init__(*args,**kwargs)

for name in self.fields.keys():
if name.startswith(’confirm_’):
compare_field = name.replace(’confirm_’,”)
setattr(self,’clean_%s’ % name, self._make_confirmation_method(compare_field, name))

def _make_confirmation_method(self, field_name, confirm_field_name):
return lambda: self._confirm_fields_match(field_name, confirm_field_name)

def _confirm_fields_match(self, field_name, confirm_field_name):
if self[field_name].data != self[confirm_field_name].data:
raise forms.ValidationError(’This field must match the %s field’ % self[field_name].label)
return self.cleaned_data.get(confirm_field_name)

class PasswordChange(ConfirmForm):
oldpw = forms.CharField(label=’Vecchia Password’, widget=PasswordInput(render_value=False), max_length=100, )
newpw = forms.CharField(label=’Nuova Password’, widget=PasswordInput(render_value=False), max_length=100, min_length=4)
confirm_newpw = forms.CharField(label=’Ripeti nuova Password ‘, widget=PasswordInput(render_value=False), max_length=100, min_length=4)

This code was pulled from a GoogleGroups post by Ian and modified to fit my setup.

6) check the code for updates
The widget code is very interesting!

7) be aware of devel API changes
If you develop on a django svn version newer than 0.96 (which I do recommend) watch out for changes such as .clean_data which changed to .cleaned_data in newforms. See this page for changes.

6 Comments

  1. Joe

    Thanks! These are great tips.

    I’m about to start using newforms, having just read the documentation for it on the django site, and I will keep these in mind. :)

  2. Thanks for the tips! Would you happen to know how to get the SelectDateWidget to show a date retrieved from the database? I haven’t been able to find anything related to that.

  3. Did you try SplitDateTimeWidget()? Although this is not what you are looking for I suppose. I did not stumble over this date issue yet. Perhaps have a peak into django-newforms-admin code?

  4. Hi Philippe!
    Please do a favor for me.
    We are a reasearches center trying to make statistics of how Sudan could really
    involved into using wireless networking.
    We really impressed of Kismet Earth for detecting wireless Access Points with the region you are.
    Now we tried do use Kismet to discover the the wireless networks near here in Sudan,Khartoum, but we couldnt do it.
    So would you please do it for us, i mean to use Kismet and send us the result of the Access points that surround our region.
    like Demo
    http://www.niquille.com/wp-content/munich_dez05.kmz
    or
    http://www.niquille.com/wp-content/zurich_v0.2.kmz

    we will be very thakful if you do it.

  5. @Ziad: I’m not to sure if you got the usage-scenario right of Kismet-Earth. Kismet-Earth scans your Kismet logs which you need to get by driving/walking past all wireless nodes in your area. I’m not to sure if I’ll make it to Sudan in the next couple of weeks unless you invite me ;-)

  6. Martin

    for tip #1,
    Although fields= not work
    editable=False in database model works fine in Django 0.96

Incoming Links

Leave a Reply