Natalia Bidart anunciou em 3 de dezembro de 2025 o lançamento oficial do Django 6.0. A nova versão marca uma grande atualização do framework, misturando ferramentas modernas, foco em segurança e ajustes importantes de compatibilidade.
O pacote já está disponível na página de downloads do Django e no Python Package Index (PyPI). O lançamento foi assinado com a chave PGP de Natalia Bidart: 2EE82A8D9470983E.
Com essa versão, o Django 5.2 encerra o suporte principal. A última correção de bugs menores, a versão 5.2.9, saiu ontem. A linha 5.2 ainda receberá correções de segurança e de perda de dados até abril de 2028, e os usuários são orientados a atualizar antes disso para manter as correções de segurança em dia.
Já o Django 5.1 chegou ao fim do suporte estendido. A última atualização de segurança, 5.1.15, foi lançada em 2 de dezembro de 2025. Quem ainda está na série 5.1 é incentivado a migrar para uma versão suportada.
Os detalhes sobre versões ativas e calendário de lançamentos futuros continuam disponíveis na página de downloads do Django.
Compatibilidade com Python: adeus versões antigas 🐍
O Django 6.0 funciona com Python 3.12, 3.13 e 3.14, com suporte oficial apenas para o lançamento mais recente de cada série.
A linha Django 5.2.x foi a última a funcionar com Python 3.10 e 3.11. Isso também afeta dependências opcionais: todas agora precisam ser compatíveis com Python 3.12 ou superior, com versões mínimas recomendadas como:
- aiosmtpd 1.4.5
- argon2-cffi 23.1.0
- bcrypt 4.1.1
- docutils 0.22
- geoip2 4.8.0
- Pillow 10.1.0
- mysqlclient 2.2.1
- numpy 1.26.0
- PyYAML 6.0.2
- psycopg 3.1.12
- psycopg2 2.9.9
- redis-py 5.1.0
- selenium 4.23.0
- sqlparse 0.5.0
- tblib 3.0.0
Depois do lançamento do Django 6.0, a recomendação para autores de apps de terceiros é abandonar o suporte a versões anteriores à 5.2 e rodar os testes com python -Wd, corrigindo todos os avisos de descontinuação antes de dar suporte formal ao 6.0.
Segurança: CSP nativo na caixa 🔐
Uma das grandes novidades é o suporte nativo a Content Security Policy (CSP), para reforçar a proteção contra injeção de conteúdo, como ataques de XSS.
Agora é possível declarar, diretamente no framework, quais origens de scripts, estilos, imagens e outros recursos são confiáveis. A integração vem com:
- ContentSecurityPolicyMiddleware para adicionar os cabeçalhos de CSP;
- o context processor csp() para gerar nonces;
- configuração via SECURE_CSP e SECURE_CSP_REPORT_ONLY, recebendo dicionários Python.
As configurações podem usar constantes do módulo django.utils.csp.CSP, por exemplo:
from django.utils.csp import CSP
SECURE_CSP = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
"img-src": [CSP.SELF, "https:"],
}
Isso gera um cabeçalho Content-Security-Policy como:
default-src 'self'; script-src 'self' 'nonce-SECRET'; img-src 'self' https:
O framework ainda oferece documentação específica: guia de “como fazer” com CSP, visão geral de segurança e referência com detalhes, inclusive sobre decoradores para sobrescrever ou desativar políticas em views individuais.
Template Partials: fragmentos reutilizáveis em templates 🧩
A linguagem de templates do Django ganhou suporte a template partials, permitindo criar pequenos blocos nomeados dentro de um mesmo arquivo para reaproveitar código sem precisar quebrar tudo em vários templates.
Dois novos tags entram em cena:
- {% partialdef %} para definir o partial;
- {% partial %} para renderizar o partial.
Além disso, partials podem ser referenciados com a sintaxe template_name#partial_name em get_template(), render(), {% include %} e outras APIs de carregamento de templates.
Quem já usava o pacote de terceiros django-template-partials conta com um guia de migração específico para se adaptar ao recurso agora integrado ao core.
Tarefas em segundo plano: novo framework de Tasks ⚙️
Outra mudança pesada é a introdução de um framework nativo de Background Tasks, pensado para rodar código fora do ciclo tradicional requisição–resposta HTTP.
Com ele, dá para descarregar trabalhos como envio de e-mails ou processamento de dados para workers em segundo plano. O sistema cuida de:
- definição e validação de tarefas;
- enfileiramento;
- tratamento de resultados.
A definição de tarefas é feita com o decorador @task, por exemplo:
from django.core.mail import send_mail
from django.tasks import task@task
def email_users(emails, subject, message):
return send_mail(subject, message, None, emails)
Depois disso, a tarefa pode ser enfileirada por um backend configurado:
email_users.enqueue(
emails=["user@example.com"],
subject="You have a message",
message="Hello there!",
)
Os backends são definidos via configuração TASKS. Duas opções já vêm incluídas, voltadas principalmente para desenvolvimento e testes.
Importante: o Django gerencia criação e enfileiramento das tarefas, mas não fornece o mecanismo de execução. A responsabilidade de rodar os jobs continua sendo de processos ou serviços externos.
A documentação traz uma visão geral do framework de Tasks e uma referência com os detalhes da API.
E-mail: adoção total da API moderna do Python 📧
O sistema de e-mail do Django foi atualizado para usar a API moderna introduzida no Python 3.6, baseada na classe email.message.EmailMessage.
Essa nova base:
- oferece uma interface mais limpa e amigável a Unicode;
- substitui o uso da API antiga (Compat32) e das classes de baixo nível de email.mime;
- simplifica a composição e o envio de mensagens.
Uma mudança concreta é o retorno de EmailMessage.message(), que agora passa a ser uma instância de email.message.EmailMessage. Ela mantém a mesma API esperada por quem usava SafeMIMEText e SafeMIMEMultipart, mas já não é mais instância dessas classes, que foram marcadas como obsoletas.
Outros ajustes incluem:
- novo argumento policy em EmailMessage.message(), permitindo escolher a política de e-mail (regra de atualização e serialização da mensagem), com padrão email.policy.default;
- EmailMessage.attach() agora aceita objetos MIMEPart da API moderna;
- vários detalhes internos foram reescritos, então subclasses personalizadas que mexem em métodos internos não documentados precisam ser revisadas.
Algumas propriedades não documentadas foram descartadas:
- mixed_subtype e alternative_subtype em EmailMessage e EmailMultiAlternatives;
- uso da propriedade encoding com objetos email.charset.Charset legados.
E, olhando para o futuro, vários comportamentos antigos já foram declarados como obsoletos. Por exemplo:
- APIs em django.core.mail passam a exigir uso de keyword arguments para parâmetros opcionais em get_connection(), mail_admins(), mail_managers(), send_mail() e send_mass_mail();
- ao criar EmailMessage ou EmailMultiAlternatives, apenas os quatro primeiros argumentos (subject, body, from_email, to) continuam aceitando forma posicional; o resto deve ser nomeado;
- passar objetos MIMEBase da API legada para EmailMessage.attach() foi marcado como descontinuado;
- a exceção django.core.mail.BadHeaderError foi deprecada em favor de ValueError, levantado pela API moderna;
- as classes SafeMIMEText e SafeMIMEMultipart entram na lista de APIs obsoletas, assim como as funções não documentadas forbid_multi_line_headers() e message.sanitize_address().
Admin, autenticação, GIS, Postgres, staticfiles e mais: os extras do 6.0
django.contrib.admin
- As ícones do admin agora usam o pacote Font Awesome Free na versão 6.7.2.
- Um novo atributo AdminSite.password_change_form permite customizar o formulário de troca de senha no admin.
- Níveis de mensagem messages.DEBUG e messages.INFO ganharam ícones e estilos CSS distintos. Antes, ambos pareciam com messages.SUCCESS. Como ModelAdmin.message_user() usa messages.INFO por padrão, quem quiser manter o visual antigo deve trocar o nível para messages.SUCCESS.
django.contrib.auth
- O número padrão de iterações do hasher de senha PBKDF2 sobe de 1.000.000 para 1.200.000, fortalecendo o hashing.
django.contrib.gis
- Nova propriedade GEOSGeometry.hasm para checar se a geometria possui dimensão M.
- Função de banco Rotate, para rotacionar geometrias por um ângulo, em torno da origem ou de um ponto específico.
- Atributo BaseGeometryWidget.base_layer para definir a camada base do mapa via JavaScript, permitindo personalizar provedores de tiles.
- Novos recursos suportados no MariaDB 12.0.1+: lookups coveredby e isvalid, agregação Collect e funções GeoHash e IsValid.
- Lookup geom_type e função de banco GeometryType() para filtrar geometrias por tipo.
- Widgets em django.contrib.gis.forms.widgets passam a renderizar sem JavaScript inline; customizações de widgets ou templates podem precisar de ajuste para acompanhar o novo layout.
django.contrib.postgres
- Novo tipo de expressão Lexeme para full text search, com:
- escape automático do input;
- operadores lógicos &, |, ~;
- suporte a prefixo;
- peso de termos.
- Campos de modelo, índices e constraints do pacote passam a incluir system checks para garantir que django.contrib.postgres está instalado em INSTALLED_APPS.
- As operações CreateExtension, BloomExtension, BtreeGinExtension, BtreeGistExtension, CITextExtension, CryptoExtension, HStoreExtension, TrigramExtension e UnaccentExtension passam a aceitar um parâmetro opcional hints, para ajudar roteadores de banco a tomar decisões.
django.contrib.staticfiles
- ManifestStaticFilesStorage agora garante uma ordenação consistente dos caminhos no arquivo de manifesto, o que reduz diffs desnecessários.
- O comando collectstatic passa a mostrar apenas um resumo de arquivos ignorados (e dos deletados com --clear) quando --verbosity 1. Para ver detalhes por arquivo, é preciso aumentar o nível para 2 ou mais.
Internacionalização
- O framework ganhou suporte e traduções para o idioma crioulo haitiano.
Management commands
- Os comandos startproject e startapp agora criam o diretório alvo customizado, se ele ainda não existir.
- Utilitários comuns, como django.conf.settings, passam a ser importados automaticamente no shell por padrão.
Migrations
- Migrations “espremidas” (squashed) podem ser novamente “espremidas” antes de virarem migrations normais.
- Migrations passam a serializar instâncias de zoneinfo.ZoneInfo.
- A serialização de objetos deconstructible agora suporta argumentos nomeados cujos nomes não são identificadores Python válidos.
Models e ORM
- Constraints agora implementam um método check() já registrado no framework de checks.
- O novo argumento order_by em Aggregate permite definir a ordenação dos elementos no resultado.
- Um novo atributo de classe Aggregate.allow_order_by controla se a função de agregação aceita o argumento order_by.
- A nova agregação StringAgg concatena valores em uma string, separados por um delimitador. Antes, ela existia apenas para PostgreSQL; agora é geral.
- O método save() passa a lançar uma exceção especializada Model.NotUpdated quando um forced update não afeta nenhuma linha, em vez de um django.db.DatabaseError genérico.
- QuerySet.raw() agora aceita modelos com CompositePrimaryKey.
- Subqueries que retornam CompositePrimaryKey podem ser usadas em lookups além de __in, como __exact.
- JSONField agora suporta indexação negativa de arrays no SQLite.
- A nova agregação AnyValue retorna um valor arbitrário entre os não nulos, com suporte em SQLite, MySQL, Oracle e PostgreSQL 16+.
- GeneratedFields e campos com expressões passam a ser atualizados a partir do banco após save() em backends com suporte a RETURNING (SQLite, PostgreSQL, Oracle). Em MySQL e MariaDB, os campos são marcados como deferred para forçar um refresh no acesso posterior.
- O uso de ForeignObject com múltiplos from_fields em índices, constraints ou unique_together agora emite um system check de erro.
Paginação assíncrona
- Entram em cena o AsyncPaginator e o AsyncPage, versões assíncronas de Paginator e Page.
Requests e responses
- Ao rodar com ASGI, o framework agora suporta múltiplos cabeçalhos Cookie em requisições HTTP/2.
Templates
- A variável forloop.length fica disponível dentro do laço for nos templates.
- A tag querystring passa a sempre prefixar o retorno com ?, facilitando a geração consistente de links.
- A mesma tag agora aceita múltiplos argumentos posicionais, contanto que sejam mapeamentos, como QueryDict ou dict.
Tests
- O DiscoverRunner passa a suportar testes paralelos em sistemas que usam o método de inicialização de multiprocessing forkserver.
Banco de dados: mudanças que podem quebrar backends de terceiros
Algumas alterações no backend de banco exigem atenção de quem mantém integrações personalizadas.
- BaseDatabaseSchemaEditor e os backends PostgreSQL deixam de usar CASCADE ao remover colunas.
- Os métodos DatabaseOperations.return_insert_columns() e DatabaseOperations.fetch_returned_insert_rows() foram renomeados para returning_columns() e fetch_returned_rows(), já que agora valem também para UPDATE ... RETURNING, não só para INSERT ... RETURNING.
- O método DatabaseOperations.fetch_returned_insert_columns() foi removido. Já fetch_returned_rows(), que substitui fetch_returned_insert_rows(), passa a exigir cursor e returning_params, como fazia o método removido.
- Backends que suportam UPDATE ... RETURNING podem ajustar DatabaseFeatures.can_return_rows_from_update = True.
Fim do suporte ao MariaDB 10.5
Com o término do suporte upstream em junho de 2025, o Django 6.0 passa a funcionar apenas com MariaDB 10.6+.
DEFAULT_AUTO_FIELD: BigAutoField vira o padrão
Desde o Django 3.2, o template padrão de startproject já incluía:
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
E o template de startapp vinha com:
default_auto_field = "django.db.models.BigAutoField"
Mas, por compatibilidade, o valor real padrão de DEFAULT_AUTO_FIELD ainda era django.db.models.AutoField. Agora, no Django 6.0, o default passa a ser oficialmente django.db.models.BigAutoField e essas linhas são removidas dos templates.
Desde o Django 3.2 o sistema já emitia o aviso models.W042 para projetos que não configuravam DEFAULT_AUTO_FIELD. Quem ainda ignora esse aviso e quer manter o comportamento antigo precisa declarar explicitamente:
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
ou, em nível de app:
default_auto_field = 'django.db.models.AutoField'
Expressões customizadas no ORM: params agora precisam ser tuplas
Expressões e lookups personalizados que implementam as_sql() (e métodos auxiliares como process_lhs() e process_rhs()) antes podiam retornar a sequência de parâmetros como lista ou tupla. Para evitar problemas de interoperabilidade, o segundo elemento retornado por as_sql() agora deve ser obrigatoriamente uma tupla:
def as_sql(self, compiler, connection) -> tuple[str, tuple]: ...
Quem mantém código compatível com múltiplas versões de Django deve se certificar de que qualquer pré-processamento de parâmetros aceite tanto listas quanto tuplas, por exemplo:
params = (*lhs_params, *rhs_params)
Outras mudanças gerais
- O serializador JSON agora escreve uma quebra de linha ao final da saída, mesmo sem indent.
- A função não documentada django.utils.http.parse_header_parameters() foi refeita para usar email.message.Message internamente. Cabeçalhos com mais de 10.000 caracteres passam a gerar ValueError.
- A versão mínima de asgiref sobe de 3.8.1 para 3.9.1.
Funcionalidades marcadas como obsoletas no 6.0
Alguns recursos entram oficialmente em fase de descontinuação, com avisos de deprecação e remoção planejada em versões futuras.
- django.core.mail:
- Uso de argumentos posicionais para parâmetros opcionais (a partir de fail_silently) em get_connection(), mail_admins(), mail_managers(), send_mail() e send_mass_mail() passa a emitir warnings e será proibido no futuro.
- Em EmailMessage e EmailMultiAlternatives, todos os parâmetros devem ser passados como keyword, exceto os quatro primeiros, que continuam aceitando forma posicional ou nomeada.
- Passar objetos MIMEBase legados para EmailMessage.attach() (ou na lista de attachments) entra na lista de usos obsoletos.
- A exceção BadHeaderError, as classes SafeMIMEText e SafeMIMEMultipart e as funções não documentadas forbid_multi_line_headers() e message.sanitize_address() são oficialmente marcadas como deprecated.
- Banco de dados e ORM:
- BaseDatabaseCreation.create_test_db(serialize) é descontinuado; o recomendado é usar serialize_db_to_string().
- A classe StringAgg específica de PostgreSQL entra em descontinuação em favor da StringAgg geral.
- OrderableAggMixin para PostgreSQL é substituído pelo novo atributo order_by em Aggregate.
- O uso de % em aliases de coluna ou anotações é considerado obsoleto.
- URL e texto:
- No Django 7.0, o protocolo padrão em urlize e urlizetrunc passará de http para https. Durante o ciclo 6.x, é possível antecipar esse comportamento com o setting transitório URLIZE_ASSUME_HTTPS = True, que por sua vez já está marcado como deprecado.
- ADMINS e MANAGERS:
- Configurar essas listas como tuplas (nome, endereço) entra em desuso. A recomendação é usar apenas strings de e-mail. Se o nome for necessário, o formato sugerido é "Name" <address> ou o uso de email.utils.formataddr().
- Paginator:
- Passar um valor para orphans maior ou igual a per_page em Paginator e AsyncPaginator passa a ser desaconselhado.
Funcionalidades removidas no 6.0
O Django 6.0 também limpa a casa, removendo recursos que já haviam cumprido o ciclo de deprecação em versões anteriores (5.0 e 5.1).
- ORM e banco de dados:
- Suporte a argumentos posicionais em BaseConstraint some.
- BaseDatabaseOperations.field_cast_sql() é removido.
- django.db.models.sql.datastructures.Join não recorre mais a get_joining_columns().
- Métodos ForeignObject.get_joining_columns(), ForeignObjectRel.get_joining_columns() e ForeignObject.get_reverse_joining_columns() são retirados.
- O método Prefetch.get_current_queryset() deixa de existir.
- Métodos get_prefetch_queryset() em managers relacionados e descritores são removidos.
- get_prefetcher() e prefetch_related_objects() não caem mais no fallback get_prefetch_queryset().
- O argumento check em CheckConstraint é eliminado.
- O atributo OS_OPEN_FLAGS de FileSystemStorage deixa de existir.
- Formulários e templates:
- Os renderizadores transitórios DjangoDivFormRenderer e Jinja2DivFormRenderer saem de cena.
- Chamar format_html() sem args ou kwargs não é mais permitido.
- O esquema padrão de forms.URLField muda de "http" para "https".
- O setting transitório FORMS_URLFIELD_ASSUME_HTTPS é removido.
- URL routing:
- django.urls.register_converter() deixa de aceitar sobrescrever conversores já existentes.
- Drivers e integrações:
- Suporte ao driver cx_Oracle é retirado.
- Modelos e API de alto nível:
- Passar argumentos posicionais para Model.save() e Model.asave() não é mais suportado.
- A alias ChoicesMeta para django.db.models.enums.ChoicesType é removida.
- O método ModelAdmin.log_deletion() e LogEntryManager.log_action() saem da API.
- O método get_cache_name() em FieldCacheMixin é eliminado.
- GeoDjango:
- O método django.contrib.gis.geoip2.GeoIP2.coords() é removido.
- O método django.contrib.gis.geoip2.GeoIP2.open() é removido.
- O setter de django.contrib.gis.gdal.OGRGeometry.coord_dim não existe mais.
- Utils:
- O módulo django.utils.itercompat e a função não documentada is_iterable() desaparecem.
- Mail e headers:
- O suporte ao uso de
foi removido (já citado em banco de dados, mas impacta formatações relacionadas).
- O suporte ao uso de
Um detalhe importante: recursos deprecatados no Django 5.0 e 5.1 que chegaram ao fim do ciclo agora estão oficialmente fora da base do 6.0. A recomendação é sempre conferir as seções “Features deprecated in 5.0” e “Features deprecated in 5.1” das notas de versão anteriores para ter o passo a passo completo de migração.
No geral, o Django 6.0 sinaliza um ciclo mais moderno: Python recente, segurança reforçada (com CSP), background tasks integradas, templates mais modulares e uma limpeza ampla na API, preparando o terreno para as próximas versões do framework. 🧱✨