The power of root

Flask - Página de Contato

seg 25 maio 2015 flask / python / programação /

Seguindo o post anterior sobre flask, vamos desenvolver uma paǵina de contatos. Onde será preenchido algumas informações e encaminhado um e-mail e para isso vamos usar um compelmento do flask chamado flask-wtf

Flask-WTF offers simple integration with WTForms. This integration includes optional CSRF handling for greater security.

Pare efetuar a instalação é muito simples:

pip3 install flask-wtf

Você pode encontrar informações sobre as extenções flask aqui.

Formulário

Vamos criar um módulo para chamarmos o nosso formulário, para isso seguindo a estrutura já utilizada anteriormente vamos criar um arquivo chamado app/forms.py com o seguindo conteúdo:

#!/usr/bin/python3
# -*- encoding: utf-8 -*-

from flask.ext.wtf import Form
from wtforms.fields import TextField, TextAreaField, SubmitField

class ContactForm(Form):
        name = TextField("Nome")
        email = TextField("Email")
        subject = TextField("Assunto")
        message = TextAreaField("Mensagem")
        submit = SubmitField("Enviar")

No código acima efetuamos a importação do móduco flask-wtf as funções de Form e TextField. Em seguida criamos a função chamada ContactForm com os seus devidos campos.

Vamos agora alterar o arquivo routes.py para que o mesmo possa chamar o nosso formulário. O primeiro passo é importar as funções que acabamos de criar no forms.py.

#!/usr/bin/python3
# -*- encoding: utf-8 -*-

from flask import Flask, render_template, request
from forms import ContactForm

app = Flask(__name__)

app.secret_key = 'development key'

@app.route('/')
def home():
        return render_template('home.html')

@app.route('/about')
def about():
        return render_template('about.html')

@app.route('/contact', methods=['GET', 'POST'])
def contact():
        form = ContactForm()

        if request.method == 'POST':
                return 'Formulário enviado.'

        elif request.method == 'GET':
                return render_template('contact.html', form=form)

if __name__ == '__main__':
        app.run(debug=True)

Vamos criar também o template para o nosso formulário:

{% extends "layout.html" %}

{% block content %}
  <h2>Contato</h2>
  <form action="{{ url_for('contact') }}" method=post>
    {{ form.hidden_tag() }}

    {{ form.name.label }}
    {{ form.name }}

    {{ form.email.label }}
    {{ form.email }}

    {{ form.subject.label }}
    {{ form.subject }}

    {{ form.message.label }}
    {{ form.message }}

    {{ form.submit }}
  </form>
{% endblock %}

Oque fizemos até agora foi:

  1. Ao acessar http://localhost:5000/contact é chamado a função contact().
  2. Ao executar a função contact() é enviado para o contact.html a instancia da classe ContactForm() com as informações do formulário.
  3. O html é processado e enviado de volta para o routes.py que o retorna para o html.
  4. É apresentado no browser o formulário que criamos e ao clicar em enviar o routes.py executa novamente a função contact() seguindo seu fluxo.

Vamos agora deixar nosso formulário mais bonito com os seus devidos campos configurados. Para que possamos fazer isso vamos editar nosso arquivo main.css acrescentando o seguinte conteúdo.

/* Contact form */
form label {
  font-size: 1.2em;
  font-weight: bold;
  display: block;
  padding: 10px 0;
}

form input#name,
form input#email,
form input#subject {
  width: 400px;
  background-color: #fafafa;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border: 1px solid #cccccc;
  padding: 5px;
  font-size: 1.1em;
}

form textarea#message {
  width: 500px;
  height: 100px;
  background-color: #fafafa;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border: 1px solid #cccccc;
  margin-bottom: 10px;
  padding: 5px;
  font-size: 1.1em;
}

