├── imagens ├── CMD.png ├── Avatar.png ├── Tabelas.png ├── FlaskLogo.png ├── HTMLForm.png └── FlaskTemplate.png ├── LICENSE ├── README.md └── capitulos ├── Referências.md ├── Arquivos Static.md ├── Intro_Flask.md ├── Banco de Dados.md ├── Flask.md ├── Templates.md └── Formulários Web.md /imagens/CMD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/CMD.png -------------------------------------------------------------------------------- /imagens/Avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/Avatar.png -------------------------------------------------------------------------------- /imagens/Tabelas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/Tabelas.png -------------------------------------------------------------------------------- /imagens/FlaskLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/FlaskLogo.png -------------------------------------------------------------------------------- /imagens/HTMLForm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/HTMLForm.png -------------------------------------------------------------------------------- /imagens/FlaskTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/FlaskTemplate.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gabriel Felippe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Programação Web com Flask

2 | 3 |

4 | Python
5 |

6 | 7 |

8 | Este guia tem como objetivo ensinar Programação Web com Python através do microframework Flask 9 |

10 | 11 | ### Conteúdo 12 | 13 | 01. [Introdução](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Flask.md) 14 | 02. [Templates](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Templates.md) 15 | 03. [Arquivos Static](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Arquivos%20Static.md) 16 | 04. [Formulários Web](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Formul%C3%A1rios%20Web.md) 17 | 05. [Banco de Dados](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Banco%20de%20Dados.md) 18 | 06. [Guia Rápido](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Intro_Flask.md) 19 | 07. [Referências](https://github.com/the-akira/Flask-Programacao-Web/blob/master/capitulos/Refer%C3%AAncias.md) -------------------------------------------------------------------------------- /capitulos/Referências.md: -------------------------------------------------------------------------------- 1 | # Referências 2 | 3 | - [Flask](https://flask.palletsprojects.com/en/1.1.x/) | EN 4 | - [Make a Web App Using Python & Flask](https://aryaboudaie.com/python/technical/educational/web/flask/2018/10/17/flask.html) | EN 5 | - [Flask SQLAlchemy Tutorial](https://kite.com/blog/python/flask-sqlalchemy-tutorial/) | EN 6 | - [Flask (Wikipedia)](https://en.wikipedia.org/wiki/Flask_(web_framework)) | EN 7 | - [Flask Tutorial](http://www.patricksoftwareblog.com/flask-tutorial/) | EN 8 | - [Explore Flask](https://exploreflask.com/en/latest/index.html) | EN 9 | - [Flask 101](http://www.blog.pythonlibrary.org/tag/flask/) | EN 10 | - [Full Stack Python](https://www.fullstackpython.com/flask.html) | EN 11 | - [Real Python](https://realpython.com/tutorials/flask/) | EN 12 | - [The Flask Mega-Tutorial](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world) | EN 13 | - [Websites with Python Flask](https://opentechschool.github.io/python-flask/) | EN 14 | - [SQLAlchemy + Flask Tutorial](https://docs.graphene-python.org/projects/sqlalchemy/en/latest/tutorial/) | EN 15 | - [How to Flask](http://www.cs.fsu.edu/~jayarama/pythonsu18/Slides/Flask.pdf) | EN 16 | - [Flask Reddit Community](https://www.reddit.com/r/flask/) | EN 17 | - [Building Python-based, database-driven web applications](http://jonathansoma.com/tutorials/flask-sqlalchemy-mapbox/index.html) | EN 18 | - [Developing Web Applications with Flask](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/Python3_Flask.html) | EN 19 | - [Learn Flask for Python](https://www.youtube.com/watch?v=Z1RJmh_OqeA) | EN 20 | - [Flask Tutorials](https://www.youtube.com/watch?v=MwZwr5Tvyxo&list=PL-osiE80TeTs4UjLw5MM6OjgkjFeUxCYH) | EN 21 | - [REST API with Flask & SQLAlchemy](https://www.youtube.com/watch?v=PTZiDnuC86g) | EN 22 | - [Learning Flask](https://www.youtube.com/watch?v=BUmUV8YOzgM&list=PLF2JzgCW6-YY_TZCmBrbOpgx5pSNBD0_L) | EN 23 | - [Python Flask from Scratch](https://www.youtube.com/watch?v=zRwy8gtgJ1A&list=PLillGF-RfqbbbPz6GSEM9hLQObuQjNoj_) | EN 24 | - [Web Programming with Flask](https://www.youtube.com/watch?v=zdgYw-3tzfI) | EN 25 | - [Python Web Apps with Flask](https://www.youtube.com/watch?v=qla-KaMF-2Q) | EN 26 | - [Flask for Beginners Tutorial](https://www.youtube.com/watch?v=EnJKHVEzHFw) | EN 27 | - [Flask Tutorials](https://www.youtube.com/playlist?list=PLzMcBGfZo4-n4vJJybUVV3Un_NFS5EOgX) | EN -------------------------------------------------------------------------------- /capitulos/Arquivos Static.md: -------------------------------------------------------------------------------- 1 | # Arquivos Static 2 | 3 | ## Introdução 4 | 5 | Os **Arquivos Static**, como seus nomes sugerem, são arquivos que não mudam, **estáticos**. Aplicações Web geralmente precisam servir esses arquivos, que seriam **imagens**, arquivos **Javascript** e **CSS**. 6 | 7 | Para trabalharmos com esses arquivos precisaremos criar um diretório chamado `static` dentro de nosso diretório principal que chamamos de `Exemplos`. Dentro do diretório `static` que criamos, vamos criar mais três diretórios respectivamente `css`, `js` e `imagens`. 8 | 9 | ### CSS 10 | 11 | No diretório `css` vamos criar um arquivo `style.css` com o seguinte conteúdo: 12 | 13 | ```css 14 | body { 15 | background-color: gray; 16 | color: white; 17 | } 18 | ``` 19 | 20 | Veja que alteramos o fundo de Aplicação para a cor cinza e também alteramos a cor das fontes para branco, um estilo simples para testarmos. 21 | 22 | ### Javascript 23 | 24 | Agora vamos criar dentro do diretório `js` um arquivo chamado `main.js` com o seguinte conteúdo: 25 | 26 | ```javascript 27 | alert('Hello World') 28 | ``` 29 | 30 | Veja que é apenas um simples **script** que exibe um alerta 'Hello World'. 31 | 32 | ### Imagens 33 | 34 | Agora vamos obter o logo do Flask: 35 | 36 | ![img](https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/FlaskLogo.png) 37 | 38 | Vamos salvá-lo em nosso diretório `imagens`. 39 | 40 | ### Estrutura 41 | 42 | A estrutura de nosso diretório static ficou dessa forma: 43 | 44 | ``` 45 | static 46 | ├── css 47 | │   └── style.css 48 | ├── imagens 49 | │   └── flask-logo.png 50 | └── js 51 | └── main.js 52 | ``` 53 | 54 | ## Servindo os Arquivos Static 55 | 56 | Agora em nossa aplicação, vamos editar o arquivo `app.py` de forma que possamos servir esses **arquivos static**, para isso vamos criar uma nova rota de exemplo. 57 | 58 | ```python 59 | @app.route('/static') 60 | def arquivos_static(): 61 | return render_template('static.html') 62 | ``` 63 | 64 | Veja que é apenas uma simples rota para teste, agora vamos criar um arquivo `static.html` dentro do diretório `templates` para que possamos servir o conteúdo estático. Nosso arquivo `static.html` contará com o seguinte conteúdo: 65 | 66 | ```html 67 | {% extends 'layout.html' %} 68 | 69 | {% block conteudo %} 70 | 71 |

Arquivos Static

