Anda di halaman 1dari 9

Flask Web Forms

Part 3

Recap
En el captulo anterior de la serie definimos una plantilla simple para la pgina de inicio y usamos
objetos falsos como marcadores de posicin para cosas que todava no tenemos, como los usuarios o
las entradas de blog.

En este artculo vamos a llenar uno de los muchos agujeros que todava tenemos en nuestra aplicacin,
vamos a ver cmo trabajar con formularios web.

Los formularios Web son uno de los bloques de construccin ms bsicos en cualquier aplicacin web.
Estaremos usando formularios para permitir a los usuarios escribir publicaciones en el blog, y tambin
para ingresar a la aplicacin.

Para seguir este captulo a lo largo de lo que necesita para tener la aplicacin microblog como lo
dejamos al final del captulo anterior. Asegrate de que la aplicacin est instalada y en ejecucin.

Configuracin
Para manejar nuestros formularios web vamos a utilizar la extensin Flask-WTF, que a su vez envuelve
el proyecto WTForms de una manera que se integra muy bien con las aplicaciones de Flask.
Muchas extensiones de Flask requieren una cierta cantidad de configuracin, por lo que vamos a
configurar un archivo de configuracin dentro de nuestra carpeta raz de microblog para que sea
fcilmente accesible si necesita ser editado. Aqu es lo que vamos a comenzar con (archivo config.py):
WTF_CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'

Bastante simple, es slo dos configuraciones que nuestra extensin Flask-WTF necesita. El parmetro
WTF_CSRF_ENABLED activa la prevencin de falsificacin de solicitudes entre sitios (tenga en
cuenta que esta configuracin est habilitada de forma predeterminada en las versiones actuales de
Flask-WTF). En la mayora de los casos, desea habilitar esta opcin, ya que hace que su aplicacin sea
ms segura.
La configuracin SECRET_KEY slo es necesaria cuando se habilita CSRF y se utiliza para crear un
token criptogrfico que se utiliza para validar un formulario. Cuando escribe sus propias aplicaciones
asegrese de establecer la clave secreta para algo que es difcil de adivinar.

Ahora que tenemos nuestro archivo de configuracin necesitamos decirle a Flask que lo lea y lo use.
Podemos hacerlo justo despus de crear el objeto Flask app, como se muestra a continuacin (file app /
__ init__.py):
from flask import Flask

app = Flask(__name_
app.config.from_object(config)

from app import route

The user login form


Los formularios Web se representan en Flask-WTF como clases, subclasificadas de la clase base Form.
Una subclase de formulario simplemente define los campos del formulario como variables de clase.

Ahora crearemos un formulario de inicio de sesin que los usuarios usarn para identificarse con el
sistema. El mecanismo de inicio de sesin que vamos a apoyar en nuestra aplicacin no es el tipo de
usuario / contrasea estndar, haremos que nuestros usuarios inicien sesin con su OpenID. Los
OpenIDs tienen el beneficio de que la autenticacin sea realizada por el proveedor de OpenID, por lo
que no tenemos que validar contraseas, lo que hace que nuestro sitio sea ms seguro para nuestros
usuarios.

El inicio de sesin OpenID slo requiere una cadena, la llamada OpenID. Tambin lanzaremos una
casilla de verificacin "Recurdeme" en el formulario, para que los usuarios puedan elegir tener una
cookie instalada en sus navegadores que recuerde su inicio de sesin cuando regresen.

Escribamos nuestro primer formulario (file app/forms.py):


from flask_wtf import Form
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired

class LoginForm(Form):
openid = StringField('openid', validators=[DataRequired()])
remember_me = BooleanField('remember_me', default=False)

Creo que la clase es bastante auto-explicativo. Hemos importado la clase Form, y las dos clases de
campo de formulario que necesitamos, StringField y BooleanField.

La importacin DataRequired es un validador, una funcin que se puede adjuntar a un campo para
realizar la validacin en los datos enviados por el usuario. El validador DataRequired simplemente
comprueba que el campo no se enva vaco. Hay muchos ms validadores incluidos con Flask-WTF,
vamos a utilizar un poco ms en el futuro.

Form templates
Tambin necesitaremos una plantilla que contenga el HTML que produzca el formulario. La buena
noticia es que la clase LoginForm que acabamos de crear sabe cmo renderizar campos de formulario
como HTML, as que solo necesitamos concentrarnos en el diseo. Aqu est nuestra plantilla de inicio
de sesin (archivo app / templates / login.html):

<!-- extend from base layout -->


{% extends "base.html" %}

{% block content %}
<h1>Sign In</h1>
<form action="" method="post" name="login">
{{ form.hidden_tag() }}
<p>
Please enter your OpenID:<br>
{{ form.openid(size=80) }}<br>
</p>
<p>{{ form.remember_me }} Remember Me</p>
<p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}

