Skip to main content
O Django é um framework web em Python com ORM e sistema de migrations integrados, que se comunica com o PostgreSQL por meio do driver psycopg 3. Neste guia, você vai conectar um novo projeto Django ao ClickHouse Managed Postgres por meio do PgBouncer, criar uma tabela todos com uma migration e atender a requisições de criação, leitura, atualização e exclusão a partir de uma pequena view JSON. Todas as conexões usam TLS com verificação completa de certificados.

Pré-requisitos

  • Python 3.12 ou superior, conforme exigido pelo Django 6. Este guia foi testado com Python 3.13, Django 6.1.1 e psycopg 3.3.6.
  • Uma conta do ClickHouse Cloud
  • psql, para criar o banco de dados. Você também pode executar a instrução CREATE DATABASE no SQL Console.

Crie um serviço ClickHouse Managed Postgres

No console do ClickHouse Cloud, clique em New service e selecione Postgres. A instância estará pronta em poucos minutos. Para um passo a passo completo, consulte o guia de início rápido.

Obtenha os detalhes de conexão

Clique em Connect na barra lateral esquerda do seu serviço. O modal exibe seu nome de usuário, senha, servidor e porta, além de um seletor Directly / via PgBouncer. Este guia conecta o Django por meio do PgBouncer incluído, na porta 6432. Uma aplicação Django em produção geralmente executa vários processos worker em várias máquinas, e cada um deles abre as próprias conexões. O PgBouncer opera no modo de pooling de transações e permite que todos esses processos compartilhem um pequeno número de conexões com o Postgres. O Django exige algumas configurações para funcionar com pooling de transações; este guia as inclui e as explica em Configurações do PgBouncer para Django. Selecione via PgBouncer para ver os detalhes de conexão com pooling. A porta muda para 6432, e a string de conexão inclui sslmode=verify-full. No modal, clique em Download CA certificate. Você também pode baixá-lo em Settings → CA Certificate. O certificado é exclusivo da sua instância, permitindo que o driver o use para confirmar que está se comunicando com o seu servidor.

Configure o projeto

Crie um diretório para o projeto com um ambiente virtual, instale o Django e o psycopg 3 e crie um projeto Django com um app todos:
O psycopg[binary] já inclui uma versão recente da libpq, então você não precisa ter o PostgreSQL instalado localmente.
Vai adicionar a um aplicativo existente?Pule os comandos acima. No ambiente virtual do seu projeto, execute pip install "psycopg[binary]" e, em seguida, siga para Configurar a conexão, que substitui a configuração DATABASES do SQLite. Para copiar seus dados do SQLite:
  • Antes de alterar DATABASES, execute python manage.py dumpdata --natural-foreign --natural-primary -e contenttypes -e auth.permission -o data.json.
  • Depois de executar python manage.py migrate, execute python manage.py loaddata data.json.

Configure a conexão

Mova o certificado da CA que você baixou para o diretório do projeto, ao lado de manage.py, e renomeie-o para ca-certificate.pem. Crie um banco de dados para a aplicação. Substitua <PASSWORD> e o host pelos valores exibidos no modal Connect:
Defina o host e a senha como variáveis de ambiente para mantê-los fora do seu código:
Abra mysite/settings.py, adicione import os abaixo de from pathlib import Path e substitua a configuração DATABASES por:
mysite/settings.py
O Django repassa as chaves de OPTIONS ao psycopg, que as encaminha ao libpq. Com sslmode definido como verify-full, o libpq verifica se o certificado do servidor foi assinado pela CA do seu serviço e se corresponde ao hostname. BASE_DIR torna absoluto o caminho do certificado, de modo que a configuração funciona independentemente do diretório em que você inicia o Django.
Se sslrootcert apontar para a CA errada, a conexão falha com SSL error: certificate verify failed. Sem sslrootcert, ela falha com root certificate file ".../.postgresql/root.crt" does not exist, porque o libpq recorre ao local padrão da CA. Se você se conectar pelo endereço IP em vez do hostname, a conexão falha com server certificate for "..." does not match host name.
Se sua aplicação lê uma DATABASE_URL com o dj-database-url, ele repassa sslmode e sslrootcert da string de consulta da URL para OPTIONS. Chame dj_database_url.config(conn_max_age=600, conn_health_checks=True, disable_server_side_cursors=True) para obter as mesmas configurações. Um caminho relativo de sslrootcert na URL é resolvido em relação ao diretório em que você inicia o Django.

Crie um model e execute as migrations

Adicione o app todos a INSTALLED_APPS em mysite/settings.py:
mysite/settings.py
Defina um model Todo em todos/models.py:
todos/models.py
Crie uma migration para o model e aplique todas as migrations:
Além de todos_todo, o migrate cria as tabelas dos aplicativos nativos do Django, como auth_user e django_session, e registra as migrations aplicadas em django_migrations. Em um aplicativo existente, pule o model todos e execute apenas python manage.py migrate, que cria todas as tabelas do seu aplicativo no novo banco de dados. O migrate não adquire um advisory lock no nível da sessão, então funciona com o PgBouncer. Ele também não impede execuções simultâneas; por isso, execute as migrations de um único ponto, como uma etapa de implantação.