form input#submit {
  display: block;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border:1px solid #d8d8d8;
  padding: 10px;
  font-weight:bold;
  text-align: center;
  color: #000000;
  background-color: #f4f4f4;
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f4f4), color-stop(100%, #e5e5e5));
  background-image: -webkit-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -moz-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -ms-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -o-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: linear-gradient(top, #f4f4f4, #e5e5e5);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#f4f4f4, endColorstr=#e5e5e5);
}

form input#submit:hover{
  cursor: pointer;
  border:1px solid #c1c1c1;
  background-color: #dbdbdb;
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dbdbdb), color-stop(100%, #cccccc));
  background-image: -webkit-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -moz-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -ms-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -o-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: linear-gradient(top, #dbdbdb, #cccccc);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#dbdbdb, endColorstr=#cccccc);
}

Validando o formulário

Agora que nosso formulário de contato está bonitinho, vamos validar as informações que serão inseridas em seus campos, graças ao flask-wtf que já vem com vários validadores, vamos alterar nosso forms.py e inserir esses validadores na classe ContactForm.

O primeiro validador que vamos utilizar é o mais básico, que valida apenas se o formulário contém ou não informações.

Primeiramente vamos importar os validadores do flask-wtf

from flask.ext.wtf import Form
from wtforms.fields import TextField, TextAreaField, SubmitField
from wtforms import validators, ValidationError

E em seguida vamos adicionar aos campos do formulário a validação [validators.Required()]

Ficando o arquivo forms.py assim:

#!/usr/bin/python3
# -*- encoding: utf-8 -*-

from flask.ext.wtf import Form
from wtforms.fields import TextField, TextAreaField, SubmitField
from wtforms import validators, ValidationError

class ContactForm(Form):
        name = TextField("Nome", [validators.Required()])
        email = TextField("Email", [validators.Required()])
        subject = TextField("Assunto", [validators.Required()])
        message = TextAreaField("Mensagem", [validators.Required()])
        submit = SubmitField("Enviar", [validators.Required()])

Agora que adicionamos as validações, devemos exibir para o usuário algum alerta qual algum campo não for preenchido, para isso vamos utilizar outra função do flask, o flash. Vamos começar importando essa função no arquivo routes.py

from flask import Flask, render_template, request, flash

Para tratarmos a validação vamos usar os validadores if e else alterando nosso arquivo routes.py

@app.route('/contact', methods=['GET', 'POST'])
def contact():
  form = ContactForm()

  if request.method == 'POST':
    if form.validate() == False:
      flash('Todos os campos são obrigatórios.')
      return render_template('contact.html', form=form)
    else:
      return 'Formulário enviado.'

  elif request.method == 'GET':
    return render_template('contact.html', form=form)

E para que a função flash tenha efeito, devemos editar nosso arquivo contact.html e acrescentar o código para apresentar a mensagem de erro.

{% for message in get_flashed_messages() %}
  <div class="flash">{{ message }}</div>
{% endfor %}

Nosso arquivo contact.html

{% extends "layout.html" %}

{% block content %}
  <h2>Contato</h2>

  {% for message in get_flashed_messages() %}
    <div class="flash">{{ message }}</div>
  {% endfor %}

  <form action="{{ url_for('contact') }}" method=post>
    {{ form.hidden_tag() }}

    {{ form.name.label }}
    {{ form.name }}

    {{ form.email.label }}
    {{ form.email }}

    {{ form.subject.label }}
    {{ form.subject }}

    {{ form.message.label }}
    {{ form.message }}

    {{ form.submit }}
  </form>
{% endblock %}

E finalmente editar nosso arquivo main.css

/* Message flashing */
.flash {
  background-color: #FBB0B0;
  padding: 10px;
  width: 400px;
}

Ok, até agora estamos validando se todos os campos foram preenchidos e caso algum campo ficar sem informações retorna um alerta, podemos melhorar um pouco mais, retornando qual campo está com problema.

Pra isso vamos primeiro editar nosso arquivo forms.py e acrescentar na validação uma mensagem caso retorne erro, e no campo do e-mail vamos validar se o dado inserido é realmente um e-mail.

#!/usr/bin/python3
# -*- encoding: utf-8 -*-

from flask.ext.wtf import Form
from wtforms.fields import TextField, TextAreaField, SubmitField
from wtforms import validators, ValidationError

class ContactForm(Form):
        name = TextField("Nome",  [validators.Required("Porfavor, ensira um nome.")])
        email = TextField("Email",  [validators.Required("Porfavor, ensira um endereço de email."), validators.Email("Porfavor, insira um endereço de email válido.")])
        subject = TextField("Assunto",  [validators.Required("Porfavor, insira um assunto.")])
        message = TextAreaField("Message",  [validators.Required("Porfavor, insira uma mensagem.")])
        submit = SubmitField("Enviar")

Agora que estamos tratando cada erro, vamos modificar nosso contact.html para carregar tais erros se necessário acrescentando o seguinte código:

{% for message in form.name.errors %}
  <div class="flash">{{ message }}</div>
{% endfor %}

{% for message in form.email.errors %}
  <div class="flash">{{ message }}</div>
{% endfor %}

{% for message in form.subject.errors %}
  <div class="flash">{{ message }}</div>
{% endfor %}

{% for message in form.message.errors %}
  <div class="flash">{{ message }}</div>
{% endfor %}

Flask-Mail

Finalmente vamos configurar nosso formulário para ser enviador por e-mail utilizando o flask-mail. A instalação do complemento segue o mesmo padrão que utilizamos até agora vamos instalá-lo

pip3 install flask-mail

Agora vamos fazer a importação do módulo e suas configurações:

from flask import Flask, render_template, request, flash
from forms import ContactForm
from flask.ext.mail import Message, Mail

mail = Mail()

app = Flask(__name__)

app.secret_key = 'development key'

app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_PORT"] = 465
app.config["MAIL_USE_SSL"] = True
app.config["MAIL_USERNAME"] = 'contact@example.com'
app.config["MAIL_PASSWORD"] = 'your-password'

mail.init_app(app)

E por final, vamos alterar a parte do código referente ao formulário no arquivo routes.py :

@app.route('/contact', methods=['GET', 'POST'])
def contact():
        form = ContactForm()

        if request.method == 'POST':

                if form.validate() == False:
                        flash('All fields are required.')
                        return render_template('contact.html', form=form)
                else:
                        msg = Message(form.subject.data, sender='contact@example.com', recipients=['your_email@example.com'])
                        msg.body = """
                        From: %s <%s>
                        %s
                        """ % (form.name.data, form.email.data, form.message.data)
                        mail.send(msg)

                        return render_template('contact.html', success=True)

        elif request.method == 'GET':
                return render_template('contact.html', form=form)

Na linha 10 inserimos a variável onde será armazenado a mensage e nas linhas 11 a 14 as configurações do e-mail, na linha 17 configuramos para evinar uma mensagem de sucesso ao contact.html.

Vamos editar nosso arquivo contact.html também, inserindo nele as condições if e else com o uso do jinja2.

{% extends "layout.html" %}

{% block content %}
  <h2>Contato</h2>

  {% if success %}
    <p>Obrigado por sua mensagem.</p>

  {% else %}

    {% for message in form.name.errors %}
      <div class="flash">{{ message }}</div>
    {% endfor %}

    {% for message in form.email.errors %}
      <div class="flash">{{ message }}</div>
    {% endfor %}

    {% for message in form.subject.errors %}
      <div class="flash">{{ message }}</div>
    {% endfor %}

    {% for message in form.message.errors %}
      <div class="flash">{{ message }}</div>
    {% endfor %}

    <form action="{{ url_for('contact') }}" method=post>
      {{ form.hidden_tag() }}

      {{ form.name.label }}
      {{ form.name }}

      {{ form.email.label }}
      {{ form.email }}

      {{ form.subject.label }}
      {{ form.subject }}

      {{ form.message.label }}
      {{ form.message }}

      {{ form.submit }}
    </form>

  {% endif %}
{% endblock %}

Para finalizar, vamos editar nosso arquivo layout.html e inserir no menú o botão para contato.

<!DOCTYPE html>
<html>
  <head>
<title>Flask</title>
  <strong><link rel="stylesheet" href="{{ url_for('static',   filename='css/main.css') }}"></strong>
  </head>
  <body>
    <header>
      <div class="container">
        <h1 class="logo">Aplicação Flask</h1>
        <strong><nav>
          <ul class="menu">
            <li><a href="{{ url_for('home') }}">Home</a></a></li>
            <li><a href="{{ url_for('about') }}">Sobre</a></li>
            <li><a href="{{ url_for('contact') }}">Contato</a></li>
          </ul>
        </nav>
        </strong>
      </div>
    </header>

    <div class="container">
      {% block content %}
      {% endblock %}
    </div>
  </body>
</html>

Em fim temos nosso formulário de contato funcionando.

on the top

Comments