oscarmlage oscarmlage

Pyramid: 6 - Forms (simpleform)

Written by oscarmlage on

Aunque hasta ahora es cierto que hemos creado un model (bueno, dos), una view y una template, hemos configurado el root context de la aplicación y sabemos más o menos cómo funciona y cómo movernos por ella, de momento no hemos interactuado demasiado con el ZODB, nos falta agregar datos a ese modelo Twitts que creamos en su día y, obviamente, mostrarlos.

Para agregar datos necesitamos un formulario que mapee el modelo twitt en html y que el usuario pueda interactuar con él. Y aquí es donde entra en escena pyramid_simpleform. Como su nombre indica, se trata de una librería de validación y render de formularios que deberemos instalar en nuestro entorno:

$ pip install pyramid_simpleform

Una vez instalada ya podemos crear los formularios correspondientes. Para ello y por seguir alguna convención, usaremos el directorio schemas/, así que creamos dicho directorio, colocamos en él un __init__.py y, en principio, vamos a crear el formulario correspondiente al modelo twitt: twitt.py

# -*- coding: utf-8 -*-

from formencode import Schema, validators

class TwittSchema(Schema):

    allow_extra_fields = True
    filter_extra_fields = True

    twitt = validators.UnicodeString(max=140)

Definido el schema del form, vamos a usarlo en una view, necesitamos importar las clases correspondientes, crear una instancia de ese formulario en base al esquema y pasarlo a template para renderizarlo en html:

# views/__init__.py
from pyramid_simpleform import Form, State
from pyramid_simpleform.renderers import FormRenderer
from src.schemas.twitt import TwittSchema
...
def homepage(context, request):
...
    form = Form(request, schema=TwittSchema, multipart=True)
    ....
    return {'form': FormRenderer(form),
            'title': 'PyTwitter',
            'description': 'Our twitter clon, with Pyramid'}

En nuestro index.pt agregamos el formulario propiamente dicho y ya debería aparecer algo parecido a lo siguiente:

    # templates/index.pt
    <title$>{title}</title>
    <p>${description}</p>
    <hr />
    ${form.begin()}
        ${form.text('twitt')}
        ${form.errorlist('twitt')}
        ${form.submit('submit', 'Submit')}
    ${form.end()}

Ahora tan solo nos queda la segunda parte, recoger los datos por POST y agregarlos persistentemente a nuestra ZODB. Para ello comprobamos en view si existe algún dato request.POST y si valida adecuadamente. Finalmente llamaremos al método add_twitt() del context para que lo agregue a la base de datos:

    # views/__init__.py
    if 'submit' in request.POST and form.validate():
        twitt = form.bind(Twitt())
        twitt.published = datetime.today()
        context.add_twitt(twitt)
    # models/rootfolder.py
    def add_twitt(self, twitt):
        self.add(str(twitt.tid), twitt)

Y por último, si queremos sacar todos los twitts que hemos guardado, llamaremos a un método del model que nos los devuelva y el procedimiento es el mismo siempre, pasarlos a template para pintarlos:

    # models/rootfolder.py
    @property
    def index(self):
        return [t for t in self.values() if isinstance(t, Twitt)]
    # views/__init__.py
    ...
    twitts = context.index
    ...
    return {'form': FormRenderer(form),
            'twitts': twitts,
            'title': 'PyTwitter',
            'description': 'Our twitter clon, with Pyramid'}
    # templates/index.pt
    <hr />
    <ul>
        <li tal:repeat="twit twitts">${twit.twitt} (${twit.published})</li>
    </ul>

Ahora sí que tenemos nuestra primera interacción con ZODB completa y funcional. Ya podemos agregar nuevos twitts y ver el listado de los mismos. Ahora faltaría, de alguna forma, ponerlo un poco más bonito. En la próxima entrada hablaremos de bootstrap, fontawesomebower y webassets.