72 | 73 | 74 | {% endblock %} 75 | ``` 76 | 77 | Veja que estamos utilizando o conceito de Herança, em outras palavras, estamos herdando as propriedades de nosso layout principal e nosso conteúdo está contido dentro do `{% block conteudo %}`. 78 | 79 | Através da função **url_for()** estamos buscando dentro do diretório **static** nossos arquivos. Primeiramente carregamos o **CSS** que se encontra em `css/style.css`, depois carregamos nossa imagem que está contida em `imagens/flask.png` e por fim nosso script que se encontra em `js/main.js`. 80 | 81 | Agora podemos executar nossa aplicação através do comando `python app.py` e navegar até `http://127.0.0.1:5000/static` para vermos as alterações em nossa aplicação. 82 | 83 | Caso deseje experimentar com o código em tempo real: https://repl.it/@theakira/Flask-Static 84 | 85 | ## Sumarizando 86 | 87 | Nesse capítulo aprendemos como gerenciar e servir nossos arquivos static, podemos também observar que Flask torna muito fácil trabalharmos com esses arquivos. 88 | 89 | Caso você queira optar por utilizar uma **[CDN](https://www.webopedia.com/TERM/C/CDN.html)** para servir os seus arquivos static de uma forma mais eficiente, você pode checar este interessante **[Tutorial](https://www.digitalocean.com/community/tutorials/using-a-cdn-to-speed-up-static-content-delivery)** 90 | 91 | Agora que já temos o domínio dos Arquivos Static podemos começar a utilizar Formulários para capturar dados dos usuários de nossa aplicação. -------------------------------------------------------------------------------- /capitulos/Intro_Flask.md: -------------------------------------------------------------------------------- 1 | # Flask Referência 2 | 3 | Flask é um **microframework** [WSGI](https://wsgi.readthedocs.io/) para desenvolvimento de aplicações web. É projetado para você começar desenvolvendo rápido e com facilidade. Com a possibilidade de escalar em aplicações complexas, sua história começou como um simples *wrapper* sob [Werkzeug](https://palletsprojects.com/p/werkzeug) e [Jinja](https://palletsprojects.com/p/jinja) e se tornou um dos frameworks Python de aplicações web mais popular. 4 | 5 | Flask oferece sugestões, porém não força nenhuma dependência ou *layout* de projeto, em outras palavras, te dá liberdade total. É importante lembrar que existem muitas extensões disponíveis para Flask, que tornam a possibilidade de adicionar novas funcionalidades em nossa aplicação muito mais fácil. 6 | 7 | - Website Oficial: [Flask](https://palletsprojects.com/p/flask/) 8 | - Documentação: [Flask Documentação](https://flask.palletsprojects.com/en/1.1.x/) 9 | 10 | ## Instalando Flask 11 | 12 | ```python 13 | pip install Flask 14 | ``` 15 | 16 | ## Aplicação Simples 17 | 18 | ```python 19 | from flask import Flask 20 | app = Flask(__name__) 21 | 22 | @app.route('/') 23 | def hello_world(): 24 | return 'Hello World' 25 | ``` 26 | 27 | ## Rotas 28 | 29 | ```python 30 | @app.route('/teste/') # exemplo.com/teste/Gabriel 31 | def teste(nome): 32 | return 'Hello ' + nome # nos retornará Hello Gabriel 33 | ``` 34 | 35 | ## Métodos Request Permitidos 36 | 37 | ```python 38 | @app.route('/teste') # Padrão, apenas permite requisições GET 39 | @app.route('/teste', methods=['GET', 'POST']) # Permite apenas os métodos GET e POST 40 | @app.route('/teste', methods=['PUT']) # Permite apenas o método PUT 41 | ``` 42 | 43 | ## Configuração 44 | 45 | ```python 46 | app.config['CONFIG_NAME'] = 'valor' # Acesso direto à configuração 47 | app.config.from_envar('NOME_ENV_VAR') # Importando de uma variável de ambiente exportada com o caminho para o arquivo 48 | ``` 49 | 50 | ## Templates 51 | 52 | ```python 53 | from flask import render_template 54 | 55 | @app.route('/') 56 | def index(): 57 | return render_template('index.html', variavel=variavel) 58 | ``` 59 | 60 | ## Respostas em JSON 61 | 62 | ```python 63 | import jsonify 64 | 65 | @app.route('/arquivojson') 66 | def arquivojson(): 67 | lista = [1,2,3,4,5] 68 | dict = {'números': lista, 'nome': 'Números'} 69 | 70 | return jsonify({'output': dict}) 71 | ``` 72 | 73 | ## Acessando Dados de Request 74 | 75 | ```python 76 | request.args['nome'] # acessando argumentos query 77 | request.form['nome'] # acessando dados de formulário 78 | request.method # tipo de requisição 79 | request.cookies.get('nome_do_cookie') # acessa dados de cookies 80 | request.session['nome'] # acessa dados sobre a sessão 81 | request.files['nome'] # acessa dados de arquivos 82 | ``` 83 | 84 | ## Redirecionando 85 | 86 | ```python 87 | from flask import url_for, redirect 88 | 89 | @app.route('/home') 90 | def home(): 91 | return render_template('home.html') 92 | 93 | @app.route('/redirecionar') 94 | def redirecionar(): 95 | return redirect(url_for('home')) 96 | ``` 97 | 98 | ## Abortando 99 | 100 | ```python 101 | from flask import abort 102 | 103 | @app.route('/') 104 | def index(): 105 | abort(404) # Retorna o erro 404 106 | render_template('index.html') # Essa linha nunca é executada 107 | ``` 108 | 109 | ## Setando Cookies 110 | 111 | ```python 112 | from flask import make_response 113 | 114 | @app.route('/') 115 | def index(): 116 | resposta = make_response(render_template('index.html')) 117 | resposta.set_cookie('nome_do_cookie', 'valor_do_cookie') 118 | return resposta 119 | ``` 120 | 121 | ## Lidando com Sessões 122 | 123 | ```python 124 | import session 125 | 126 | app.config['SECRET_KEY'] = 'qualquer string aleatória' 127 | 128 | @app.route('/login_sucesso') # Seta a sessão 129 | def login_sucesso(): 130 | session['nome_da_chave'] = 'valor_da_chave' # Guarda um cookie seguro no browser 131 | return redirect(url_for('index')) 132 | 133 | @app.route('/') # Sessão de leitura 134 | def index(): 135 | if 'nome_da_chave' in session: 136 | # Sessão existe e há uma chave 137 | session_var = session['valor_da_chave'] 138 | else: 139 | # Sessão não existe 140 | ``` 141 | 142 | ## Estruturando uma Aplicação com Blueprints 143 | 144 | A árvore seguinte representa um projeto com o nome de **projeto** 145 | 146 | ``` 147 | run.py 148 | projeto/ 149 | __init__.py 150 | config.py 151 | forms.py 152 | models.py 153 | admin/ 154 | __init__.py 155 | routes.py 156 | main/ 157 | __init__.py 158 | routes.py 159 | templates/ 160 | index.html 161 | static/ 162 | css/ 163 | style.css 164 | ``` 165 | 166 | ### Em `run.py` 167 | 168 | ```python 169 | from projeto import app 170 | 171 | if __name__ == '__main__': 172 | app.run() 173 | ``` 174 | 175 | ### Em `projeto/__init__.py` 176 | 177 | ```python 178 | from flask import Flask 179 | from project.main.routes import main 180 | from project.admin.routes import admin 181 | 182 | app = Flask(__name__) 183 | 184 | app.register_blueprint(main, url_prefix='/') 185 | app.register_blueprint(admin, url_prefix='/admin') 186 | ``` 187 | 188 | ### Em `projeto/main/routes.py` 189 | 190 | ```python 191 | from flask import Blueprint 192 | 193 | main = Blueprint('main', __name__) 194 | 195 | @main.route('/') 196 | def index(): 197 | return "Hello, World! Essa é a página principal." 198 | ``` 199 | 200 | ### Em `projeto/admin/routes.py` 201 | 202 | ```python 203 | from flask import Blueprint 204 | 205 | admin = Blueprint('admin', __name__) 206 | 207 | @main.route('/') 208 | def index(): 209 | return "Hello, World! Essa é a página de administração." 210 | ``` 211 | 212 | ## Utilizando Jinja2 (Template Engine) 213 | 214 | Renderizando um template através de `main/routes.py`: 215 | 216 | ```python 217 | from flask import Blueprint, render_template 218 | 219 | @main.route('/') 220 | def home(): 221 | # Define uma lista de dicionários posts 222 | posts = [ 223 | { 224 | "texto": "Hello, this is a post", 225 | "data": "This is a date and time", 226 | } 227 | ] 228 | 229 | # Passa a lista de dicionários para o template HTML 230 | return render_template("home.html", posts=posts) 231 | ``` 232 | 233 | Utilizando Jinja2 dentro de `templates/home.html`: 234 | 235 | ```html 236 | {% for posts in posts %} 237 |
238 |

{{ post.texto }}

239 |

{{ post.data }}

240 |
241 | {% endfor %} 242 | ``` 243 | 244 | Utilizando filtros: 245 | 246 | ``` 247 | {{ post.texto|upper }} 248 | ``` 249 | 250 | Utilizando **extends**: 251 | 252 | ```html 253 | {% extends 'base.html' %} 254 | 255 | {% block content %} 256 |

257 | Hello, world! 258 |

