Pular para o conteúdo principal

Crie um gerenciador de tarefas em tempo real com FastHTML e MongoDB

Um tutorial completo sobre como usar ferramentas nativas em Python para operações CRUD assíncronas e interatividade com HTMX.
Atualizado 17 de jun. de 2026  · 5 min lido

FastHTML e MongoDB oferecem uma abordagem ágil e nativa em Python para o desenvolvimento web moderno. Neste tutorial, vamos construir um aplicativo de gerenciador de tarefas reativo e em tempo real, demonstrando um ciclo CRUD completo (Create, Read, Update, Delete) em um único arquivo Python, fácil de manter. Para colocar a mão na massa com MongoDB em Python, recomendo o curso Introduction to MongoDB in Python.

O que é FastHTML?

FastHTML é um framework minimalista e de alta performance, construído sobre as bases do FastAPI. Ele introduz um paradigma de HTML em Python, permitindo que você crie frontends inteiros com funções Python reutilizáveis, em vez de templates tradicionais.

Seu grande diferencial está na integração nativa com HTMX. Usando atributos HTML simples para acionar atualizações no servidor, o HTMX permite criar experiências de single-page application sem a complexidade de um stack pesado em JavaScript.

O que é MongoDB?

MongoDB é o principal banco NoSQL de uso geral baseado em documentos. Seu esquema flexível e o uso de documentos BSON (semelhantes a JSON) o tornam ideal para desenvolvimento moderno e iterativo.

Para Python, usamos o driver assíncrono oficial, Motor, que oferece uma interface não bloqueante — perfeita para a arquitetura de alto desempenho do FastAPI e do FastHTML.

Por que este stack se destaca

A combinação dessas tecnologias cria um ambiente de desenvolvimento extremamente produtivo:

  • Segurança de tipos com Pydantic e MongoDB: o FastHTML aproveita o Pydantic para modelagem e validação de dados. Esses modelos se mapeiam naturalmente à estrutura de documentos do MongoDB, oferecendo uma experiência "code-first" que elimina boilerplate pesado de ORMs.
  • Performance assíncrona de ponta a ponta: ao combinar o Motor com o núcleo assíncrono do FastHTML, as operações no banco não bloqueiam o event loop. Isso garante alta concorrência e baixa latência — essenciais para apps reativos e em tempo real.
  • Menos troca de contexto: você gerencia esquema do banco, lógica de backend e componentes de frontend dentro de um ecossistema Python unificado, acelerando bastante a entrega.

Configuração e conexão

Você vai precisar de alguns pré-requisitos para acompanhar este tutorial: 

  • Python 3.8+
  • Instância MongoDB: instalação local ou um cluster MongoDB Atlas (recomendado para recursos em tempo real)
  • Conhecimentos básicos: familiaridade com decorators em Python e estrutura básica de HTML.

Inicialização do projeto

Para mostrar a eficiência deste stack, vamos implementar todo o aplicativo — incluindo configuração do banco, modelos de dados e rotas reativas — em um único arquivo app.py.

Instalação 

Vamos precisar do framework FastHTML, do Motor (driver MongoDB assíncrono oficial) e do Uvicorn para o servidor ASGI.

Configuração da conexão com o MongoDB

Usamos AsyncIOMotorClient para estabelecer uma conexão não bloqueante. Assim, enquanto o app aguarda o I/O do banco, ele continua processando outras requisições concorrentes.

import os
from motor.motor_asyncio import AsyncIOMotorClient
from fasthtml.common import *
from bson import ObjectId
from pydantic import Field, BaseModel
from pymongo.errors import ServerSelectionTimeoutError, ConnectionFailure


# configure MongoDB
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://localhost:27017/") # your Mongo URI
DB_NAME = "fasthtml_tasks_db"
COLLECTION_NAME = "tasks"

# Initialize the async client and reference our collections
client = AsyncIOMotorClient(MONGO_URI)
db = client[DB_NAME]
collection = db[COLLECTION_NAME]

# FastHTML Application Initialization
app = FastHTML()

Definindo o modelo de dados 

Em um fluxo orientado a documentos, o esquema vive no seu código de aplicação. Usamos o Pydantic v2 para fazer a ponte entre o ObjectId BSON do MongoDB e strings Python padrão. Isso garante que todo documento que entra ou sai do banco seja validado conforme nossos requisitos.

