django forms: best practices, tips, tricks

18
Django Forms Django Forms Best Practices, Tips and Tricks Best Practices, Tips and Tricks DjangoCon 2010 Shawn Rider PBS Education

Upload: shawn-rider

Post on 06-Feb-2015

35.132 views

Category:

Technology


3 download

DESCRIPTION

This is a presentation for novice Django developers that reviews the basics of working with Django's Forms module.

TRANSCRIPT

Page 1: Django Forms: Best Practices, Tips, Tricks

Django FormsDjango FormsBest Practices, Tips and TricksBest Practices, Tips and Tricks

DjangoCon 2010

Shawn RiderPBS Education

Page 2: Django Forms: Best Practices, Tips, Tricks

Basic Forms

from django import forms  class ContactForm(forms.Form):     subject = forms.CharField(max_length=100)     message = forms.CharField()     sender = forms.EmailField()     cc_myself = forms.BooleanField(required=False)      def save(self):         data = self.cleaned_data         contact = Contact()         contact.subject = data.get('subject', '')         contact.message = data.get('message', '')          contact.sender = data.get('sender', '')          contact.cc_myself = data.get('cc_myself', False)          contact.save()         return contact

Page 3: Django Forms: Best Practices, Tips, Tricks

But that's so much to write...But that's so much to write...

Page 4: Django Forms: Best Practices, Tips, Tricks

Model Forms

• Easily create forms with just a few lines of code.

• Customize and modify fields available for editing on the form.

• Override default methods to support complex business logic, etc.

• Customized Model Forms can easily be used in Django Admin.

• Model Forms can be used with Model Formsets to edit multiple forms in a single view.

Page 5: Django Forms: Best Practices, Tips, Tricks

Model Forms

from django.forms import ModelForm 

### ... Form Definition ... ### class ArticleForm(ModelForm):     class Meta:         model = Article ### ... Inside the View ... ### article = Article.objects.get(pk=article_id) if request.method == 'POST':     form = ArticleForm(request.POST, instance=article)     if form.is_valid():        article = form.save()         return HttpResponseRedirect(redirect_url)   else:     form = ArticleForm(instance=article)

Page 6: Django Forms: Best Practices, Tips, Tricks

Model Forms   

A Model Form with listed editable fields and explicitly defined widgets:

class ArticleForm(ModelForm):     class Meta:         model = Article         fields = ('title', 'content', 'blurb')        widgets = {            'content': Textarea(attrs:{'cols':80, 'rows':20})        }

A Model Form with a custom save method:

class ArticleForm(ModelForm):     class Meta:         model = Article    def save(self, *args, **kwargs):         data = self.cleaned_data        ### Insert complex, custom save logic here. ###        return article

Page 7: Django Forms: Best Practices, Tips, Tricks

Formsets

• Formsets allow you to produce multiple forms for a page (bulk editing).

• Can be customized in many ways.

• Handle basic metadata to keep forms and data properly aligned.

• Formsets are used with basic Django forms. Model Formsets are used with Django Model Forms.

• Allow for validation of entire set of forms as well as individual forms within the formset.

Page 8: Django Forms: Best Practices, Tips, Tricks

Formsets ### View code ### def manage_articles(request):     ArticleFormSet = formset_factory(ArticleForm)     if request.method == 'POST':        formset = ArticleFormSet(request.POST, request.FILES)         if formset.is_valid():             for form in formset:                 form.save()             return HttpResponseRedirect(REDIRECT_URL)    else:         formset = ArticleFormSet()     return render_to_response('manage_articles.html', {        'formset': formset     })

<!-- Template Code --> <form method="post" action="">     <table> {{ formset }} </table>  </form>

Page 9: Django Forms: Best Practices, Tips, Tricks

Dynamic Forms

A Dynamic Form modulates the fields and/or choices available in the form

Why would I ever need a Dynamic Form?

• Enforcing restricted permissions for different levels of user

• Providing choices based on user or system data (custom contact lists, for example)

• Enforcing other complex business logic