259 | {% endblock %} 260 | ``` 261 | 262 | Em `base.html` vamos definir nossa estrutura base: 263 | 264 | ```html 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | {% blockcontent %}{% endblock %} 273 | 274 | 275 | ``` 276 | 277 | Utilizando **include** para adicionar arquivos parciais: 278 | 279 | ``` 280 | {% include '_post.html' %} 281 | ``` 282 | 283 | Adicionando **folhas de estilo** para `templates/base.html`: 284 | 285 | ```html 286 | 287 | ``` 288 | 289 | ## Criando Modelos com SQLAlchemy 290 | 291 | Em `projeto/models.py`: 292 | 293 | ```python 294 | from flask_sqlalchemy import SQLAlchemy 295 | 296 | db = SQLAlchemy() 297 | 298 | class Post(db.Model): 299 | id = db.Column(db.Integer, primary_key=True) 300 | body = db.Column(db.String(256)) 301 | 302 | def __init__(self, body): 303 | self.body = body 304 | 305 | def __repr__(self): 306 | return "".format(self.id) 307 | ``` 308 | 309 | Em `projeto/__init__.py`: 310 | 311 | ```python 312 | from projeto.models import db 313 | 314 | app = Flask(__name__) 315 | app.config.from_object(config.DevelopmentConfig) 316 | with app.app_context(): 317 | db.init_app() 318 | ``` 319 | 320 | Em `projeto/config.py`: 321 | 322 | ```python 323 | import os 324 | BASE_DIR = os.path.abspath(os.path.dirname(__name__)) 325 | 326 | class BaseConfig(object): 327 | # ... 328 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'data.db') 329 | SQLALCHEMY_TRACK_MODIFICATIONS = False 330 | ``` 331 | 332 | Criando a Base de Dados e interagindo com os modelos e *queries* dentro de uma [shell](https://en.wikipedia.org/wiki/Shell_(computing)) 333 | 334 | ``` 335 | >>> from projeto import app, db 336 | >>> from projeto.models import Post 337 | >>> app.app_context().push() 338 | >>> db.create_all() 339 | >>> p = Post('Hello!') 340 | >>> db.session.add(p) 341 | >>> db.session.commit() 342 | >>> posts = Post.query.all() 343 | ``` 344 | 345 | ## Plugins Importantes 346 | 347 | - [Flask-PyMongo](https://flask-pymongo.readthedocs.io/en/latest/) 348 | - [Flask-SQLAlchemy](https://pypi.org/project/Flask-SQLAlchemy/) 349 | - [Flask-Mail](https://pythonhosted.org/Flask-Mail/) 350 | - [Flask-RESTful](https://flask-restful.readthedocs.io/en/latest/) 351 | - [Flask-Uploads](https://flask-uploads.readthedocs.io/en/latest/) 352 | - [Flask-WTF](https://flask-wtf.readthedocs.io/en/stable/) 353 | - [Flask-User](https://flask-user.readthedocs.io/en/latest/) 354 | - [Flask-Login](https://flask-login.readthedocs.io/en/latest/) 355 | -------------------------------------------------------------------------------- /capitulos/Banco de Dados.md: -------------------------------------------------------------------------------- 1 | # Banco de Dados 2 | 3 | ## Introdução 4 | 5 | Um **[banco de dados](https://pt.wikipedia.org/wiki/Banco_de_dados)** é uma coleção organizada de dados, geralmente armazenados e acessados eletronicamente através de um sistema de computador. 6 | 7 | O **[sistema de gerenciamento de banco de dados (DBMS)](https://pt.wikipedia.org/wiki/Sistema_de_gerenciamento_de_banco_de_dados)** é o software que interage com usuários finais, aplicativos e o próprio banco de dados para capturar e analisar os dados. 8 | 9 | **[Conolly e Begg](https://www.pearson.com/us/higher-education/program/Connolly-Database-Systems-A-Practical-Approach-to-Design-Implementation-and-Management-6th-Edition/PGM116956.html)** definem os Sistemas de Gerenciamento de Banco de Dados como um software que habilita usuários a definir, criar, manter e controlar o acesso ao banco de dados. 10 | 11 | A funcionalidade provida por uma DBMS pode variar bastante entre cada solução, porém as principais funcionalidades são o armazenamento, recuperação e atualização dos dados. 12 | 13 | Em determinado momento muitos aplicações web terão de lidar com banco de dados, como já estudamos, por ser um microframework, Flask não traz consigo um mecanismo para lidarmos com banco de dados, porém existe uma solução muito eficaz chamada **[SQLAlchemy](https://www.sqlalchemy.org/)**, que é um kit de ferramentas SQL para a linguagem Python e um **[Object Relational Mapper](https://en.wikipedia.org/wiki/Object-relational_mapping)** que fornece aos desenvolvedores de aplicação o poder total e flexibilidade de SQL. 14 | 15 | Um Object Relational Mapper é basicamente uma camada de abstração que se estabelece no topo de **[consultas SQL brutas](https://www.codecademy.com/articles/sql-commands)** sendo executadas em nosso banco dados. SQLAlchemy nos fornece uma **[API](https://en.wikipedia.org/wiki/Application_programming_interface)** consistente para diversos sistemas de banco de dados, os mais populares incluem MySQL, PostgreSQL e SQLite e também torna fácil movermos dados entre nossos modelos e nosso banco de dados e ainda torna fácil por exemplo a alteração de um sistema de banco de dados e a migração de nossos **[schemas](https://en.wikipedia.org/wiki/Database_schema)**. Em resumo, SQLAlchemy nos possibilitará escrever todo o código em Python, sem a necessidade de escrevermos códigos SQL. 16 | 17 | Neste guia específico, vamos utilizar a versão do SQLAlchemy para Flask chamada de **[Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/en/2.x/)** que nos possibilitará um início rápido e vamos escolher o sistema gerenciador de banco de dados [SQLite3](https://www.sqlite.org/index.html), que embora não seja uma solução escalável, ela é muito conveniente para pequenas aplicações como a nossa, além disso, em SQLite cada base de dados é armazenada em um único arquivo em disco e não há necessidade de executarmos um servidor de banco de dados como em MySQL e PostgreSQL. 18 | 19 | ## Flask-SQLAlchemy 20 | 21 | Flask-SQLAlchemy torna ainda mais simples o uso da biblioteca SQLAlchemy com Flask, para trabalharmos com ela é necessário fazermos sua instalação, com nosso Ambiente Virtual ativo, vamos digitar: 22 | 23 | ``` 24 | pip install flask-sqlalchemy 25 | ``` 26 | 27 | Uma vez instalada com sucesso, agora temos a biblioteca a nossa disposição para trabalharmos. Vamos então criar um novo arquivo chamado `models.py` dentro da pasta `Exemplos` este arquivo que representará um modelo de uma simples biblioteca. 28 | 29 | Vamos começar com as configurações básicas 30 | 31 | ```python 32 | from flask import Flask 33 | from flask_sqlalchemy import SQLAlchemy 34 | 35 | app = Flask(__name__) 36 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///livros.db' 37 | db = SQLAlchemy(app) 38 | ``` 39 | 40 | Nós primeiramente importamos as bibliotecas necessárias, que nesse caso é o próprio Flask e o Flask-SQLAlchemy, posteriormente criamos nosso objeto **app** e indicamos onde o arquivo do banco de dados deve ficar localizado (root da aplicação). Por fim criamos o objeto **db** que nos permite integrar SQLAlchemy na nossa aplicação Flask. 41 | 42 | Agora que temos nossas configurações estabelecidades, vamos começar a trabalhar efetivamente em nosso banco de dados, vamos criar uma classe **Autor** que representará uma tabela Autor em nosso banco de dados, este será nosso modelo. 43 | 44 | ```python 45 | class Autor(db.Model): 46 | id = db.Column(db.Integer, primary_key=True) 47 | nome = db.Column(db.String(30), nullable=False) 48 | sobrenome = db.Column(db.String(30), nullable=False) 49 | livros = db.relationship('Livro', backref='autor', lazy=True) 50 | 51 | def __repr__(self): 52 | return f'Autor("{self.nome}", "{self.sobrenome}")' 53 | ``` 54 | 55 | Começamos definindo o nome de nossa classe como **Autor**, esta que herda de `db.Model`, uma classe base para todos os modelos de Flask-SQLAlchemy. Esta classe define diversos campos como variáveis de classe. Campos são criados como instâncias da classe `db.Column`, no qual recebem o campo como argumento, mais alguns argumentos adicionais como por exemplo `primary_key` que índica o campo como uma chave primária da tabela, que deve ser único. 56 | 57 | Nossa tabela então é composta pelos seguintes campos: 58 | 59 | - **id**, valor inteiro único que representa nossa chave primária 60 | - **nome**, String de até 30 caracteres que não pode ser nulo 61 | - **sobrenome**, String de até 30 caracteres que não pode ser nulo 62 | - **livros**, Este campo é um relacionamento com a classe **Livro** que vamos criar, o argumento **backref** define o nome do campo que será adicionado aos objetos da classe 'muitos' que apontará de volta para o objeto 'único'. 63 | 64 | Para entendermos melhor, estamos fazendo uma relação em que um **Autor** poderá ter a autoria sob muitos livros, porém um livro pertencerá a um único autor. 65 | 66 | É o que chamamos de relação **[one-to-many](https://en.wikipedia.org/wiki/One-to-many_(data_model))** 67 | 68 | - Por fim, o método mágico `__repr__` diz ao Python como imprimir os objetos dessa classe, o que será muito útil caso precisemos debuggar. 69 | 70 | Vamos agora criar a Classe que representará a tabela **Livros** 71 | 72 | ```python 73 | class Livro(db.Model): 74 | id = db.Column(db.Integer, primary_key=True) 75 | titulo = db.Column(db.String(100), nullable=False) 76 | sumario = db.Column(db.String(250), nullable=False) 77 | autor_id = db.Column(db.Integer, db.ForeignKey('autor.id'), nullable=False) 78 | 79 | def __repr__(self): 80 | return f'Livro("{self.titulo}")' 81 | ``` 82 | 83 | Como em nossa classe Autor, começamos definindo o nome de nossa classe como **Livro** e herdamos de `db.Model`. Criamos o campo **id** que representa nossa chave primária, o **titulo** de nosso livro que será uma String de até 100 caracteres e o **sumario** que será uma string de até 250 caracteres. O campo **autor_id** é chamado de **ForeignKey**, que seria como uma chave estrangeira para acessarmos o autor do respectivo livro. 84 | 85 | - Por fim, o método mágico `__repr__` diz ao Python como imprimir os objetos dessa classe. 86 | 87 | A imagem a seguir ilustra o [esquema](https://en.wikipedia.org/wiki/Database_schema) de nosso banco de dados: 88 | 89 | ![img](https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/Tabelas.png) 90 | 91 | Agora que nossos modelos estão estabelecidos, é hora de testarmos nosso banco de dados para termos certeza que podemos inserir dados. Dentro de seu diretório `Exemplos` onde reside o arquivo `models.py`, abra o interpretador Python para que possamos trabalhar interactivamente. Para isso digite `python` 92 | 93 | Começamos com os imports necessários 94 | 95 | ```python 96 | >>> from models import db, Autor, Livro 97 | ``` 98 | 99 | Inicializando Banco de Dados e Tabelas 100 | 101 | ```python 102 | >>> db.create_all() 103 | ``` 104 | 105 | Cadastrando um autor em nosso banco de dados 106 | 107 | ```python 108 | >>> autor = Autor(nome='Aldous', sobrenome='Huxley') 109 | >>> db.session.add(autor) 110 | >>> db.session.commit() 111 | ``` 112 | 113 | Perceba que é necessário primeiro adicionarmos o **autor** criado através de `db.session.add()` e depois para escrevermos as mudanças em nosso banco de dados executamos `db.session.commit()`. Feito, conseguimos popular a nossa tabela autor com nosso primeiro autor! Vamos agora cadastrar um livro 114 | 115 | ```python 116 | >>> livro = Livro(titulo='Brave New World', sumario='Dystopian Novel', autor_id=autor.id) 117 | >>> db.session.add(livro) 118 | >>> db.session.commit() 119 | ``` 120 | 121 | Seguimos o mesmo procedimento anterior, exceto que passamos o atributo **id** do autor para o campo **autor_id**, dessa forma estamos cadastrando o autor que criamos recentemente como o autor deste livro. Agora que temos os cadastro feitos, podemos nos referir aos campos de nossas tabelas para acessarmos os dados, por exemplo 122 | 123 | Se desejarmos acessar os atributos da tabela Livro 124 | 125 | ```python 126 | >>> livro.titulo 127 | >>> livro.sumario 128 | >>> livro.autor 129 | ``` 130 | 131 | Nos retornará, respectivamente 132 | 133 | ``` 134 | 'Brave New World' 135 | 'Dystopian Novel' 136 | Autor("Aldous", "Huxley") 137 | ``` 138 | 139 | Podemos fazer o mesmo com a tabela Autor 140 | 141 | ```python 142 | >>> autor.nome 143 | >>> autor.sobrenome 144 | >>> autor.livros 145 | ``` 146 | 147 | Que nos retorna 148 | 149 | ``` 150 | 'Aldous' 151 | 'Huxley' 152 | [Livro("Brave New World")] 153 | ``` 154 | 155 | Podemos também executar consultas através de SQLAlchemy, vejamos alguns exemplos 156 | 157 | ```python 158 | >>> Autor.query.all() 159 | ``` 160 | 161 | O método `query.all()` nos retorna todos os Autores em nosso banco de dados, nesse caso só temos um, então nos será retornado `[Autor("Aldous", "Huxley")]`. 162 | 163 | Podemos também consultar um livro pelo seu respectivo **id**: 164 | 165 | ```python 166 | Livro.query.get(1) 167 | ``` 168 | 169 | O método `query.get()` recebe como parâmetro um **id** e nos retorna o respectivo Livro com tal **id**, nesse caso: `Livro("Brave New World")` 170 | 171 | ## Sumarizando 172 | 173 | - Neste capítulo estudamos os conceitos básicos de banco de dados 174 | - Vimos alguns Sistemas Gerenciadores de Banco de Dados e sua importância 175 | - Aprendemos sobre o conceito de **ORM** 176 | - Utilizamos o **ORM** Flask-SQLAlchemy para criarmos nosso primeiro banco de dados 177 | - Executamos algumas manipulações básicas como inserção de dados e consultas simples 178 | 179 | Este Capítulo fecha a saga dos **fundamentos básicos de Flask**, agora vamos partir para a segunda parte de nossa caminhada, onde vamos aprender a estruturar uma aplicação de uma forma mais consistente, bem como unir todos os conhecimentos que adquirimos até então. -------------------------------------------------------------------------------- /capitulos/Flask.md: -------------------------------------------------------------------------------- 1 | # Flask 2 | 3 | Este projeto tem como objetivo apresentar o microframework Flask e suas principais características que nos possibilitam desenvolver aplicações web completas e **[escaláveis](https://www.romexsoft.com/blog/scalable-website/)**. 4 | 5 | ## Introdução 6 | 7 | **[Flask](https://flask.palletsprojects.com/en/1.1.x/)** foi criado por Armin Ronacher, seu lançamento oficial ocorreu no ano de 2010. Por ser pequeno, leve e minimalista, ele é conhecido como um microframework Python, mas isso não quer dizer que ele seja somente limitado a aplicações pequenas, muito pelo contrário, Flask pode ser utilizado em grandes aplicações que escalam, sua fama de microframework ocorre pelo fato de Flask manter o núcleo de uma aplicação simples, porém extensível, Flask não tem construído uma camada de abstração para banco de dados, nem mesmo validação para formulários, porém Flask suporta **extensões** que são capazes de adicionar todas essas funcionalidades para nossa aplicação. 8 | 9 | Flask na verdade é a união de dois frameworks muito populares. 10 | 11 | 1. **[Werkzeug](https://palletsprojects.com/p/werkzeug/)**: Uma biblioteca **[WSGI (Web Server Gateway Interface)](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface)** para Python, que inclui sistema de rotas de URL, objetos *request* e *response* com características completas e um poderoso *debugger*. 12 | 2. **[Jinja2](https://palletsprojects.com/p/jinja/)**: Um **[Template Engine](https://en.wikipedia.org/wiki/Template_processor)** completo para Python 13 | 14 | Como já vimos, tarefas de alto-nível como acesso ao banco de dados, formulários web e autenticação de usuários são suportados através de **'extensões'**. 15 | 16 | Dentro do escopo da arquitetura **[MVC (Model-View-Controller)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)**, Werkzeug abrange o Controller (C) e Jinja2 abrange a View (V). Flask não fornece um Model (M) integrado, ele deixa você escolher sua solução de banco de dados favorita. Uma escolha muito popular é **[Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/en/2.x/)** que traz um **[ORM (Object-Relational Mapper)](https://en.wikipedia.org/wiki/Object-relational_mapping)** sob um banco de dados relacional como MySQL ou PostgreSQL. 17 | 18 | Sumarizando, o microframework Flask é capaz de nos fornecer: 19 | 20 | - Uma interface em conformidade com o **WSGI** 21 | - Sistema de Rotas de URL e Request/Response 22 | - Cookies e Sessions Seguros 23 | - Servidor Web de desenvolvimento e Debugger construídos 24 | - Cliente de Unit Test para testes unitários 25 | - Templates Jinja2 (tags, filtros, macros, etc) 26 | - Extensiva Documentação 27 | - Extensões disponíveis para aperfeiçoar e agilizar o desenvolvimento 28 | 29 | Através de Flask você pode lidar com requisições HTTP e AJAX, rotear requests para um controller, avaliar e validar dados requisitados e também fornecer respostas com **HTML** ou **JSON**. 30 | 31 | Você pode conferir projetos e corporações que usam Flask em: **[flask-powered](https://github.com/rochacbruno/flask-powered)** 32 | 33 | ## Instalando Flask 34 | 35 | Para instalarmos Flask é necessário que tenhamos Python em nosso computador, caso você ainda não o tenha, faça o download através do **[Website Oficial](https://www.python.org/downloads/)** e você estará pronto para começar. 36 | 37 | Agora abra a sua **[Interface de Linha de Comandos](https://en.wikipedia.org/wiki/Shell_(computing))** ![terminal](https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/CMD.png) e digite: 38 | 39 | ``` 40 | python --version 41 | ``` 42 | 43 | Nos será retornada a versão atual do Python em nosso computador, em nosso caso estamos lidando com a versão `3.7.1`. Agora que já temos o Python em nossa máquina, podemos utilizar o **[pip](https://pypi.org/project/pip/)** para instalarmos o Flask. **Pip** é um gerenciador de pacotes Python que nos permite instalar diversos módulos escritos por outros desenvolvedores, ele já vem automaticamente instalado com Python, porém caso você tenha algum problema, poderá obtê-lo em: **[pip](https://pypi.org/project/pip/)**. 44 | 45 | Antes de instalarmos Flask é importante termos em mente o conceito de Ambientes Virtuais, que nos permitem isolar os pacotes utilizados em nosso projeto para que possamos evitar conflitos de versões com nosso ambiente global. A ferramenta **[virtualenv](https://virtualenv.pypa.io/en/latest/)** nos auxilia nesse processo, para obtermos ela é muito simples: 46 | 47 | ``` 48 | pip install virtualenv 49 | ``` 50 | 51 | Tendo a ferramenta **virtualenv** em nossa máquina, podemos agora criar um Ambiente Virtual, crie um diretório com o nome de sua escolha, em nosso caso será `Exemplo` e **dentro** dele digite o seguinte comando 52 | 53 | ``` 54 | python -m venv ambiente 55 | ``` 56 | 57 | Será criado para nós um diretório com o nome `ambiente`, este que representará o nosso ambiente virtual, para ativarmos ele digitamos o seguinte comando 58 | 59 | ``` 60 | source ambiente/bin/activate 61 | ``` 62 | 63 | ou 64 | 65 | ``` 66 | . ambiente/bin/activate 67 | ``` 68 | 69 | Para desativarmos basta digitarmos `deactivate` e o ambiente será desativado, por hora vamos mantê-lo ativo, pois iremos instalar a Biblioteca Flask através do **pip**: 70 | 71 | ``` 72 | pip install flask 73 | ``` 74 | 75 | Depois dessa rápida instalação, agora já temos Flask disponível para trabalharmos em nossa máquina. Antes de iniciarmos nossos experimentos com Flask, vamos experimentar alguns comandos **pip** importantes 76 | 77 | Listando Pacotes Instalados no Ambiente Virtual 78 | 79 | ``` 80 | pip list 81 | ``` 82 | 83 | Nos será trazida a seguinte resposta: 84 | 85 | ``` 86 | Click 7.0 87 | Flask 1.1.1 88 | itsdangerous 1.1.0 89 | Jinja2 2.10.1 90 | MarkupSafe 1.1.1 91 | pip 10.0.1 92 | setuptools 39.0.1 93 | Werkzeug 0.15.5 94 | ``` 95 | 96 | Criando um arquivo `requirements.txt` 97 | 98 | Através do **pip** é possível criarmos um arquivo `requirements.txt` que servirá como o guardião dos pacotes necessários para que nossa aplicação funcione corretamente. Caso alguma pessoa queira utilizar nossa aplicação, ela poderá instalar os requerimentos através desse arquivo. Para criarmos ele devemos digitar o seguinte comando: 99 | 100 | ``` 101 | pip freeze > requirements.txt 102 | ``` 103 | 104 | Nos será criado um arquivo `requirements.txt` com o seguinte conteúdo 105 | 106 | ``` 107 | Click==7.0 108 | Flask==1.1.1 109 | itsdangerous==1.1.0 110 | Jinja2==2.10.1 111 | MarkupSafe==1.1.1 112 | Werkzeug==0.15.5 113 | ``` 114 | 115 | Para instalar os pacotes contidos no arquivo `requirements.txt` podemos utilizar o comando 116 | 117 | ``` 118 | pip install -r requirements.txt 119 | ``` 120 | 121 | Caso tenha interesse em se aprofundar mais na questão dos Ambientes Virtuais, você pode visitar os guias: **[Gerenciadores de Pacotes e Ambientes Virtuais](https://github.com/the-akira/Python-Iluminado/blob/master/Capitulos/29.PIP.md)** e **[Environment](https://exploreflask.com/en/latest/environment.html#)** 122 | 123 | ## Flask Hello World 124 | 125 | Agora que já temos nosso Ambiente Virtual funcionando corretamente e Flask está instalado em nosso Ambiente isolado, vamos criar nosso primeiro **Hello World**. Para isso, vamos criar em nosso diretório `Exemplo` o arquivo `app.py` que terá o seguinte conteúdo 126 | 127 | ```python 128 | from flask import Flask 129 | app = Flask(__name__) 130 | 131 | @app.route('/') 132 | def hello_world(): 133 | return 'Hello World!' 134 | 135 | if __name__ == '__main__': 136 | app.run() 137 | ``` 138 | 139 | 1. Começamos importando a classe Flask. Uma instância dessa classe será nossa aplicação **WSGI** 140 | 2. Em seguida nós criamos uma instância dessa classe. O primeiro argumento é o nome do módulo da aplicação ou pacote. Se você estiver utilizando um único módulo (como em nosso exemplo) você deve usar `__name__` porque dependendo se é iniciado como aplicativo ou importado como módulo, o nome será diferente, isso é necessário para que Flask saiba onde buscar Templates e arquivos Static. 141 | 3. Nós usamos o **[decorador](https://realpython.com/primer-on-python-decorators/)** **route()** para dizer ao Flask qual URL irá ativar nossa função. 142 | 4. À função é dado um nome no qual também é utilizado para gerar URL's para essa função em particular, e retorna a mensagem que desejamos apresentar no **[browser](https://en.wikipedia.org/wiki/Web_browser)** do usuário. 143 | 5. O bloco **if** é basicamente uma forma de Python dizer 'Execute esse código apenas se eu rodá-lo'. Como vimos antes `__name__` é uma variável que Python cria automaticamente e ela é igual a `__main__` quando somos nós que rodamos o código. 144 | 145 | Em resumo podemos dizer que: 146 | 147 | ```python 148 | # Importamos e criamos nosso app 149 | from flask import Flask 150 | app = Flask(__name__) 151 | 152 | # Especificamos nossa rota, sua função e seu retorno 153 | @app.route('/') 154 | def hello_world(): 155 | return 'Hello World!' 156 | 157 | # Roda o nosso app 158 | if __name__ == '__main__': 159 | app.run() 160 | ``` 161 | 162 | Agora finalmente podemos executar nossa aplicação através do comando `python app.py`. Por padrão Flask irá utilizar a porta 5000 de nosso localhost, então navegue até `http://127.0.0.1:5000/` para ver nossa aplicação funcionando. Perfeito, conseguimos executar nossa primeira aplicação em Flask, é incrível como em poucas linhas de códigos conseguimos obter este resultado. Flask é realmente poderoso. 163 | 164 | Caso queiramos disponibilizar nossa aplicação para outras pessoas em nossa rede, podemos passar o parâmetro **host** para a função **run()**, vejamos 165 | 166 | ```python 167 | if __name__ == '__main__': 168 | app.run(host='0.0.0.0') 169 | ``` 170 | 171 | Para alterarmos a porta em que a aplicação é disponibilizada passamos o parâmetro **port** para a função **run()** 172 | 173 | ```python 174 | if __name__ == '__main__': 175 | app.run(port=3535) 176 | ``` 177 | 178 | Nossa aplicação agora estará rodando na porta **3535**. Por fim, mas não menos importante, podemos ativar o modo **debug** para facilitar o processo de desenvolvimento de nossas aplicações. 179 | 180 | ```python 181 | if __name__ == '__main__': 182 | app.run(debug=True) 183 | ``` 184 | 185 | Atribuindo **debug** como **True** nos permite um maior controle sobre os erros que ocorrem durante o desenvolvimento, porém é importante lembrarmos que devemos utilizar somente durante essa fase, jamais devemos utilizar em produção. 186 | 187 | Você pode ver o exemplo em tempo real acessando: https://repl.it/@theakira/Flask-Introducao 188 | 189 | ## Sumarizando 190 | 191 | Neste capítulo aprendemos 192 | 193 | - Um pouco sobre a história do microframework Flask 194 | - Instalação do Flask 195 | - Manipulando Ambientes Virtuais 196 | - Criação de uma simples aplicação `Hello World` 197 | - Conhecimento básico da estrutura do Flask -------------------------------------------------------------------------------- /capitulos/Templates.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | ## Introdução 4 | 5 | Templates são um elemento essencial em Flask e muitos outros frameworks, eles são o que chamamos de camada de apresentação ou *view* de nossa aplicação. Um template é um arquivo que contém textos estáticos, assim como *placeholders* para renderizarmos conteúdo dinâmico. 6 | 7 | ![templates](https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/FlaskTemplate.png) 8 | 9 | Como podemos ver na ilustração: 10 | 11 | - Temos nossos dados armazenados em um banco de dados 12 | - Temos um arquivo template 13 | 14 | O template engine conecta com o modelo de dados e processa os códigos específicos nos templates e então direciona o output para um arquivo específico que normalmente é renderizado em um browser de forma que possamos ver a apresentação dos dados. 15 | 16 | ## Jinja2 17 | 18 | Jinja é uma moderna e amigável linguagem de Templates para Python. É veloz, amplamente utilizado e seguro e conta com características como: 19 | 20 | - Execução em Sandbox 21 | - Um poderoso sistema automático de *escaping* para prevenção contra ataques **[XSS](https://en.wikipedia.org/wiki/Cross-site_scripting)** 22 | - Herança de Templates 23 | - Compila para código python otimizado *[just in time](https://en.wikipedia.org/wiki/Just-in-time_compilation)* 24 | - Fácil de debugar 25 | - Sintáxe Configurável 26 | 27 | Podemos instalar Jinja2 através do comando `pip install Jinja2`, porém uma vez que já instalamos Flask, não precisamos fazê-lo, pois Jinja2 já faz parte do Flask. 28 | 29 | É muito importante sabermos que existem dois tipos de delimitadores em Jinja2: 30 | 31 | - `{% ... %}`: Usado para executar comandos como **for loops** ou atribuição de valores 32 | - `{{ ... }}`: Usado para imprimirmos o resultado de expressões no template 33 | 34 | ## Trabalhando com Templates em Flask 35 | 36 | Atualmente contamos com um diretório `Exemplos` que contém nosso Ambiente Virtual, o arquivo `requirements.txt` e nossa simples aplicação `app.py` que no momento contém o seguinte código: 37 | 38 | ```python 39 | from flask import Flask 40 | app = Flask(__name__) 41 | 42 | @app.route('/') 43 | def hello_world(): 44 | return 'Hello World!' 45 | 46 | if __name__ == '__main__': 47 | app.run(debug=True) 48 | ``` 49 | 50 | Dentro de nosso diretório `Exemplos` vamos agora criar um novo diretório chamado de `templates` e nele vamos criar um arquivo `index.html` com o seguinte conteúdo: 51 | 52 | ```html 53 |