Tenga en cuenta que en esta plantilla estamos reutilizando la plantilla base.html a travs de la sentencia
de herencia de plantilla extends. Realmente haremos esto con todas nuestras plantillas, para asegurar un
diseo consistente en todas las pginas.

Hay algunas diferencias interesantes entre un formulario HTML regular y nuestra plantilla. Esta
plantilla espera un objeto de formulario instanciado de la clase de formulario que acabamos de definir
almacenada en un argumento de plantilla denominado form. Nos encargaremos de enviar este
argumento de plantilla a la plantilla siguiente, cuando escribamos la funcin de vista que procesa esta
plantilla.

El argumento de la plantilla form.hidden_tag () ser reemplazado por un campo oculto que implementa
la prevencin CSRF que hemos habilitado en la configuracin. Este campo debe estar en todos sus
formularios si tiene habilitado CSRF. La buena noticia es que Flask-WTF lo maneja para nosotros, slo
necesitamos asegurarnos de que est incluido en el formulario.

Los campos reales de nuestro formulario son representados por los objetos de campo, solo necesitamos
referirnos a un argumento de plantilla {{form.field_name}} en el lugar donde se debe insertar cada
campo. Algunos campos pueden tomar argumentos. En nuestro caso, estamos pidiendo que el campo de
texto genere nuestro campo openid con un ancho de 80 caracteres.

Puesto que no hemos definido el botn de envo en la clase de formulario, tenemos que definirlo como
un campo regular. El campo Enviar no contiene datos, por lo que no necesita definirse en la clase de
formulario.

Form views
El paso final antes de que podamos ver nuestro formulario es codificar una funcin de vista que
procesa la plantilla.
Esto es realmente muy simple ya que slo necesitamos pasar un objeto de formulario a la plantilla. Esta
es nuestra nueva funcin de vista (file app / route.py||views.py):

from flask import render_template, flash, redirect


from app import app
from .forms import LoginForm

# Funcin de vista de ndice suprimida por brevedad

@app.route('/login', methods=['GET', 'POST'])


def login():
form = LoginForm()
return render_template('login.html',
title='Sign In',
form=form)

As que, bsicamente, hemos importado nuestra clase de LoginForm, instanciado un objeto de ella, y
enviado a la plantilla. Esto es todo lo que se requiere para obtener los campos de formulario
procesados.

Ignoremos por ahora las importaciones de flash y redirigir. Los utilizaremos un poco ms tarde.

La nica otra cosa que es nueva aqu es el argumento de methods en el decorador de ruta. Esto le dice a
Flask que esta funcin de vista acepta las solicitudes GET y POST. Sin esto, la vista slo aceptar
solicitudes GET. Queremos recibir las solicitudes POST, stas son las que traern en la forma datos
introducidos por el usuario.

En este punto, puedes probar la aplicacin y ver el formulario en tu navegador web. Despus de iniciar
la aplicacin, deber abrir http: // localhost: 5000 / login en su navegador web, ya que esta es la ruta
que hemos asociado con la funcin de vista de inicio de sesin.

No hemos codificado la parte que acepta datos todava, de modo que pulsar el botn Enviar no tendr
ningn efecto en este momento.

Recepcin de datos de formulario


Otra rea donde Flask-WTF hace nuestro trabajo realmente fcil es en el manejo de los datos del
formulario enviado. Esta es una versin actualizada de nuestra funcin de vista de inicio de sesin que
valida y almacena los datos del formulario (archivo app / views.py):

@app.route('/login', methods=['GET', 'POST'])


def login():
form = LoginForm()
if form.validate_on_submit():
flash(Login requested for OpenIDS=%s, remember_me=%s %
(form.openid.data, str(form.remember_me.data)))
return redirect(/index)
return render_template('login.html',
title='Sign In',
form=form)
El mtodo validate_on_submit hace todo el trabajo de procesamiento de
formularios. Si lo llama cuando el formulario se presenta al usuario
(es decir, antes de que el usuario tenga la oportunidad de introducir
datos en l), a continuacin, devolver False, por lo que en ese caso
usted sabe que tiene que hacer la plantilla.

