---
# System prepended metadata

title: 18 Blueprints
tags: [web, day2]

---

---
tags: web,day2
robots: noindex, nofollow
lang: pt-br
---

# 18 Blueprints

Blueprint é o padrão usado pelo flask para extendermos nossa aplicação com funcionalidades,
em nosso caso teremos as views para o nosso blog.

- / -> listar todos os posts
- /new -> formulário para criar novo post
- /slug-do-post -> Ler um post especifico

Vamos começar pelos templates

Em todas essas URLs iremos renderizar um template base usando o framework CSS **Bootstrap**, portanto precisaremos da extensão Flask-Bootstrap e para inicializa-la faremos 2 alterações

`setup.py`
```python

    install_requires=["flask", "flask-pymongo", "dynaconf", "flask-bootstrap"]  # NEW

```
Depois rodamos na mesma pasta onde está o `setup.py`

```bash
pip install -e .
```

E no `settings.toml`

```toml
[default]
mongo_uri = "mongodb://localhost:27017/blog"
extensions = [
    "blog.database:configure",
    "blog.commands:configure",
    "flask_bootstrap:Bootstrap"  # NEW
]
```

## Templates

Agora podemos criar os templates:

`templates/base.html.j2`
```html
{% extends "bootstrap/base.html" %}
{% block title %}{{config.get('TITLE')}}{% endblock %}

{% block navbar %}
<div class="navbar container">
<div class="navbar-header">
    <a class="navbar-brand" href="/">
    <img alt="Brand" src="https://via.placeholder.com/150x50?text=BLOG">
    </a>
</div>
</div>
{% endblock %}
```

`templates/index.html.j2`
```html
{% extends "base.html.j2" %}

{% block content %}
<div class="container">
<h1>{{config.get('TITLE')}}</h1>

<div class="jumbotron">
<ul class="list-group">
    {% for post in posts %}
    <li class="list-group-item">
        <a href="{{url_for('post.detail', slug=post.slug)}}">{{post.title}}</a>
    </li>
    {% endfor %}
</ul>
</div>

</div>
{% endblock %}
```

`templates/post.html.j2`
```html
{% extends "base.html.j2" %}
{% block content %}
<div class="container">
<h1>{{ post.title }}</h1>

<div class="jumbotron">
<small>{{ post.date }}</small>
<p>
    {{ post.content }}
</p>
</div>
</div>
{% endblock %}
```

`templates/form.html.j2`
```html
{% extends "base.html.j2" %}
{% block content %}
<div class="container">
<h1>New Post</h1>

<div class="jumbotron">

<form action="/new" method="post">
    <label for="title">Title:</label><br>
    <input type="text" name="title" /><br>
    <label for="content">Content:</label><br>
    <textarea name="content" cols="30" rows="5"></textarea><br>
    <input type="submit" value="Enviar">
</form>

</div>
</div>
{% endblock %}
```

### Blueprint

Vamos criar o nosso blueprint no arquivo `view.py` esse Blueprint será um módulo independente contendo as URLs para lidar com os posts da aplicação.


`views.py`
```python
from flask import (
    Blueprint,
    render_template,
    abort,
    request,
    url_for,
    redirect,
)
from blog.posts import (
    get_all_posts,
    get_post_by_slug,
    new_post,
)


bp = Blueprint("post", __name__,  template_folder="templates")


@bp.route("/")
def index():
    posts = get_all_posts()
    return render_template("index.html.j2", posts=posts)


@bp.route("/new", methods=["GET", "POST"])
def new():
    if request.method == "POST":
        title = request.form.get("title")
        content = request.form.get("content")
        slug = new_post(title, content)
        return redirect(url_for("post.detail", slug=slug))
    return render_template("form.html.j2")


@bp.route("/<slug>")
def detail(slug):
    post = get_post_by_slug(slug)
    if not post:
        return abort(404, "Post Not Found")
    return render_template("post.html.j2", post=post)


def configure(app):
    app.register_blueprint(bp)
```

E para invocar a factory `configure` vamos adicionar ao arquivo `settings.toml`


```toml
[default]
mongo_uri = "mongodb://localhost:27017/blog"
title = "Meu Blog"  # NEW
extensions = [
    "blog.database:configure",
    "blog.commands:configure",
    "flask_bootstrap:Bootstrap",
    "blog.views:configure"  # NEW
]

```

Agora ao executar podemos acessar a página inicial e ver os posts criados.

```bash
FLASK_APP=blog.app:create_app FLASK_ENV=development flask run
```

Em http://127.0.0.1:5000/ 
![](https://github.com/rochacbruno/python-web-api/raw/day2/docs/day2/imgs/flask_blog_index.png)


Para criar um novo blog post acesse http://127.0.0.1:5000/new

![](https://github.com/rochacbruno/python-web-api/raw/day2/docs/day2/imgs/flask_blog_new.png)


E após criar será feito o redirecionamento para http://127.0.0.1:5000/criei-um-blog-com-flask 

![](https://github.com/rochacbruno/python-web-api/raw/day2/docs/day2/imgs/flask_blog_detail1.png)


### Markdown

Escrevemos o nosso post usando a linguagem Markdown mas na imagem acima o conteúdo em markdown não foi corretamente renderizado, para resolver vamos adicionar ao sistema de templates uma função responsável por renderizar markdown.


O primeiro passo é instalar um renderizador de markdown, altere o `setup.py`


```setup.py
from setuptools import setup

setup(
    name="flask_blog",
    version="0.1.0",
    packages=["blog"],
    install_requires=[
        "flask",
        "flask-pymongo",
        "dynaconf",
        "flask-bootstrap",
        "mistune",  # NEW
    ],
)
```

Execute agora a instalação no diretório onde está o `setup.py`

```bash
pip install -e .
```

Agora vamos alterar o arquivo `plugins.py` e vamos aproveitar para adicionar também um filtro
para formatação de datas.


`exemplos/day2/flask/blog/plugins.py`
```python
from mistune import markdown


def configure(app):
    # adiciona {{ markdown('texto') }} para os templates
    app.add_template_global(markdown)

    # adiciona {{ date | format_date }}
    app.add_template_filter(lambda date: date.strftime("%d-%m-%Y"), "format_date")

```

Adicionamos o módulo `plugins` ao `settings.toml`

```toml
[default]
mongo_uri = "mongodb://localhost:27017/blog"
title = "Meu Blog"
extensions = [
    "blog.database:configure",
    "blog.commands:configure",
    "flask_bootstrap:Bootstrap",
    "blog.views:configure",
    "blog.plugins:configure",  # NEW
]
```


Agora podemos mudar o template `post.html.j2` e adicionar a renderização do markdown.

```html
{% extends "base.html.j2" %}
{% block content %}
<div class="container">
<h1>{{ post.title }}</h1>

<div class="jumbotron">
<small>{{ post.date | format_date }}</small>  <!-- NEW -->
<p>
    {{ markdown(post.content) }}   <!-- NEW -->
</p>
</div>
</div>
{% endblock %}
```

E agora sim temos o conteúdo melhor formatado.

![](https://github.com/rochacbruno/python-web-api/raw/day2/docs/day2/imgs/flask_blog_detail2.png)