Nosso primeiro Template

54 | ``` 55 | 56 | Agora vamos modificar nosso arquivo `app.py` de forma que possamos servir esse template. 57 | 58 | ```python 59 | from flask import Flask, render_template 60 | app = Flask(__name__) 61 | 62 | @app.route('/') 63 | def index(): 64 | return render_template('index.html') 65 | 66 | if __name__ == '__main__': 67 | app.run(debug=True) 68 | ``` 69 | 70 | Observe que tivemos que importar a função **render_template()** para podermos trabalhar com os templates. 71 | 72 | - Essa função recebe como argumento o **nome do template** a ser renderizado ou um iterável com nomes de templates, em que o primeiro será renderizado. 73 | - O **contexto**, em outras palavras: as variáveis que estarão disponíveis no contexto do template. 74 | 75 | Para saber mais detalhes sobre a função visite: **[flask.render_template](https://flask.palletsprojects.com/en/1.1.x/api/#flask.render_template)** 76 | 77 | Agora execute a aplicação com o comando `python app.py` e visite `http://127.0.0.1:5000/` para ver o resultado. 78 | 79 | ## Passando Variáveis para o Template 80 | 81 | Até então renderizamos um arquivo HTML estático, o que já nos fornece bastante flexibilidade para criarmos páginas web, porém o grande poder dos templates está em sua capacidade de receber variáveis para que possamos apresentar os dados para os usuários que irão visualizar nossa aplicação. 82 | 83 | Vamos alterar nossos arquivos `app.py` e `index.html` para vermos um simples exemplo 84 | 85 | ```python 86 | from flask import Flask, render_template 87 | app = Flask(__name__) 88 | 89 | @app.route('/') 90 | def index(): 91 | nome = 'Gabriel' 92 | return render_template('index.html', nome=nome) 93 | 94 | if __name__ == '__main__': 95 | app.run(debug=True) 96 | ``` 97 | 98 | ```html 99 |