Adicione um endpoint JSON

Substitua todos/views.py por duas views que criam, listam, atualizam e excluem tarefas usando o ORM do Django:
todos/views.py
Substitua o conteúdo de mysite/urls.py para rotear /todos e /todos/<id> para as views:
mysite/urls.py

Executar e verificar

Inicie o servidor de desenvolvimento:
Em um segundo terminal, crie duas tarefas, marque a primeira como concluída e exclua a segunda:
A requisição PATCH retorna a linha atualizada:
Abra http://localhost:3111/todos no navegador para listar as tarefas pendentes. A resposta será semelhante a esta:
Para ver os dados no console, abra o SQL Console na barra lateral esquerda do seu serviço, expanda guide_django e, em seguida, public e clique na tabela todos_todo. A tabela contém a linha restante:

Configurações do PgBouncer para Django

O PgBouncer opera no modo de pooling de transações: cada transação, ou cada instrução fora de uma transação, pode ser executada em uma conexão Postgres diferente. Veja como isso afeta as configurações acima e outros recursos do Django:
  • DISABLE_SERVER_SIDE_CURSORS: QuerySet.iterator lê linhas em fragmentos por meio de um cursor do lado do servidor. Fora de uma transação, o Django declara o cursor WITH HOLD e busca cada fragmento separadamente; assim, via PgBouncer, uma busca pode cair em uma conexão Postgres que não tem o cursor e falhar com cursor "_django_curs_..." does not exist. Isso só acontece quando outros clientes usam o pool ao mesmo tempo, por isso muitas vezes não aparece em desenvolvimento. Com a configuração ativada, .iterator() usa um cursor comum, e o psycopg carrega todo o resultado na memória. Para fazer streaming de uma tabela muito grande, execute esse código pela conexão direta na porta 5432, com a configuração desativada.
  • CONN_MAX_AGE: por padrão (0), o Django abre uma nova conexão para cada requisição. Abrir uma conexão TLS exige várias idas e voltas na rede, tanto via PgBouncer quanto diretamente, então reutilizar conexões deixa as requisições muito mais rápidas. Em um teste feito a partir de um laptop com quatro workers do Gunicorn, definir CONN_MAX_AGE como 600 reduziu o tempo mediano de requisição de cerca de 670 ms para 95 ms. Via PgBouncer, uma conexão Django aberta não ocupa uma conexão Postgres entre transações, portanto conexões persistentes não esgotam max_connections. CONN_HEALTH_CHECKS faz o Django verificar uma conexão reutilizada no início de cada requisição e reconectar caso ela tenha sido fechada.
  • Pool de conexões: o pool integrado do Django ("pool": True em OPTIONS, que requer pip install "psycopg[binary,pool]") oferece um ganho de desempenho semelhante e também funciona via PgBouncer. Ele exige CONN_MAX_AGE definido como 0 e mantém pelo menos quatro conexões abertas por processo. Com o PgBouncer, CONN_MAX_AGE basta para a maioria das aplicações; considere o pool para servidores com threads ou ASGI.
  • Prepared statements: nenhuma configuração é necessária. Por padrão, o Django define o prepare_threshold do psycopg como None e vincula os parâmetros de consulta no cliente, portanto não cria prepared statements do lado do servidor. Se você ativar "server_side_binding": True e definir "prepare_threshold" em OPTIONS, os prepared statements também funcionam via PgBouncer, porque o psycopg[binary] inclui a libpq 18 e libera as instruções com uma mensagem Close no nível do protocolo. Com o psycopg compilado com a libpq 16 ou anterior, liberar uma instrução dentro de uma transação falha com prepared statement "_pg3_0" does not exist. Para verificar sua versão, execute python -c "import psycopg; print(psycopg.pq.version())". É necessário 170000 ou superior.
  • Estado de sessão: uma instrução SET, como SET search_path, só se aplica à conexão Postgres que a executou; assim, consultas posteriores podem não enxergá-la, enquanto outros clientes podem. O PgBouncer rejeita a configuração "options": "-c search_path=..." do Django com unsupported startup parameter in options: search_path. Em vez disso, defina os valores padrão no banco de dados, por exemplo com ALTER DATABASE guide_django SET search_path = myschema, public;. Não use a opção assume_role, que executa SET ROLE. O tratamento de TIME_ZONE do próprio Django e a opção isolation_level funcionam via PgBouncer.
Para se conectar diretamente, defina PORT como 5432 e remova DISABLE_SERVER_SIDE_CURSORS. Nesse caso, cada worker do Django mantém sua própria conexão Postgres, portanto mantenha o número total de workers abaixo de max_connections.

Próximos passos