Cuando validate_on_submit es llamado como parte de una solicitud de envo de formularios, reunir
todos los datos, ejecutar todos los validadores adjuntos a los campos, y si todo est bien, devolver
True, indicando que los datos son vlidos y se pueden procesar. Esta es su indicacin de que estos datos
son seguros de incorporar a la aplicacin.

Si al menos un campo falla la validacin entonces la funcin devolver False y que har que el
formulario sea devuelto al usuario, y esto le dar al usuario la oportunidad de corregir cualquier error.
Ms adelante veremos cmo mostrar un mensaje de error cuando la validacin falla.

Cuando validate_on_submit devuelve True nuestra funcin de vista de inicio llama a dos nuevas
funciones, importadas de Flask. La funcin de flash es una forma rpida de mostrar un mensaje en la
siguiente pgina presentada al usuario. En este caso lo usaremos para la depuracin, ya que no
disponemos de toda la infraestructura necesaria para ingresar a los usuarios todava, en su lugar
simplemente mostraremos un mensaje que muestre los datos enviados. La funcin flash tambin es
extremadamente til en los servidores de produccin para proporcionar retroalimentacin al usuario
con respecto a una accin.

Los mensajes destellados no aparecern automticamente en nuestra pgina, nuestras plantillas


necesitan mostrar los mensajes de una manera que funcione para el diseo del sitio. Vamos a agregar
estos mensajes a la plantilla base, para que todas nuestras plantillas hereden esta funcionalidad. Esta es
la plantilla base actualizada (archivo app / templates / base.html):

<html>
<head>
{% if title %}
<title>{{ title }} - microblog</title>
{% else %}
<title>microblog</title>
{% endif %}
</head>
<body>
<div>Microblog: <a href="/index">Home</a></div>
<hr>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }} </li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
La tcnica para mostrar el mensaje flashado es esperanzadamente auto-
explicativo. Una propiedad interesante de los mensajes flash es que
una vez que se solicitan a travs de la funcin get_flashed_messages
se eliminan de la lista de mensajes, por lo que estos mensajes
aparecen en la primera pgina solicitada por el usuario despus de
llamar a la funcin flash y luego desaparecen.

La otra funcin nueva que utilizamos en nuestra vista de inicio de


sesin es redirect. Esta funcin indica al navegador web del cliente
que navegue a una pgina diferente en lugar de la solicitada. En
nuestra funcin de vista lo usamos para redirigir a la pgina de
ndice que desarrollamos en captulos anteriores. Tenga en cuenta que
los mensajes flash se mostrarn incluso si una funcin de vista
termina en un redireccionamiento.

Este es un buen momento para iniciar la aplicacin y probar cmo


funciona el formulario. Asegrese de intentar enviar el formulario
con el campo openid vaco, para ver cmo el validador DataRequired
detiene el proceso de envo.

Mejora de la validacin de campo


Con la aplicacin en su estado actual, los formularios que se enven
con datos no vlidos no se aceptarn. En su lugar, el formulario se
presentar de nuevo al usuario para corregir. Esto es exactamente lo
que queremos.

Lo que nos falta es una indicacin al usuario de lo que est mal con
el formulario. Afortunadamente, Flask-WTF tambin hace que esto sea
una tarea fcil.

Cuando un campo falla la validacin Flask-WTF aade un mensaje de


error descriptivo al objeto de formulario. Estos mensajes estn
disponibles para la plantilla, por lo que slo tenemos que aadir un
poco de lgica que los procesa.

Aqu est nuestra plantilla de inicio de sesin con mensajes de


validacin de campo (archivo app / templates / login.html):

<!-- extend base layout -->

{% extends "base.html" %}

{% block content %}
<h1>Sign In</h1>
<form action="" method="post" name="login">
{{ form.hidden_tag() }}
<p>
Please enter your OpenID:<br>
{{ form.openid(size=80) }}<br>
{% for error in form.openid.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}<br>
</p>
<p>{{ form.remember_me }} Remember Me</p>
<p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}

El nico cambio que hemos hecho es agregar un bucle for que muestra
cualquier mensaje agregado por los validadores debajo del campo
openid. Como regla general, cualquier campo que tenga validadores
adjuntos tendr errores aadidos bajo form.field_name.errors. En
nuestro caso usamos form.openid.errors. Mostramos estos mensajes en
un estilo rojo para llamar la atencin del usuario.