Olá {{ nome }}

100 | ``` 101 | 102 | Novamente executamos nossa aplicação através do comando `python app.py` e podemos ver o resultado que nos é retornado. 103 | 104 | ### Trabalhando com Estruturas de Dados, Funções e Classes 105 | 106 | Vamos agora criar uma nova rota e um novo template de forma que possamos trabalhar com estruturas variadas. Em nosso diretório **templates** vamos criar o arquivo `jinja.html`, no momento ele terá o seguinte conteúdo 107 | 108 | ```html 109 |

Jinja Template

110 | ``` 111 | 112 | Agora vamos alterar nosso arquivo `app.py` de forma que possamos servir esse novo template 113 | 114 | ```python 115 | from flask import Flask, render_template 116 | app = Flask(__name__) 117 | 118 | @app.route('/') 119 | def index(): 120 | nome = 'Gabriel' 121 | return render_template('index.html', nome=nome) 122 | 123 | @app.route('/jinja') 124 | def jinja(): 125 | return render_template('jinja.html') 126 | 127 | if __name__ == '__main__': 128 | app.run(debug=True) 129 | ``` 130 | 131 | Executamos nossa aplicação e agora podemos navegar até `http://127.0.0.1:5000/jinja` para ver o resultado. Agora vamos criar alguns dados para experimentarmos em nosso template, novamente vamos editar o arquivo `app.py` com o seguinte conteúdo: 132 | 133 | ```python 134 | from flask import Flask, render_template 135 | app = Flask(__name__) 136 | 137 | @app.route('/') 138 | def index(): 139 | nome = 'Gabriel' 140 | return render_template('index.html', nome=nome) 141 | 142 | @app.route('/jinja') 143 | def jinja(): 144 | num = 10 145 | 146 | langs = ['Python', 'Javascript', 'C', 'C++', 'Bash', 'Haskell'] 147 | 148 | personagens = { 149 | 'DBZ': 'Goku', 150 | 'Naruto': 'Kakashi', 151 | 'Death Note': 'Raito Yagami', 152 | 'Akira': 'Tetsuo', 153 | 'Pokémon': 'Ash' 154 | } 155 | 156 | cores = ('red', 'green', 'blue') 157 | 158 | online = True 159 | 160 | class Aplicacao: 161 | def __init__(self, nome, descricao, url): 162 | self.nome = nome 163 | self.descricao = descricao 164 | self.url = url 165 | 166 | def nome(self): 167 | return f'O nome da aplicação é {self.nome}' 168 | 169 | def endereco(self): 170 | return f'Você pode acessar a aplicação atraves do endereço: {self.url}' 171 | 172 | app = Aplicacao(nome='Flask Programação Web', descricao='Tutorial Completo', url='https://github.com/the-akira') 173 | 174 | def cubo(x): 175 | return x**3 176 | 177 | html = "

