Using Formish within Restish — Restish v1 documentation

### Navigation

- index
- previous |
- Restish v1 documentation »

# Using Formish within Restish

## Introduction

Formish is a forms library that was developed in parralel with Restish, although the library itself can be used completely independently. Formish started life as formal, a form library written for Twisted/Nevow. The goal of the project was to create a simple forms library that allowed separation of the component parts such as schema, widgets, validation, data conversion and templates. The result is a suite of components formish, validatish, convertish and schemaish. These can all be used independently but work seamlessly when needed.

## Using a simple form withing Restish

We’ll start off with one of the examples from the Formish documentation.

    class SimpleSchema(schemaish.Structure):
        """ A simple sommets form """
        email = schemaish.String(validator=schemaish.All(schemaish.NotEmpty, schemaish.Email))
        first_names = schemaish.String(validator=schemaish.NotEmpty)
        last_name = schemaish.String(validator=schemaish.NotEmpty)
        comments = schemaish.String()

    def get_form():
        """ Creates a form and assigns a widget """
        form = formish.Form(SimpleSchema())
        form['comments'].widget = formish.TextArea()
        return form

    class Root(resource.Resource):
        """ Our form resource """

        @resource.GET()
        @templating.page('test.html')
        def html(self, request, form=None):
            """
            If the form is None then we get a clean form, otherwise show the
            form that was passsed back from an unsuccessful POST
            """
            if form is None:
                form = get_form()
            return {'form': form}

        @resource.POST()
        def POST(self, request):
            """
            Get a clean form and validate it against the request data that was
            submitted. Errors pass the form (with attached errors) back up to
            the page renderer. Success shows a thanks page (typically you would
            redirect here.
            """
            form = get_form()
            try:
                data = form.validate(request)
            except formish.FormError, e:
                return self.html(request, form)
            return self.thanks(request,data)

        @templating.page('thanks.html')
        def thanks(self, request, data):
            """ Just show the data """
            return {'data': data}

We need to have the following in the `test.html` file

    <div id="formbox">
      ${form()|n}
    </div>

The steps when this form is created are as follows

1. Get a copy of the form and put it on the page
2. When POST’d, validate the returned request data. If this raises an exception, errors will have been bound to the form instance.
3. (On Error): Pass the form with bound errors back up the page renderer.
4. (On Success): Show a thanks page.

We can also pass the success and failure callables to the validate function to simplify the form handling.

    class Root(resource.Resource):

        @resource.GET()
        @templating.page('test.html')
        def html(self, request, form=None):
            if form is None:
                form = get_form()
            return {'form': form}

        @resource.POST()
        def POST(self, request):
            return get_form().validate(request, self.html, self.thanks)

        @templating.page('thanks.html')
        def thanks(self, request, data):
            return {'data': data}

## Multiple Actions on a Form

If we have more than one action on a form

    class Root(resource.Resource):

        def get_form(self):
            form = formish.Form( ('email', schemaish.String()) )
            form.addAction(self.check_email_domain, 'check')
            form.addAction(self.send_test_email, 'test')
            return form

        def check_email_domain(self, request, data):
            """ Check the domain has an MX or A record """

        def send_test_email(self, request, data):
            """ Send a test email to this address """

        @resource.GET()
        @templating.page('test.html')
        def html(self, request, form=None):
            if form is None:
                form = self.get_form()
            return {'form': form}

        @resource.POST()
        def POST(self, request):
            form = self.get_form()
            return form.validate(request, self.html, form.action)

Here we have pass the `form.action` method as the success callable. The whatever is in `form.action` (for example, `check_email_domain`) is called with `(request, data)`.

## Multiple Forms on a Page

If we have more than one form on a page, we can use the utility function, `form_in_request` to find out which one was posted.

    class Root(resource.Resource):

        ##
        # Forms

        def _email_form(self):
            return formish.Form( ('email', schemaish.String()), name='email' )

        def _domain_form(self):
            return formish.Form( ('domain', schemaish.String()), name='domain' )

        ##
        # Form Handling

        def _POST_email(self, request):
            form = self._email_form()
            return form.validate(request, self.html, self.thanks)

        def _POST_domain(self, request):
            form = self._domain_form()
            return form.validate(request, self.html, self.thanks)

        ##
        # GET, POST, templating and thanks

        @resource.GET()
        def GET(self, request):
            return self.html(request)

        @resource.POST()
        def POST(self, request):
            handlers = {'email': self._POST_email, 'domain': self._POST_domain}
            return handlers[formish.form_in_request(request)](request)

        @templating.page('forms.html')
        def html(self, request, form=None):
            form_name = formish.form_in_request(request)
            form = {form_name: form}
            if form_name is not 'email':
                form['email'] = self._email_form()
            if form_name is not 'domain':
                form['domain'] = self._domain_form()
            return {'forms': forms}

        @templating.page('thanks.html')
        def thanks(self, request, data):
            pass

We could simplify this further, although I’m not sure this is quite as readable..

    class Root(resource.Resource):

        def form(self,name):
            if name is 'email':
                return formish.Form( ('email', schemaish.String()), name='email' )
            if name is 'domain':
                return formish.Form( ('domain', schemaish.String()), name='domain' )

        @resource.GET()
        def GET(self, request):
            return self.html(request)

        @resource.POST()
        def POST(self, request):
            form_name = formish.form_in_request(request)
            return self.form(name).validate(request, self.html, self.thanks)

        @templating.page('forms.html')
        def html(self, request, form=None):
            form_name = formish.form_in_request(request)
            form = {form_name: form}
            # Check each form, if it isn't the one passed in then fetch it.
            for f in ['email','domain']:
                if form_name is not f:
                    form[f] = self.form(f)
            return {'forms': forms}

        @templating.page('thanks.html')
        def thanks(self, request, data):
            pass

### Navigation

- index
- previous |
- Restish v1 documentation »