Definimos uma classe PyObjectId personalizada. Isso é necessário porque o Pydantic não sabe lidar nativamente com o tipo ObjectId do MongoDB. Com __get_pydantic_core_schema__, instruímos o Pydantic a tratar esse tipo como string em JSON, mas validá-lo como BSON no banco.

python
from pydantic import BaseModel, Field
from pydantic_core import core_schema
from pydantic.json_schema import JsonSchemaValue

class PyObjectId(ObjectId):
    """Custom type to bridge MongoDB ObjectId and Pydantic v2 validation."""
    @classmethod
    def __get_pydantic_core_schema__(cls, source_type, handler):
        # Defines how Pydantic should validate this type
        return core_schema.no_info_plain_validator_function(cls.validate)

    @classmethod
    def validate(cls, v):
        if isinstance(v, ObjectId): return v
        if isinstance(v, str) and ObjectId.is_valid(v): return ObjectId(v)
        raise ValueError("Invalid ObjectId")

    @classmethod
    def __get_pydantic_json_schema__(cls, _core_schema, handler) -> JsonSchemaValue:
        # Ensures the OpenAPI/JSON schema reflects this as a string
        return {"type": "string"}

class Task(BaseModel):
    """Pydantic model representing the Task document schema."""
    # Maps MongoDB's internal '_id' to a developer-friendly 'id' field
    id: PyObjectId | None = Field(None, alias='_id')
    title: str
    description: str | None = None
    completed: bool = False

    model_config = ConfigDict(
        arbitrary_types_allowed=True
    )

Layout e rota inicial 

O componente de layout é uma função de ordem superior reutilizável que envolve nossas views. Assim, dependências essenciais, como Tailwind CSS para estilo e HTMX para interatividade, ficam consistentes em toda a aplicação.

Ao usar os componentes em caixa-alta do FastHTML (como Main e Div), mantemos uma estrutura limpa e pythônica que espelha a árvore HTML.

# A responsive layout using Tailwind CSS and the HTMX CDN
def layout(*comps):
    """Wraps the application content in a consistent container."""
    return Main(
        Div(
            H1('📝 Real-Time FastHTML Task Manager', 
               cls='text-3xl font-bold mb-8 text-center text-gray-800'),
            *comps,
            cls='container mx-auto p-6 max-w-2xl'
        )
    )

@app.get('/')
async def home():
    """Initial route rendering the core application layout."""
    return layout(
        await TaskList(), # Fetches and displays existing tasks (Read)
        TaskForm()        # Renders the entry form (Create)
    )

Agora, ao executar o app, sua interface ficará assim:

Imagem: captura de tela após a configuração

Ainda não há tarefas. Vamos adicionar e atualizar tarefas na próxima seção.

Implementação CRUD completa

Read: exibindo tarefas (GET /)

Para exibir as tarefas, buscamos todos os documentos e renderizamos dentro de um componente. Porém, em um cenário real, o banco pode estar offline. Nossa versão atualizada de TaskList lida com isso de forma elegante, oferecendo passos de troubleshooting direto na interface.

Busca de dados resiliente 

Usamos collection.find().to_list(length=None) para recuperar documentos de forma assíncrona. Ao envolver isso em um bloco try/except, conseguimos detectar se o MongoDB está desconectado e dar feedback imediato ao usuário.

async def TaskList():
    """Fetches documents from MongoDB and hydrates the Task list view with error handling."""
    try:
        tasks_data = await collection.find().to_list(length=None)
        tasks = [Task(**doc) for doc in tasks_data]
    except (ServerSelectionTimeoutError, ConnectionFailure, Exception) as e:
        # Catch MongoDB connection errors and provide troubleshooting tips
        return Div(
            H2('Current Tasks', cls='text-xl font-semibold mb-4'),
            Div(
                P('⚠️ MongoDB is not running.', cls='text-red-600 font-semibold mb-2'),
                P('To start MongoDB:', cls='text-gray-600 mb-1'),
                P('1. brew install mongodb-community', cls='text-gray-500 text-sm ml-4'),
                P('2. brew services start mongodb-community', cls='text-gray-500 text-sm ml-4'),
                cls='p-4 bg-yellow-50 border border-yellow-200 rounded'
            ),
            id='task-list'
        )

    return Div(
        H2('Current Tasks', cls='text-xl font-semibold mb-4'),
        *[TaskItem(task) for task in tasks] if tasks else P('No tasks yet. Add one below!', cls='text-gray-500 italic p-4'),
        id='task-list',
        cls='bg-white rounded-lg shadow-sm border border-gray-200'
    )