Page 10: Django Forms: Best Practices, Tips, Tricks

For some developers, For some developers, it seems natural to use it seems natural to use a "code factory" design a "code factory" design

pattern to solve this pattern to solve this problem.problem.

Please don't do that.Please don't do that.

Page 11: Django Forms: Best Practices, Tips, Tricks

Override __init__ function

class ContactForm(forms.Form):     def __init__(self, user, *args, **kwargs):         super(ContactForm, self).__init__(*args, **kwargs)         if not user.is_authenticated():             self.fields['captcha'] = CaptchaField()    name = forms.CharField(max_length=50)    email = forms.Emailfield()    message = forms.CharField(widget=forms.Textarea)

Code Factory

def make_contact_form(user):     # The basic form     class _ContactForm(forms.Form):        name = forms.CharField(max_length=50)        email = forms.EmailField()        message = forms.CharField(widget=forms.Textarea)           if user.is_authenticated():       return _ContactForm 

    class _CaptchaContactForm(_ContactForm):       captcha = CaptchaField()                    return _CaptchaContactForm 

(Taken from James Bennett's http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/)

Page 12: Django Forms: Best Practices, Tips, Tricks

Dynamic Forms

class MemberSearchForm(forms.Form):    def __init__(self, data=None, account=None, *args, **kwargs):        self.account = account        super(MemberSearchForm, self).__init__(data, *args, **kwargs)

    terms = forms.CharField(required=False)    role = forms.ChoiceField(choices=SEARCH_ROLE_CHOICES, required=False)    status = forms.ChoiceField(choices=SEARCH_STATUS_CHOICES, required=False)

Page 13: Django Forms: Best Practices, Tips, Tricks

Tip: Always Redirect After Modifying Data

article = Article.objects.get(pk=article_id) if request.method == 'POST':    form = ArticleForm(request.POST, instance=article)     if form.is_valid():        article = form.save()         return HttpResponseRedirect(redirect_url)   else:     form = ArticleForm(instance=article)

Page 14: Django Forms: Best Practices, Tips, Tricks

The Worst Example in the Django docs?

def contact(request):     if request.method == 'POST': # If the form has been submitted...       form = ContactForm(request.POST) # A form bound to the POST data       if form.is_valid(): # All validation rules pass         subject = form.cleaned_data['subject']         message = form.cleaned_data['message']         sender = form.cleaned_data['sender']         cc_myself = form.cleaned_data['cc_myself']         recipients = ['[email protected]']         if cc_myself:             recipients.append(sender)             from django.core.mail import send_mail             send_mail(subject, message, sender, recipients)         return HttpResponseRedirect('/thanks/') # Redirect after POST     else:         form = ContactForm() # An unbound form     return render_to_response('contact.html', { 'form': form, })

Page 15: Django Forms: Best Practices, Tips, Tricks

Tip:Use Forms to Isolate Logic class MemberSearchForm(forms.Form):    def __init__(self, data=None, account=None, *args, **kwargs):        self.account = account        super(MemberSearchForm, self).__init__(data, *args, **kwargs)    terms = forms.CharField(required=False)    role = forms.ChoiceField( choices=SEARCH_ROLE_CHOICES, required=False)    status = forms.ChoiceField( choices=SEARCH_STATUS_CHOICES, required=False)

    def search(self):         data = self.cleaned_data         ### Complex Search Logic Here ###         return results

Page 16: Django Forms: Best Practices, Tips, Tricks

Tip:Use django-uni-form

Page 17: Django Forms: Best Practices, Tips, Tricks

Tip:Roll Your Own Fields and Form Classes• Isolate logic at any cost

• Sometimes objects or features in your project warrant a completely custom Form Field

• Custom Form Classes can perform custom templatized output, eliminating repetitive HTML in your templates

Sub Tip:

• Extend existing classes to save yourself headaches

Page 18: Django Forms: Best Practices, Tips, Tricks

Thanks and Further Reading

James Bennett's B-List: http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/

Danny Greenfield’s Django-Uniform: http://github.com/pydanny/django-uni-form/