|
|
@ -162,10 +162,17 @@ |
|
|
|
│ ├── layout.html |
|
|
|
│ ├── layout.html |
|
|
|
│ └── page_not_found.html |
|
|
|
│ └── page_not_found.html |
|
|
|
├── contents |
|
|
|
├── contents |
|
|
|
│ └── 2017-10-31.md |
|
|
|
|
|
|
|
├── setup.py |
|
|
|
├── setup.py |
|
|
|
|
|
|
|
├── wsgi.py |
|
|
|
├── MANIFEST.in |
|
|
|
├── MANIFEST.in |
|
|
|
└── requirements.txt</pre> |
|
|
|
└── requirements.txt</pre> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
Essa é a estrutura básica de uma aplicação Flask |
|
|
|
|
|
|
|
(ou basicamente qualquer aplicação Python). Na |
|
|
|
|
|
|
|
sequencia veremos o que cada diretório contém e |
|
|
|
|
|
|
|
sua funcionalidade. |
|
|
|
|
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
@ -275,6 +282,21 @@ |
|
|
|
projeto Python. |
|
|
|
projeto Python. |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<h3><code>├── wsgi.py</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p> |
|
|
|
|
|
|
|
Execução do projeto em modo wsgi. |
|
|
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
Pela forma como WSGI deve ser executado, |
|
|
|
|
|
|
|
normalmente se cria um arquivo chamado |
|
|
|
|
|
|
|
wsgi.py que executa o projeto em modo |
|
|
|
|
|
|
|
WSGI. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
@ -576,146 +598,256 @@ STORAGE='/home/jbiason/src/ata/contents'</code></pre> |
|
|
|
</body> |
|
|
|
</body> |
|
|
|
</html></code></pre> |
|
|
|
</html></code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
<aside class="notes"> |
|
|
|
Para templates Jinja, assim como Django, é |
|
|
|
Para templates Jinja, assim como Django, é |
|
|
|
possível ter um arquivo base do qual todos |
|
|
|
possível ter um arquivo base do qual todos |
|
|
|
os demais decendem. |
|
|
|
os demais decendem. |
|
|
|
|
|
|
|
|
|
|
|
Importante notar aqui o url_for(), que faz |
|
|
|
Importante notar aqui o url_for(), que faz |
|
|
|
a conversão do endpoint para uma URL (no nosso |
|
|
|
a conversão do endpoint para uma URL (no nosso |
|
|
|
caso, do static) e quando endpoint requer um |
|
|
|
caso, do static) e quando endpoint requer um |
|
|
|
parametro (como o nosso "entry_name") ele *tem* |
|
|
|
parametro (como o nosso "entry_name") ele *tem* |
|
|
|
que estar no comando. static requer filename |
|
|
|
que estar no comando. static requer filename |
|
|
|
para saber qual arquivo estático deve ser |
|
|
|
para saber qual arquivo estático deve ser |
|
|
|
carregado. |
|
|
|
carregado. |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h3><code>index.html</code></h3> |
|
|
|
<h3><code>index.html</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
{% block maincontent %} |
|
|
|
{% block maincontent %} |
|
|
|
<div class='entry'> |
|
|
|
<div class='entry'> |
|
|
|
{% for entry, text in data %} |
|
|
|
{% for entry, text in data %} |
|
|
|
<a href="{{ url_for('show_entry', entry_name=entry) }}">{{ entry }}</a> |
|
|
|
<a href="{{ url_for('show_entry', entry_name=entry) }}">{{ entry }}</a> |
|
|
|
{{ text|safe }} |
|
|
|
{{ text|safe }} |
|
|
|
{% endfor %} |
|
|
|
{% endfor %} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
<aside class="notes"> |
|
|
|
O arquivo apresentado na raíz da aplicação. |
|
|
|
O arquivo apresentado na raíz da aplicação. |
|
|
|
|
|
|
|
|
|
|
|
Variáveis com {{ }}, url_for() usando a função |
|
|
|
Variáveis com {{ }}, url_for() usando a função |
|
|
|
"show_entry" com um parametro |
|
|
|
"show_entry" com um parametro |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h3><code>entry.html</code></h3> |
|
|
|
<h3><code>entry.html</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
{% block maincontent %} |
|
|
|
{% block maincontent %} |
|
|
|
<div class="entry"> |
|
|
|
<div class="entry"> |
|
|
|
<div class="title">{{ entry }}</div> |
|
|
|
<div class="title">{{ entry }}</div> |
|
|
|
{{ output|safe }} |
|
|
|
{{ output|safe }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
<aside class="notes"> |
|
|
|
Como apresentar somente uma entrada. |
|
|
|
Como apresentar somente uma entrada. |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h3><code>page_not_found.html</code></h3> |
|
|
|
<h3><code>page_not_found.html</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
{% block maincontent %} |
|
|
|
{% block maincontent %} |
|
|
|
<h2>Page not found</h2> |
|
|
|
<h2>Page not found</h2> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
<aside class="notes"> |
|
|
|
A página quando ocorrer um 404... |
|
|
|
A página quando ocorrer um 404... |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h2><code>templates</code></h2> |
|
|
|
<h3><code>entry_not_found.html</code></h3> |
|
|
|
<h3><code>entry_not_found.html</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
<pre><code>{% extends "layout.html" %} |
|
|
|
{% block maincontent %} |
|
|
|
{% block maincontent %} |
|
|
|
<h2>Entry not found</h2> |
|
|
|
<h2>Entry not found</h2> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
{% endblock %}</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
<aside class="notes"> |
|
|
|
... e quando a entrada não existir |
|
|
|
... e quando a entrada não existir |
|
|
|
(que é a captura do nosso FileNotFoundError) |
|
|
|
(que é a captura do nosso FileNotFoundError) |
|
|
|
</aside> |
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>setup.py</code></h2> |
|
|
|
<h2><code>setup.py</code></h2> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>from setuptools import setup |
|
|
|
<pre><code>from setuptools import setup |
|
|
|
|
|
|
|
|
|
|
|
with open('requirements.txt') as origin: |
|
|
|
with open('requirements.txt') as origin: |
|
|
|
requirements = origin.readlines() |
|
|
|
requirements = origin.readlines() |
|
|
|
|
|
|
|
|
|
|
|
setup(name='Ata', |
|
|
|
setup(name='ata', |
|
|
|
version='0.1', |
|
|
|
version='0.1', |
|
|
|
long_description='A Flask app', |
|
|
|
long_description='A Flask app', |
|
|
|
packages=['ata'], |
|
|
|
packages=['ata'], |
|
|
|
zip_safe=False, |
|
|
|
zip_safe=False, |
|
|
|
include_package_data=True, |
|
|
|
include_package_data=True, |
|
|
|
install_requires=requirements)</code></pre> |
|
|
|
install_requires=requirements)</code></pre> |
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
Um arquivo de setup basicamente padrão. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Duas coisas aqui são importantes: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`zip_safe` deve ser `False`. Quando True, |
|
|
|
|
|
|
|
ele indica que o conteúdo pode ser mantido |
|
|
|
|
|
|
|
em um zip/egg sem problemas. Como teremos |
|
|
|
|
|
|
|
arquivos que tem que ser lidos pelo sistema |
|
|
|
|
|
|
|
operacional, não podemos manter os mesmos |
|
|
|
|
|
|
|
dentro de um zip -- precisamos que o |
|
|
|
|
|
|
|
conteúdo do pacote seja descompactado. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`include_package_data` serve para indicar |
|
|
|
|
|
|
|
ao setup que devem ser considerados também |
|
|
|
|
|
|
|
os arquivos indicados em MANIFEST.in; sem |
|
|
|
|
|
|
|
isso, somente arquivos fontes serão colocados |
|
|
|
|
|
|
|
no pacote. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<h3><code>wsgi.py</code></h3> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pre><code>from ata.main import app as application</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
Sim, "tudo" isso. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2><code>MANIFEST.in</code></h2> |
|
|
|
<h2><code>MANIFEST.in</code></h2> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>recursive-include ata/templates * |
|
|
|
<pre><code>recursive-include ata/templates * |
|
|
|
recursive-include ata/static *</code></pre> |
|
|
|
recursive-include ata/static * |
|
|
|
|
|
|
|
include requirements.txt</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
MANIFEST.in indica diretórios com conteúdo |
|
|
|
|
|
|
|
que deve ser adicionado ao pacote que não |
|
|
|
|
|
|
|
são arquivos fonte. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Documentação, imagens, templates, CSS, |
|
|
|
|
|
|
|
JS, qualquer arquivo dessa natureza que |
|
|
|
|
|
|
|
deva ir para o pacote deve ser listado |
|
|
|
|
|
|
|
aqui. |
|
|
|
|
|
|
|
</aside> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2>Rodando</h2> |
|
|
|
<h2>Rodando</h2> |
|
|
|
<h3>(Dev server)</h3> |
|
|
|
<h3>(Dev server)</h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code> |
|
|
|
<pre><code> |
|
|
|
FLASK_APP=ata/main.py flask run |
|
|
|
FLASK_APP=ata/main.py flask run |
|
|
|
</code></pre> |
|
|
|
</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<pre class="fragment"><code> |
|
|
|
<pre class="fragment"><code> |
|
|
|
export FLASK_RUN=ata/main |
|
|
|
export FLASK_APP=ata/main |
|
|
|
flask run |
|
|
|
flask run |
|
|
|
</code></pre> |
|
|
|
</code></pre> |
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
A partir do Flask 0.12, para executar |
|
|
|
|
|
|
|
a aplicação, é preciso exportar a |
|
|
|
|
|
|
|
variável FLASK_APP com o nome do arquivo |
|
|
|
|
|
|
|
principal. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|
<h2>Rodando de verdade</h2> |
|
|
|
<h2>Rodando de verdade</h2> |
|
|
|
<h3>Dependências de sistema</h3> |
|
|
|
<h3>Dependências de sistema</h3> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>sudo dnf install nginx uwsgi</code></pre> |
|
|
|
<pre><code>sudo dnf install nginx uwsgi uwsgi-plugin-python3</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>sudo yum install nginx uwsgi</code></pre> |
|
|
|
<pre><code>sudo yum install nginx uwsgi uwsgi-plugin-python3</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
<pre><code>sudo apt-get install nginx uwsgi</code></pre> |
|
|
|
<aside class="notes"> |
|
|
|
</section> |
|
|
|
Vamos precisar de dois pacotes do sistema |
|
|
|
</section> |
|
|
|
operacional: nginx e uwsgi. O uwsgi vai |
|
|
|
|
|
|
|
servir para "envelopar" a aplicação Flask |
|
|
|
|
|
|
|
e expor o WSGI; nginx nós vamos usar para |
|
|
|
|
|
|
|
expor a aplicação ao mundo. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<h2>Rodando de verdade</h2> |
|
|
|
|
|
|
|
<h3>Virtualenv (primeira vez)</h3> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pre><code>mkdir -p /usr/local/venv |
|
|
|
|
|
|
|
mkdir -p /usr/local/apps |
|
|
|
|
|
|
|
python -m venv /usr/local/venv/ata</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
Esses passos são necessários apenas se for |
|
|
|
|
|
|
|
a primeira instalação: precisamos de um |
|
|
|
|
|
|
|
diretório para o aplicativo e um diretório |
|
|
|
|
|
|
|
para os virtualenvs -- e inicializar o |
|
|
|
|
|
|
|
virtualenv da aplicação. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<h2>Rodando de verdade</h2> |
|
|
|
|
|
|
|
<h3>Instalando novas versões</h3> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pre><code>tar xzf Ata-0.1.tar.gz --one-top-level=/usr/local/apps/ |
|
|
|
|
|
|
|
ln -sf /usr/local/apps/Ata-0.1 /usr/local/apps/ata |
|
|
|
|
|
|
|
source /usr/local/venv/ata/bin/activate |
|
|
|
|
|
|
|
python3 -m pip install -U -r /usrlocal/apps/ata/requirements.txt</code></pre> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<aside class="notes"> |
|
|
|
|
|
|
|
O que fazemos aqui é ter um diretório para as |
|
|
|
|
|
|
|
aplicações (porque uma pessoa não pára simplesmente |
|
|
|
|
|
|
|
na sua primeira aplicação); como o diretório |
|
|
|
|
|
|
|
vem versionado, vamos aproveitar isso para termos |
|
|
|
|
|
|
|
várias versões disponíveis ao mesmo tempo; |
|
|
|
|
|
|
|
para mudar a versão, mudamos o link simbólico. |
|
|
|
|
|
|
|
</aside> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
|
|
|
<h2>Rodando de verdade</h2> |
|
|
|
|
|
|
|
<h3>Primeira configuração uwsgi</h3> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p><code>/etc/uwsgi.d/ata.ini</code></p> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pre><code>[uwsgi] |
|
|
|
|
|
|
|
chdir=/usr/local/apps/ata |
|
|
|
|
|
|
|
module=wsgi |
|
|
|
|
|
|
|
plugins=python3 |
|
|
|
|
|
|
|
virtualenv=/usr/local/venv/ata |
|
|
|
|
|
|
|
uid=uwsgi |
|
|
|
|
|
|
|
gid=uwsgi |
|
|
|
|
|
|
|
processes=4 |
|
|
|
|
|
|
|
socket=/var/run/uwsgi/ata.sock</code></pre> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
<section data-background='_images/thats-all-folks.jpg'> |
|
|
|
<section data-background='_images/thats-all-folks.jpg'> |
|
|
|
<section> |
|
|
|
<section> |
|
|
|