Create: adicionando uma nova tarefa

O fluxo de criação usa um formulário HTML com atributos HTMX. Na versão atualizada, extraímos explicitamente os dados do formulário do objeto Request e usamos model_dump para preparar o documento para inserção no MongoDB.

@app.post('/add-task')
async def add_task(req: Request):
    """Create: Inserts a task and returns the refreshed list."""
    try:
        form_data = await req.form()
        task = Task(
            title=form_data.get('title', ''),
            description=form_data.get('description') or None
        )
        
        # model_dump(by_alias=True) ensures 'id' is converted back to '_id' for Mongo
        task_dict = task.model_dump(exclude_none=True, by_alias=True)
        
        # Remove _id if it's None so MongoDB can generate its own unique ID
        if '_id' in task_dict and task_dict['_id'] is None:
            del task_dict['_id']
            
        await collection.insert_one(task_dict)
        return await TaskList()
    except Exception as e:
        return Div(P(f'Error: {str(e)}', cls='text-red-500 p-4'), id='task-list')

Se executarmos o código abaixo no terminal:

curl -X POST http://localhost:8000/add-task -d "title=Complete FastHTML MongoDB integration" -d "description=Verify that tasks can be created, updated, and deleted successfully" -H "Content-Type: application/x-www-form-urlencoded"

Você verá que a nova tarefa foi adicionada:

Imagem: captura de tela após adicionar uma tarefa

Update: alternando a conclusão

Para lidar com atualizações, usamos uma requisição PATCH. Isso demonstra um "micro-refresh", em que apenas a linha da tarefa é atualizada no banco e re-renderizada na UI usando seu ID específico.

@app.patch('/toggle-task/{task_id}')
async def toggle_task(task_id: str):
    """Update: Toggles completion status and returns the single row fragment."""
    task_doc = await collection.find_one({"_id": ObjectId(task_id)})
    if not task_doc: raise HTTPException(404, "Task not found")

    await collection.update_one(
        {"_id": ObjectId(task_id)},
        {"$set": {"completed": not task_doc['completed']}}
    )

    # Return only the updated TaskItem for a surgical DOM update
    updated_doc = await collection.find_one({"_id": ObjectId(task_id)})
    return TaskItem(Task(**updated_doc))

Delete: removendo uma tarefa

A exclusão é iniciada pelo HTMX. Assim que o MongoDB confirma a remoção, o servidor retorna uma resposta Empty(). O HTMX interpreta essa resposta vazia como um sinal para remover o elemento alvo (closest div) do DOM.

@app.delete('/delete-task/{task_id}')
async def delete_task(task_id: str):
    """Delete: Removes a task from MongoDB."""
    await collection.delete_one({"_id": ObjectId(task_id)})
    # Signal HTMX to remove the element
    return Empty()

Se fizermos…

curl -X DELETE http://localhost:8000/delete-task/695968244236010c04f313fa

…a tarefa é excluída.

Imagem: captura de tela após a exclusão 

Você encontra o script completo no GitHub.

Conclusão

Ao adotar um stack moderno e centrado em Python, você construiu um app reativo que evita a complexidade tradicional dos frameworks JavaScript no cliente. Essa arquitetura oferece diversas vantagens para o desenvolvimento web atual. A sinergia entre a UI baseada em componentes do FastHTML e o modelo flexível de documentos do MongoDB permite manter lógica de negócio, integridade dos dados e apresentação em um único ecossistema coeso. Essa abordagem "tudo em Python" reduz significativamente o esforço de desenvolvimento e a complexidade de deploy.

Próximos passos para você

  • Autenticação de usuários: use dependências do FastAPI para restringir listas de tarefas a usuários específicos, armazenando user_id no documento da tarefa.
  • Consultas avançadas: use o framework de agregação do MongoDB ou filtros simples para adicionar as visões "Ativas" e "Concluídas" na sua UI.
  • Deploy: publique seu app.py usando Uvicorn atrás de um proxy reverso NGINX para performance de produção.

