Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lesson 15 - Advanced Forms and Rendering

Lesson 15 - Advanced Forms and Rendering

Dana Spiegel

December 05, 2012
Tweet

More Decks by Dana Spiegel

Other Decks in Technology

Transcript

  1. Changing the Widget for a FormField • Django provides a

    number of alternative widgets that can be used to render • To specify an alternative widget, specify it when the field is declared: • Textarea uses an HTML <textarea> element instead of an <input type="text"> • Can replace choice fields with radio buttons instead of dropdowns: 2 message = forms.CharField(widget=forms.Textarea) GENDER_CHOICES = ( ('M', 'Male'), ('F', 'Female'), ) class ContactForm(forms.Form): ... gender = forms.ChoiceField(choices=GENDER_CHOICES) gender_2 = forms.ChoiceField(choices=GENDER_CHOICES, widget=forms.RadioSelect)
  2. Django Form Processing: Validating • Validation of a form determines

    if a form’s fields are acceptable • Each form is validated if validators are provided (or implied) • Validators don’t change the value of the field, they just determine if the field is acceptable or not • They raise a ValidationError exception if the field isn’t “valid”, which will be turned into a field error for display to a user • Validation can be configured by specifying one or more validators when specifying a field in a form • MaxValueValidator, MinValueValidator • MaxLengthValidator, MinLengthValidator • RegexValidator, URLValidator • validate_email, validate_slug, validate_ipv4_address, validate_comma_separated_integer_list 3 age = forms.IntegerField(validators=[MinValueValidator(20), MaxValueValidator(100)])
  3. Django Form Processing: Cleaning • Cleaning a form or field

    actually adjusts the field value that’s been submitted to be in the right format • Fields and the entire form can be cleaned using custom clean() methods • To clean a field, create a clean_<fieldname>() method in the form • Useful for transforming the value of an individual field • Method should take no parameters • Data is accessed via self.cleaned_data • Return the cleaned version of the field • Raise a ValidationError if the field is incorrect 4 def clean_recipients(self): data = self.cleaned_data['recipients'] if "[email protected]" not in data: raise forms.ValidationError("You have forgotten about Fred!") return data
  4. Django Form Processing: Cleaning • To clean a form, create

    a clean() method in the form • Useful for when fields need to be compared to each other • Method should take no parameters • Data is accessed via self.cleaned_data • Return a cleaned version of self.cleaned_data • Raise a ValidationError if the form is incorrect • Validation errors will be form-wide; if you want to show an error on a specific field, set the self._errors for that field 5 def clean(self): cleaned_data = super(ContactForm, self).clean() cc_myself = cleaned_data.get("cc_myself") subject = cleaned_data.get("subject") if cc_myself and subject and "help" not in subject: msg = u"Put 'help' in subject when cc'ing yourself." self._errors["cc_myself"] = self.error_class([msg]) self._errors["subject"] = self.error_class([msg]) del cleaned_data["cc_myself"] del cleaned_data["subject"] return cleaned_data
  5. Sending a Message: Mandrill API • Sending an email message

    is sometimes easier through a service, if there’s no MTA on the server • Mandrill offers an on-demand MTA with an API (for free, for small volumes) • To use the API to send a message: • Set the API Key in settings.py • In the view, import the mandrill module and use it to construct a message 6 MANDRILL_API_KEY = '12345678-1234-1234-1234-123456789012' # send the contact information via Mandrill m = mandrill.Mandrill(settings.MANDRILL_API_KEY) m.messages.send({ 'text': form.cleaned_data.get('message'), 'subject': form.cleaned_data.get('subject'), 'from_email': form.cleaned_data.get('sender'), 'to': [{ 'email': '[email protected]', 'name': 'Dana Spiegel', }], })
  6. Sending a Message: Mandrill API • Make sure to surround

    the API calls with try/except to ensure errors are caught and logged • To properly log in a django application, use the logging module • Mandrill can raise 2 types of exceptions • InvalidKeyError - if the api key is invalid • Error - if there’s an issue with the API call • Ensure you catch all relevant exceptions and log the errors 7 import logging ... logging.info('Sent contact email: {0}'.format( form.cleaned_data)) logging.error('Cannot send contact email: {0}'.format( form.cleaned_data)) logging.exception(e)
  7. Example: Mandrill API 8 def contact(request): if request.method == 'POST':

    form = forms.ContactForm(request.POST) if form.is_valid(): try: # send the contact information via Mandrill m = mandrill.Mandrill(settings.MANDRILL_API_KEY) m.messages.send({ 'text': form.cleaned_data.get('message'), 'subject': form.cleaned_data.get('subject'), 'from_email': form.cleaned_data.get('sender'), 'to': [{ 'email': '[email protected]', 'name': 'Dana Spiegel', }], }) logging.info('Sent contact email: {0}'.format(form.cleaned_data)) except mandrill.InvalidKeyError, e: logging.error('Cannot send contact email: {0}'.format( form.cleaned_data)) logging.exception(e) except mandrill.Error, e: logging.error('Cannot send contact email: {0}'.format( form.cleaned_data)) logging.exception(e) return redirect('contact_complete') else: form = forms.ContactForm() return TemplateResponse(request, 'contact.html', { 'form': form, })