--- 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 :)