FAQs

É possível usar MongoDB Change Streams com FastHTML para atualizações "push"?

Sim! Como tanto o Motor quanto o FastHTML são assíncronos, você pode usar um loop async for em Python para escutar um Change Stream do MongoDB. Depois, é só combinar com o EventStream do FastHTML (Server-Sent Events) para enviar atualizações em tempo real a todos os usuários conectados sempre que um documento mudar no banco.

Por que usar modelos Pydantic em vez de dicionários Python brutos com MongoDB?

Embora o MongoDB aceite dicionários brutos, o Pydantic funciona como o "esquema da aplicação". Ele oferece validação de dados, type hints e valores padrão (como definir completed como False automaticamente). Isso evita que "dados sujos" entrem na coleção e facilita muito o debug conforme o projeto cresce.

Como lidar com migrações de banco de dados nesse stack?

Uma das grandes forças do MongoDB é o esquema flexível. Você não precisa de "migrações" no sentido tradicional do SQL. Se adicionar um novo campo ao seu modelo Task, basta fornecer um valor padrão no Pydantic. Documentos existentes no MongoDB que não tenham esse campo serão "hidratados" com o valor padrão quando forem carregados na aplicação.

Posso adicionar busca avançada a este gerenciador de tarefas?

Com certeza. O MongoDB tem um índice $text poderoso e um Atlas Search ainda mais avançado (baseado em Lucene). Você pode criar facilmente uma barra de busca no FastHTML usando hx-get que dispara um pipeline de agregação no MongoDB para filtrar tarefas por palavras-chave conforme o usuário digita.

Como esse stack lida com alta concorrência em comparação a Django ou Flask?

FastHTML é um framework separado inspirado no FastAPI. Ele usa o padrão ASGI e consegue lidar com milhares de conexões simultâneas em um único processo. Em conjunto com o pool de conexões não bloqueante do Motor, seu app não fica "preso" aguardando respostas do banco, tornando-se muito mais eficiente para apps em tempo real e com alto tráfego.


Karen Zhang's photo
Author
Karen Zhang
LinkedIn

Karen é uma engenheira de dados apaixonada por criar plataformas de dados escalonáveis. Ela tem experiência em automação de infraestrutura com o Terraform e está animada para compartilhar seus conhecimentos em postagens de blog e tutoriais. Karen é uma construtora de comunidades e é apaixonada por promover conexões entre profissionais de dados.

Tópicos

Principais cursos da DataCamp

Programa

Engenheiro de dados Em Python

40 h
Adquira habilidades sob demanda para ingerir, limpar e gerenciar dados com eficiência, além de programar e monitorar pipelines, destacando você no campo da engenharia de dados.
Ver detalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado

Tutorial

Desenvolvimento backend com Python: guia completo para iniciantes

Este guia completo ensina os fundamentos do desenvolvimento backend com Python. Aprenda conceitos básicos, frameworks e boas práticas para começar a criar aplicações web.
Oluseye Jeremiah's photo

Oluseye Jeremiah

Tutorial

Tutorial FastAPI: Uma introdução ao uso da FastAPI

Explore a estrutura FastAPI e descubra como você pode usá-la para criar APIs em Python
Moez Ali's photo

Moez Ali

SQLAlchemy_Tutorial.

Tutorial

Tutorial de SQLAlchemy com exemplos

Aprenda a acessar e executar consultas SQL em todos os tipos de bancos de dados relacionais usando objetos Python.
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

Tutorial de instalação do Anaconda no Windows

Este tutorial demonstrará como você pode instalar o Anaconda, um poderoso gerenciador de pacotes, no Microsoft Windows.
DataCamp Team's photo

DataCamp Team

Tutorial

Tutorial de como executar consultas SQL em Python e R

Aprenda maneiras fáceis e eficazes de executar consultas SQL em Python e R para análise de dados e gerenciamento de bancos de dados.
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

21 ferramentas essenciais do Python

Aprenda sobre as ferramentas Python essenciais para o desenvolvimento de software, raspagem e desenvolvimento da Web, análise e visualização de dados e aprendizado de máquina.
Abid Ali Awan's photo

Abid Ali Awan

Ver maisVer mais