Titulo Grande

" 178 | 179 | malicioso = "" 180 | 181 | return render_template( 182 | 'jinja.html', 183 | num=num, 184 | langs=langs, 185 | personagens=personagens, 186 | cores=cores, 187 | online=online, 188 | Aplicacao=Aplicacao, 189 | cubo=cubo, 190 | app=app, 191 | html=html, 192 | malicioso=malicioso 193 | ) 194 | 195 | if __name__ == '__main__': 196 | app.run(debug=True) 197 | ``` 198 | 199 | Podemos observar que: 200 | 201 | 1. Atribuimos o valor 10 à variável **num** 202 | 2. Criamos uma lista **langs** com importantes linguagens de programação 203 | 3. Criamos um dicionário **personagens** com personagens de animes 204 | 4. Criamos uma tupla **cores** com os valores **[RGB](https://www.w3schools.com/colors/colors_rgb.asp)** 205 | 5. Atribuimos o valor **True** à variável **online** 206 | 6. Definimos uma classe **Aplicacao** que modela uma Aplicação 207 | 7. Construimos um objeto **app** através do Construtor **Aplicacao()** 208 | 8. Definimos uma função **cubo()** que eleva um número passado por parâmetro ao cubo 209 | 9. Atribuimos uma String contendo HTML à variável **html** 210 | 10. Atribuimos um String contendo um Script à variável malicioso 211 | 11. Por fim, retornamos a função **render_template()** que recebe o nosso template `jinja.html` e todas as variáveis que definimos 212 | 213 | Agora que temos acesso a todos esses dados em nosso template, podemos editar nosso arquivo `jinja.html` para apresentarmos os dados em nossa página. 214 | 215 | ```html 216 |

Jinja Template

217 |
218 | 219 |

1. Variáveis

220 |

Número: {{ num }}

221 | 222 |
223 | 224 |

2. Percorrendo a lista com o For Loop

225 | 230 | 231 |
232 | 233 |

3. Percorrendo a lista com índices através do For Loop

234 | 239 | 240 |
241 | 242 |

4. Percorrendo dicionário com o For Loop

243 | 248 | 249 |
250 | 251 |

5. Acessando um Membro da Lista

252 |

{{ langs[0] }}

253 | 254 |
255 | 256 |

6. Acessando um Membro do Dicionário

257 |

{{ personagens['Akira'] }}

258 | 259 |
260 | 261 |

7. Acessando Atributos de Classe

262 |

{{ app.nome }}

263 | 264 |
265 | 266 |

8. Desempacotando Variáveis

267 |

{% set a, b, c = cores %}

268 |

{{ a }}

269 |

{{ b }}

270 |

{{ c }}

271 | 272 |
273 | 274 |

9. Chamando uma Função

275 |

{{ cubo(3) }}

276 |

{{ cubo(2) }}

277 | 278 |
279 | 280 |

10. Chamando um Método de Classe

281 |

{{ app.endereco() }}

282 | 283 |
284 | 285 |

11. Condicionais

286 | {% if online %} 287 |

Usuário se encontra online

288 | {% endif %} 289 | 290 |
291 | 292 |

12. Comparações

293 | {% if num < 18 %} 294 |

Valor menor que 18

295 | {% elif num == 20 %} 296 |

Valor é igual a 20

297 | {% else %} 298 |

Nenhuma das outras opções

299 | {% endif %} 300 | 301 |
302 | 303 |

13. Expressões Matemáticas

304 |

{{ num/2 }}

305 |

{{ (5*5)/10 }}

306 |

{{ 'x'*3 }}

307 |

{{ (5+3)*(7-2) }}

308 | 309 |
310 | 311 |

14. Filtros de Template

312 |

{{ langs|length }}

313 |

{{ langs|lower }}

314 |

{{ langs|upper }}

315 | 316 |
317 | 318 |

15. Filtros de Template - join

319 |

{{ langs|join(', ') }}

320 | 321 |
322 | 323 |

16. Escaping

