---
tags: web,day2
robots: noindex, nofollow
lang: pt-br
---
# 17 - CLI
Command Line Interface
### Posts
O próximo passo é criarmos funções que servirão de **controllers** para nossos dados, essas funções serão úteis para abstrair o acesso ao MongoDB e serão usadas tanto pelas views quanto pela CLI.
`exemplos/day2/flask/blog/posts.py`
```python
from __future__ import annotations
from datetime import datetime
from blog.database import mongo
def get_all_posts(published=True):
posts = mongo.db.posts.find({"published": published})
return posts.sort("date")
def get_post_by_slug(slug: str) -> dict:
post = mongo.db.posts.find_one({"slug": slug})
return post
def update_post_by_slug(slug: str, data: dict) -> dict:
return mongo.db.posts.find_one_and_update({"slug": slug}, {"$set": data})
def new_post(title: str, content: str, published: bool = True) -> str:
slug = title.replace("_", "-").replace(" ", "-").lower()
# TODO: Evitar a entrada de posts com slug duplicado?
new = mongo.db.posts.insert_one(
{
"title": title,
"content": content,
"published": published,
"slug": slug,
"date": datetime.now(),
}
)
return slug
```
Nesse ponto já podemos abrir o `shell` e testar se está tudo funcionando:
```python
In [1]: from blog.posts import get_all_posts, get_post_by_slug, update_post_by_slug, new_post
# Criar um novo post
In [2]: new_post(title="Flask é legal", content="Eu gosto de flask")
Out[2]: 'flask-é-legal'
# Buscar o post mais recente
In [3]: list(get_all_posts())[-1]
Out[3]:
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'),
'title': 'Flask é legal',
'content': 'Eu gosto de flask',
'published': True,
'slug': 'flask-é-legal',
'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
# Buscar pelo slug
In [4]: get_post_by_slug("flask-é-legal")
Out[4]:
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'),
'title': 'Flask é legal',
'content': 'Eu gosto de flask',
'published': True,
'slug': 'flask-é-legal',
'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
# Alterar um post
In [5]: update_post_by_slug("flask-é-legal", {"content": "Novo contéudo alterado."})
Out[5]:
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'),
'title': 'Flask é legal',
'content': 'Eu gosto de flask',
'published': True,
'slug': 'flask-é-legal',
'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
# Confirmar a alteração
In [6]: get_post_by_slug("flask-é-legal")
Out[6]:
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'),
'title': 'Flask é legal',
'content': 'Novo contéudo alterado.',
'published': True,
'slug': 'flask-é-legal',
'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
```
### CLI
O Flask oferece a possibilidade de extendermos a sua `CLI` e para fazer isso vamos criar no arquivo `commands.py` novos comandos:
- `post new`
- `post list`
- `post get`
- `post update`
`exemplos/day2/flask/blog/commands.py`
```python
import click
from blog.posts import (
get_all_posts,
get_post_by_slug,
new_post,
update_post_by_slug
)
@click.group()
def post():
"""Manage posts"""
@post.command()
@click.option("--title")
@click.option("--content")
def new(title, content):
"""Creates a new post"""
new = new_post(title=title, content=content)
click.echo(f"New post {new} created!")
@post.command("list")
def _list():
"""Lists all posts"""
for post in get_all_posts():
click.echo(post)
@post.command()
@click.argument("slug")
def get(slug):
"""Get post by slug"""
post = get_post_by_slug(slug)
click.echo(post or "post not found")
@post.command()
@click.argument("slug")
@click.option("--content", default=None, type=str)
@click.option("--published", default=None, type=str)
def update(slug, content, published):
"""Update post by slug"""
data = {}
if content is not None:
data["content"] = content
if published is not None:
data["published"] = published.lower() == "true"
update_post_by_slug(slug, data)
click.echo("Post updated")
def configure(app):
app.cli.add_command(post)
```
Agora inicializamos o módulo `commands no arquivo de settings`
`settings.toml`
```toml
[default]
mongo_uri = "mongodb://localhost:27017/blog"
extensions = [
"blog.database:configure",
"blog.commands:configure" # NEW
]
```
E podemos testar no terminal.
```
export FLASK_APP=blog.app:create_app
export FLASK_ENV=development
```
```bash
flask post --help
Usage: flask post [OPTIONS] COMMAND [ARGS]...
Manage posts
Options:
--help Show this message and exit.
Commands:
get Get post by slug
list Lists all posts
new Creates a new post
update Update post by slug
```
```bash
flask post get flask-é-legal
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'), 'title': 'Flask é legal', 'content': 'Novo contéudo alterado.', 'published': True, 'slug': 'flask-é-legal', 'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
```
```bash
flask post list
{'_id': ObjectId('62b613a07e4b3c31107abd2b'), 'title': 'Meu primeiro post', 'content': 'Este é meu primeiro blog post', 'published': True, 'slug': 'meu-primeiro-post'}
{'_id': ObjectId('62ba00a02a93f608c1b6978f'), 'title': 'Another post', 'content': 'this is even another', 'published': True, 'slug': 'another-post', 'date': datetime.datetime(2022, 6, 27, 20, 10, 24, 914000)}
{'_id': ObjectId('62ba02d2ba946f4d625c87a7'), 'title': 'Flask é legal', 'content': 'Novo contéudo alterado.', 'published': True, 'slug': 'flask-é-legal', 'date': datetime.datetime(2022, 6, 27, 20, 19, 46, 776000)}
```
```bash
flask post new --title "Flask na linha de
comando" --content "É muito legal o CLI do Flask"
New post 62ba0a2528fe9264f931f142 created!
```
```bash
flask post update flask-é-legal --published "false"
Post updated
```
Na próxima aula continuaremos adicionando views, templates e uma interface administrativa a nossa aplicação :)