Tratamiento de OpenIDs
En la prctica, encontraremos que muchas personas ni siquiera saben
que ya tienen unos pocos OpenIDs. No es bien sabido que un nmero de
proveedores de servicios importantes en Internet admiten la
autenticacin OpenID para sus miembros. Por ejemplo, si tiene una
cuenta en Google, tiene un OpenID con ellos. Asimismo, con Yahoo,
AOL, Flickr y muchos otros proveedores. (Actualizacin: Google est
cerrando su servicio OpenID el 15 de abril de 2015).

Para facilitar a los usuarios el acceso a nuestro sitio con uno de


estos OpenID comnmente disponibles, agregaremos enlaces a una lista
corta de ellos, para que el usuario no tenga que escribir el OpenID a
mano.

Comenzaremos definiendo la lista de proveedores de OpenID que


queremos presentar. Podemos hacer esto en nuestro archivo de
configuracin (archivo config.py):

WTF_CSRF_ENABLED = True #Se cambio solamente a CSRF_ENABLED

SECRET_KEY = 'you-will-never-guess'

OPENID_PROVIDERS = [
{'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id'},
{'name': 'Yahoo', 'url': 'https://me.yahoo.com'},
{'name': 'AOL', 'url': 'http://openid.aol.com/<username>'},
{'name': 'Flickr', 'url': 'http://www.flickr.com/<username>'},
{'name': 'MyOpenID', 'url': 'https://www.myopenid.com'}]

Ahora vamos a ver cmo usamos esta matriz en nuestra funcin de vista
de inicio de sesin:

@app.route('/login', methods=['GET', 'POST'])


def login():
form = LoginForm()
if form.validate_on_submit():
flash(Login requested for OpenIDS=%s, remember_me=%s %
(form.openid.data, str(form.remember_me.data)))
return redirect(/index)
return render_template('login.html',
title='Sign In',
form=form,
providers=app.config[OPENID_PROVIDERS)

Aqu tomamos la configuracin buscando en app.config con su clave. A


continuacin, se agrega la matriz a la llamada render_template como
argumento de plantilla.

Como estoy seguro que adivin, tenemos un paso ms que se debe hacer
con esto. Ahora necesitamos especificar cmo nos gustara hacer que
estos enlaces de proveedores en nuestra plantilla de inicio de sesin
(archivo app / templates / login.html):
<!-- extend base layout -->
{% extends "base.html" %}

{% block content %}
<script type="text/javascript">
function set_openid(openid, pr)
{
u = openid.search('<username>')
if (u != -1) {
// openid requires username
user = prompt('Enter your ' + pr + ' username:')
openid = openid.substr(0, u) + user
}
form = document.forms['login'];
form.elements['openid'].value = openid
}
</script>
<h1>Sign In</h1>
<form action="" method="post" name="login">
{{ form.hidden_tag() }}
<p>
Please enter your OpenID, or select one of the providers below:<br>
{{ form.openid(size=80) }}
{% for error in form.openid.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}<br>
|{% for pr in providers %}
<a href="javascript:set_openid('{{ pr.url }}',
'{{ pr.name }}');">{{ pr.name }}</a> |
{% endfor %}
</p>
<p>{{ form.remember_me }} Remember Me</p>
<p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}

La plantilla tuvo algo de tiempo con este cambio. Algunos OpenIDs


incluyen el nombre de usuario del usuario, por lo que para aquellos
que tenemos que tener un poco de magia javascript que pide al usuario
el nombre de usuario y luego compone el OpenID con l. Cuando el
usuario hace clic en un enlace de proveedor OpenID y (opcionalmente)
introduce el nombre de usuario, se inserta el cdigo OpenID para ese
proveedor en el campo de texto.

A continuacin se muestra una captura de pantalla de nuestra pantalla


de inicio de sesin despus de hacer clic en el enlace de Google
OpenID:
Ultimas palabras

Aunque hemos hecho un gran progreso con nuestro formulario de inicio


de sesin, en realidad no hemos hecho nada para ingresar usuarios en
nuestro sistema, todo lo que hemos hecho hasta ahora tiene que ver
con los aspectos de GUI del proceso de inicio de sesin. Esto es
porque antes de que podamos hacer logins reales necesitamos tener una
base de datos donde podamos grabar a nuestros usuarios.

Anda mungkin juga menyukai