324 | {{ html }} 325 | {{ html|safe }} 326 | {{ malicioso }} 327 | ``` 328 | 329 | Podemos observar que: 330 | 331 | 1. Imprimimos o valor da variável **num** 332 | 2. Percorremos e imprimimos os elementos da lista **lang** 333 | 3. Percorremos e imprimimos os elementos da lista **lang** juntamente com seu índice 334 | 4. Percorremos o dicionário **personagens** e imprimimos os pares chave:valor 335 | 5. Acessamos o primeiro elemento da lista **lang** 336 | 6. Acessamos o elemento de chave **Akira** do dicionário **personagens** 337 | 7. Acessamos o atributo **nome** do objeto **app** 338 | 8. Desempacotamos os valores da tupla **cores** e os acessamos individualmente através das variáveis **a**, **b** e **c** 339 | 9. Chamamos a função **cubo()** para calcular o cubo dos valores **3** e **2** 340 | 10. Invocamos o método **endereco** através do objeto **app** 341 | 11. Aqui utilizamos o condicional **if** que testa se a variável **online** é True, uma vez que ela True, o conteúdo 'Usuário se encontra online' é apresentado 342 | 12. Comparamos a variável **num** com diversos valores 343 | 13. Testamos diversas expressões matemáticas 344 | 14. Utilizamos os **Filtros de Template** para modificar a apresentação de nossos dados 345 | 15. Utilizamos o filtro **join()** para transformar nossa lista em uma String 346 | 16. Exibimos os valores das variáveis **html** e **malicioso**, perceba que o filtro **safe** nos permite indicar que é seguro renderizar os dados, caso ele não seja utilizado, tags html e scripts não serão renderizados em nossa página por motivos de segurança. 347 | 348 | Finalmente vamos executar nossa aplicação através do comando `python app.py` e vamos navegar até `http://127.0.0.1:5000/jinja`. Veja como são exibidos nossos dados e experimente da forma que melhor lhe agrade. 349 | 350 | ## Herança de Template 351 | 352 | A Herança de Template nos permite criar um arquivo que servirá como o **layout** principal de nossa aplicação, de forma que não seja necessário ficarmos repetindo código desnecessariamente. Por exemplo, em aplicações web é muito como a existência de uma barra de navegação que contém diversas rotas, para não precisarmos ficar repetindo blocos html podemos usar o conceito de herança. Para entendermos melhor vamos então criar um arquivo `layout.html` em nosso diretório `templates` com o seguinte conteúdo 353 | 354 | ```html 355 | 356 | 357 | Aplicação Flask 358 | 359 | 360 | Navegar para Jinja: Jinja 361 |
362 | {% block conteudo %}{% endblock %} 363 | 364 | 365 | ``` 366 | 367 | Veja que utilizamos o comando **block** que define um bloco com o nome **conteudo** arbitrariamente escolhido por nós, este bloco será capaz de receber conteúdo de outros templates. Agora vamos editar nosso arquivo `index.html` para que ele possa herdar as propriedades de nosso `layout.html` 368 | 369 | ```html 370 | {% extends 'layout.html' %} 371 | 372 | {% block conteudo %}

Olá {{ nome }}

{% endblock %} 373 | ``` 374 | 375 | Através do comando **extends** indicamos que este arquivo irá herdar as propriedades de nosso `layout.html` e dentro do bloco **conteudo** nós definimos o HTML a ser exibido. Lembrando que é necessário fecharmos o bloco com **endblock**. Agora podemos executar nossa aplicação com o comando `python app.py` para vermos o nosso **layout** em ação. 376 | 377 | Caso queira experimentar o código em tempo real: https://repl.it/@theakira/Flask-Templates 378 | 379 | ## Sumarizando 380 | 381 | Neste capítulo: 382 | 383 | - Estudamos fundamentos sobre Template Engines 384 | - Trabalhamos com Jinja2 em Flask 385 | - Passamos variáveis para nosso Template 386 | - Apresentamos dados em nosso Template 387 | - Criamos um Layout principal para nossa simples Aplicação 388 | 389 | Agora que já temos o domínio dos Templates vamos estudar os Arquivos Static que são um aspecto importante em uma aplicação. -------------------------------------------------------------------------------- /capitulos/Formulários Web.md: -------------------------------------------------------------------------------- 1 | # Formulários Web 2 | 3 | ## Introdução 4 | 5 | **[Formulários HTML](https://en.wikipedia.org/wiki/Form_(HTML))** são um dos principais pontos de **interação** entre um usuário e um site ou aplicativo. Eles permitem que os usuários enviem dados para nossa aplicação. Na maioria das vezes, os dados são enviados para o servidor Web, mas a página Web também pode interceptá-los para usá-los por conta própria. 6 | 7 | Um formulário HTML é feito de um ou mais *widgets*. Esses *widgets* podem ser campos de texto (linha única ou multilinha), caixas de seleção, botões, caixas de checagem ou botões de opção. Na maioria das vezes, esses widgets são combinados com um rótulo que descreve sua finalidade - os rótulos implementados adequadamente podem instruir claramente os usuários cegos e com visão sobre o que inserir em uma entrada de formulário. 8 | 9 | Veja todos os tipos possíveis de input: **[html_form_input_types](https://www.w3schools.com/html/html_form_input_types.asp)** 10 | 11 | A principal diferença entre um formulário HTML e um documento HTML regular é que, na maioria das vezes, os dados coletados pelo formulário são enviados para um servidor Web. Nesse caso, você precisa configurar um servidor da Web para receber e processar os dados, felizmente Flask já traz todos esses elementos para nós. 12 | 13 | Exemplo de um simples Formulário Web 14 | 15 | ![form](https://raw.githubusercontent.com/the-akira/Flask-Programacao-Web/master/imagens/HTMLForm.png) 16 | 17 | Este formulário nos reflete o seguinte código HTML: 18 | 19 | ```html 20 |
21 | Nome: 22 |
23 | 24 |
25 | Sobrenome: 26 |
27 | 28 |
29 | 30 |
31 | ``` 32 | 33 | Perceba que definimos uma tag `
` e dentro dela três tags ``, sendo as duas primeiras com atributos de **type** `text` e a última de **type** `submit`. É essencial que definamos o tipo de nosso input. 34 | 35 | O atributo **name** serve como um identificador para nos referirmos a cada input específico, veja que fornecemos um **name** para nossos dois primeiros input, respectivamente **nome** e **sobrenome**. 36 | 37 | Nesse capítulo não vamos abordar o aspecto **HTML** de forma detalhada, nosso foco é o **Flask**! Caso você queira se aprofundar no **HTML** você pode ler esses dois **importantes** guias: 38 | 39 | - [W3Schools - HTML Forms](https://www.w3schools.com/html/html_forms.asp) 40 | - [Developer Mozilla - HTML Forms](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms) 41 | 42 | ## Básico de Formulários em Flask 43 | 44 | Para entendermos o básico de como os formulários funcionam em Flask, vamos agora criar uma nova rota em nossa aplicação, para isso vamos alterar nosso arquivo `app.py` e adicionar o seguinte conteúdo: 45 | 46 | ```python 47 | @app.route('/formulario') 48 | def formulario(): 49 | return render_template('formulario.html') 50 | ``` 51 | 52 | Agora que temos uma nova rota chamada de **formulario**, vamos então criar um template `formulario.html` dentro de nosso diretório `templates`, o conteúdo dele será: 53 | 54 | ```html 55 | {% extends 'layout.html' %} 56 | 57 | {% block conteudo %} 58 |

Formulário

59 | 60 | Nome: 61 |
62 | 63 |
64 | Email: 65 |
66 | 67 |
68 | Senha: 69 |
70 | 71 |
72 | 73 |
74 | {% endblock %} 75 | ``` 76 | 77 | Executamos nossa aplicação com o comando `python app.py` e navegamos até `http://127.0.0.1:5000/formulario` para ver que tudo está funcionando corretamente, exceto que, podemos perceber que nosso formulário ainda não apresenta nenhuma funcionalidade, caso venhamos a tentar enviar dados através dele, nos será apresentado um erro **Method Not Allowed**, isto ocorre pois nossa aplicação não está apta a receber requisições **[POST](https://en.wikipedia.org/wiki/POST_(HTTP))**. Para resolvermos esse problema vamos alterar nossa função **formulario()** de forma que ela possa capturar esses dados. Para isso vamos editar nosso arquivo `app.py` 78 | 79 | Primeiramente vamos começar alterando os **imports** de nossa aplicação 80 | 81 | ```python 82 | from flask import Flask, render_template, request, redirect 83 | ``` 84 | 85 | - A função **request()** nos possibilitará trabalharmos com os dados enviados através do formulário 86 | - A função **redirect()** nos possibilitará redirecionarmos o usuário para uma URL após a submissão do formulário 87 | 88 | Agora vamos alterar a função **formulario()** de forma que possamos receber os dados do usuário 89 | 90 | ```python 91 | @app.route('/formulario', methods=['GET','POST']) 92 | def formulario(): 93 | if request.method == 'POST': 94 | req = request.form 95 | 96 | nome = req['nome'] 97 | email = req.get('email') 98 | senha = request.form['senha'] 99 | 100 | print(nome,email,senha) 101 | 102 | return redirect(request.url) 103 | 104 | return render_template('formulario.html') 105 | ``` 106 | 107 | - Adicionamos um **if** que será avaliado como **True** caso seja uma requisição POST 108 | - Uma vez que a requisição é POST, vamos guardar na variável **req** uma estrutura de dados chamada de que é muito similar a um dicionário Python, através dessa estrutura vamos poder acessar cada campo de nosso formulário. 109 | - Através de **req['nome']** acessamos o campo nome e guardamos na variável **nome** 110 | - Através de **req.get('email')** acessamos o campo email e guardamos na variável **email** 111 | - Através de **request.form['senha']** acessamos o campo senha e guardamos na variável **senha** 112 | - Utilizamos a função **print()** para imprirmirmos os dados enviados pelo usuário (**Importante**: Os dados serão impressos em nosso terminal, onde nosso servidor está executando) 113 | - Por fim retornamos o usuário para a mesma URL através da função **redirect()** passando como parâmetro **request.url** que representa a própria URL da página. 114 | - Se eventualmente não estivermos lidando com uma requisição POST, significa que o usuário fez uma requisição GET, em outras palavras, ele deseja ver o conteúdo da página, nesse caso renderizamos o template através da função **render_template()** 115 | 116 | Momento de testarmos nossa aplicação, vamos executá-la através do comando `python app.py` e vamos visitar a URL: `http://127.0.0.1:5000/formulario`. Se fizermos uma submissão do formulário poderemos observar que eles serão impressos em nosso terminal, muito legal, não? Agora já conseguimos capturar os dados enviados através de formulários por usuários! 117 | 118 | Vamos agora aperfeiçoar nosso conhecimento e trabalhar com a biblioteca **[Flask-WTF](https://flask-wtf.readthedocs.io/en/stable/)**, esta que nos possibilitará o gerenciamento de nossos formulários de forma muito mais simples e amigável e também irá colaborar com a segurança de nossa aplicação. 119 | 120 | ## Formulários com Flask-WTF 121 | 122 | Para podermos utilizar a Biblioteca **Flask-WTF** em nossa aplicação é necessário instalarmos ela, recomendamos você fazer a instalação dela com o seu Ambiente Virtual ativado, sendo assim, execute este comando 123 | 124 | ``` 125 | pip install flask-wtf 126 | ``` 127 | 128 | Uma vez instalada com sucesso, agora podemos utilizar ela em nosso projeto, vamos então fazer algumas alterações em nosso arquivo `app.py`, porém, antes disso é importante dizermos que embora a estrutura de nossa aplicação pareça um pouco desorganizada, é porque ainda não entramos no aspecto de como estruturar nossa aplicação, por enquanto estamos focando apenas nos fundamentos, que são essenciais para executarmos diversos trabalhos, sendo assim vamos continuar trabalhando no arquivo `app.py` 129 | 130 | Primeiramente vamos alterar nossos **imports** para que possamos trabalhar com novas funcionalidades 131 | 132 | ```python 133 | from flask import Flask, render_template, request, redirect, session, url_for 134 | from flask_wtf import FlaskForm 135 | from wtforms import StringField, BooleanField, SelectField, TextField, TextAreaField, SubmitField 136 | from wtforms.validators import DataRequired 137 | ``` 138 | 139 | - Na primeira linha importamos **session** que nos permitará trabalhar com variáveis de sessão temporárias e a função **[url_for()](https://flask.palletsprojects.com/en/1.0.x/api/#flask.url_for)** que possibilita construirmos uma URL para uma função específica de nossa aplicação 140 | - Na segunda linha importamos **FlaskForm** de **wtforms** que será essencial para construirmos nosso Formulário 141 | - Na terceira linha importamos todos os campos que vamos utilizar em nosso formulário 142 | - Por fim, na quarta linha importamos o validador **DataRequired** que irá indicar que determinado campo deve ser obrigatoriamente preenchido 143 | 144 | Agora que todos os nossos **imports** estão organizados corretamente é o momento de definirmos o nosso formulário que será representado através de uma Classe Python que chamaremos de **LivroForm**, novamente vamos editar o arquivo `app.py` 145 | 146 | ```python 147 | app.config['SECRET_KEY'] = 'chavesecreta' 148 | 149 | class LivroForm(FlaskForm): 150 | titulo = StringField('Titulo do Livro', validators=[DataRequired()]) 151 | autor = StringField('Nome do Autor', validators=[DataRequired()]) 152 | vivo = BooleanField('Autor está Vivo?') 153 | genero = SelectField('Gênero:',choices=[('aventura','Aventura'),('cientifico','Cientifico'),('romance','Romance')]) 154 | resumo = TextAreaField() 155 | submit = SubmitField('Enviar') 156 | ``` 157 | 158 | 1. Iniciamos atribuindo o valor 'chavesecreta' à nossa variável de configuração **SECRET_KEY**, ela irá nos auxiliar na proteção contra ataques **[Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery)**, importante lembrarmos que não é uma boa prática o que estamos fazendo, o ideal é guardarmos esses dados em uma **[Environment Variable](https://en.wikipedia.org/wiki/Environment_variable)**, vamos deixar dessa forma para simplicidade, uma vez que nosso objetivo é entender os fundamentos. 159 | 2. Através da palavra-chave **class** definimos nosso formulário com o nome de **LivroForm** que recebe como parâmetro **FlaskForm**, este que importamos mais cedo 160 | 3. Definimos a variável **titulo** que será um Campo de String com a label 'Titulo do Livro', veja que utilizamos o validador **DataRequired()** para indicar que o campo deve ser obrigatoriamente preenchido 161 | 4. Definimos a variável **autor** que será um Campo de String com a label 'Nome do Autor', veja que utilizamos o validador **DataRequired()** para indicar que o campo deve ser obrigatoriamente preenchido 162 | 5. Definimos a variável **vivo** que será um Campo Boolean com a label 'Autor está Vivo?' 163 | 6. Definimos a variável **genero** que será um Campo de Seleção contendo as opções 'Aventura', 'Cientifico' e 'Romance' 164 | 7. Definimos a variável **resumo** que será um Campo de Área de Texto 165 | 8. Por fim definimos a variável **submit** que representará nosso botão de submissão contendo a label 'Enviar' 166 | 167 | Agora que temos nosso formulário definido, vamos definir **duas novas rotas** para experimentarmos. Novamente editamos nosso arquivo `app.py`: 168 | 169 | ```python 170 | @app.route('/wtf', methods=['GET','POST']) 171 | def wtf(): 172 | form = LivroForm() 173 | if form.validate_on_submit(): 174 | session['titulo'] = form.titulo.data 175 | session['autor'] = form.autor.data 176 | session['vivo'] = form.vivo.data 177 | session['genero'] = form.genero.data 178 | session['resumo'] = form.resumo.data 179 | 180 | return redirect(url_for('obrigado')) 181 | 182 | return render_template('wtf.html', form=form) 183 | 184 | @app.route('/obrigado') 185 | def obrigado(): 186 | return render_template('obrigado.html') 187 | ``` 188 | 189 | - A primeira rota **wtf()** vai processar o formulário (caso seja uma requisição POST) ou vai renderizar o formulário (caso seja uma requisição GET) 190 | - A segunda rota **obrigado()** vai ser ativada através da função **redirect()**, nela iremos exibir os dados submetidos pelo usuário através das variáveis de sessão 191 | - A variável **form** irá guardar o objeto que representa nosso Formulário, nesse caso **LivroForm** 192 | - Perceba que as variáveis serão atribuídas somente se o formulário for válido, por isso utilizamos o método **validate_on_submit()** 193 | - Caso o formulário não seja válido ou a requisição seja **GET** vamos apenas renderizar o template com o formulário 194 | 195 | Agora precisamos criar nossos templates para que possamos exibir o formulário e os dados submetidos, para isso vamos criar os arquivos `wtf.html` e `obrigado.html` na pasta `templates` 196 | 197 | `wtf.html` 198 | 199 | ```html 200 |

Cadastro de Livros Flask-WTF

201 | 202 |
203 | {{ form.hidden_tag() }} 204 | {{ form.titulo.label }} {{ form.titulo() }} 205 |
206 | {{ form.autor.label }} {{ form.autor() }} 207 |
208 | {{ form.vivo.label }} {{ form.vivo() }} 209 |
210 | {{ form.genero.label }} {{ form.genero() }} 211 |
212 |

Resumo da Obra

213 |
214 | {{ form.resumo() }} 215 |
216 | {{ form.submit() }} 217 |
218 | ``` 219 | 220 | - Este template espera um objeto **form** que foi instanciado de **LivroForm()** como já vimos anteriormente 221 | - O elemento HTML `
` é usado como um container para o formulário web, como também já vimos 222 | - O método **form.hidden_tag()** nos gera um campo escondido que inclui um token que será utilizado para nos proteger contra ataques Cross-Site Request Forgery, tudo que precisamos para ter nosso formulário protegido é incluir esse campo e termos uma **SECRET_KEY** definida 223 | - Por fim renderizamos todos os labels e formulários em nossa página 224 | 225 | Por fim vamos editar nosso arquivo `obrigado.html` com o seguinte conteúdo 226 | 227 | ```html 228 |

Obrigado por cadastar o livro em nossa aplicação

229 | 230 |
    231 |
  • Título: {{ session['titulo'] }}
  • 232 |
  • Autor: {{ session['autor'] }}
  • 233 |
  • Vivo: {{ session['vivo'] }}
  • 234 |
  • Genero: {{ session['genero'] }}
  • 235 |
  • Resumo: {{ session['resumo'] }}
  • 236 |
237 | ``` 238 | 239 | - Através da tag `

` criamos um simples cabeçalho para este template 240 | - Através da tag `
    ` criamos uma lista não-ordenada contendo cinco elementos `
  • ` 241 | - Através da variável temporária podemos exibir os dados enviados através do formulário 242 | 243 | Finalmente podemos executar nossa aplicação com o comando `python app.py`, vamos navegar até o endereço `http://127.0.0.1:5000/wtf` para vermos nosso formulário. Sinta-se a vontade para experimentar com as submissões e testar o formulário e para se aprofundar nas ferramentas visite suas respectivas documentações: **[WTForms](https://wtforms.readthedocs.io/en/stable/)** e **[Flask-WTF](https://flask-wtf.readthedocs.io/en/stable/)** 244 | 245 | Para experimentar o código deste tutorial: https://repl.it/@theakira/Flask-Formularios-Web 246 | 247 | ## Sumarizando 248 | 249 | Neste capítulo estudamos conceitos básicos de formulários, bem como a utilização deles em Flask. Através da biblioteca Flask-WTF aprendemos a criar formulários de uma forma mais eficaz e segura. Uma vez que adquirimos a habilidade de capturar os dados dos usuários, agora nosso caminho é guardá-los em um banco de dados que possa persistí-los e não somente armazená-los em variáveis de sessão. --------------------------------------------------------------------------------