Back-end do Django para SQL Server - mssql-django

mssql-djangoé o backend da base de dados Django da Microsoft para SQL Server, Base de Dados SQL do Azure, Azure SQL Managed Instance e base de dados SQL no Microsoft Fabric. Defina ENGINE para "mssql" na sua configuração do Django DATABASES para ligar. O backend baseia-se no pyodbc e no Microsoft ODBC Driver for SQL Server, e suporta Django 3.2 a 6.0, Python 3.8 a 3.14, e SQL Server 2016 a 2025.

Escolhe o teu ponto de partida

Linha de base de produção para o SQL do Azure

Use este excerto como ponto de partida para uma configuração SQL do Azure orientada para produção. Combina quatro ficheiros: settings.py (a configuração da base de dados do Django, o registo de middleware e o registo), myproject/retry.py (o catálogo de erros transitórios e o decorador retry_on_transient), myproject/middleware.py (o middleware de retentativa ao nível do pedido) e myapp/views.py (uma vista transacional de exemplo).

# settings.py

import logging.config
import os

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": os.environ["SQL_DATABASE"],          # for example, appdb
        "HOST": os.environ["SQL_SERVER"],            # for example, contoso.database.windows.net
        "PORT": "1433",
        "CONN_MAX_AGE": 300,                         # reuse pooled connections for 5 minutes
        "CONN_HEALTH_CHECKS": True,                  # validate connections before reuse (Django 4.1 and later)
        "ATOMIC_REQUESTS": False,                    # wrap mutating views in transactions explicitly (see the following view example)
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": (
                "Authentication=ActiveDirectoryMsi;"
                "Encrypt=yes;"
                "TrustServerCertificate=no;"
                # ODBC driver reconnects connections dropped while idle.
                "ConnectRetryCount=3;"
                "ConnectRetryInterval=10;"
            ),
            # Backend-level retry for the initial connect call. Complements
            # ConnectRetryCount, which only covers idle drops on an
            # already-established connection.
            # See Retry logic and connection resilience for the recognized error list.
            "connection_retries": 3,
            "connection_retry_backoff_time": 5,
        },
    },
}

MIDDLEWARE = [
    # Defined in myproject/middleware.py. Catches transient OperationalErrors
    # and retries the request. Add "1205" (deadlock victim) and "1222"
    # (lock-request timeout) to TRANSIENT_ERROR_CODES to also retry
    # statement-level failures.
    "myproject.middleware.DatabaseRetryMiddleware",
    "django.middleware.security.SecurityMiddleware",
    # ... your other middleware
]

LOGGING_CONFIG = None
logging.config.dictConfig({
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "json": {
            "format": (
                '{"time":"%(asctime)s","level":"%(levelname)s",'
                '"logger":"%(name)s","message":"%(message)s"}'
            ),
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "json",
        },
    },
    "loggers": {
        "django.db.backends": {
            "handlers": ["console"],
            "level": "WARNING",      # raise to INFO or DEBUG to capture SQL
            "propagate": False,
        },
        "django.request": {
            "handlers": ["console"],
            "level": "WARNING",
            "propagate": False,
        },
        "mssql": {
            "handlers": ["console"],
            "level": "INFO",
            "propagate": False,
        },
    },
})

Defina o catálogo partilhado de erros transitórios e o decorador retry_on_transient em myproject/retry.py:

# myproject/retry.py
import functools
import logging
import random
import re
import time

from django.db import OperationalError, connection

logger = logging.getLogger(__name__)

TRANSIENT_ERROR_CODES = {
    "64", "233", "4221",
    "10053", "10054", "10928", "10929",
    "40197", "40501", "40613",
    "49918", "49919", "49920",
    # Add "4060" only if targeting Azure SQL with geo-replication failover.
    # Add "1205" (deadlock victim) and "1222" (lock-request timeout) to
    # also retry statement-level failures.
}

# Microsoft ODBC driver formats native error codes as "(<number>)" in the
# message. Parenthesized matches avoid false positives for short codes like "64".
_CODE_RE = re.compile(r"\((\d+)\)")


def is_transient(error):
    codes_in_message = set(_CODE_RE.findall(str(error)))
    return bool(codes_in_message & TRANSIENT_ERROR_CODES)


def retry_on_transient(max_retries=3, base_delay=1, max_delay=30):
    """Retry on transient database errors with exponential backoff and full jitter."""

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except OperationalError as e:
                    if attempt < max_retries and is_transient(e):
                        capped = min(max_delay, base_delay * (2 ** attempt))
                        delay = random.uniform(0, capped)
                        logger.warning(
                            "Transient error in %s (attempt %d/%d), retrying in %.2fs: %s",
                            func.__name__, attempt + 1, max_retries, delay, e
                        )
                        connection.close()
                        time.sleep(delay)
                        continue
                    raise
        return wrapper
    return decorator

Defina o middleware ao nível do pedido em myproject/middleware.py. Reutiliza is_transient para que ambas as camadas reconheçam o mesmo conjunto de códigos de erro:

# myproject/middleware.py
import logging
import random
import time

from django.db import OperationalError, connection

from myproject.retry import is_transient

logger = logging.getLogger(__name__)


class DatabaseRetryMiddleware:
    """Retry the entire request on transient database errors."""

    def __init__(self, get_response):
        self.get_response = get_response
        self.max_retries = 3
        self.base_delay = 1   # seconds; doubled each attempt
        self.max_delay = 30   # cap on a single sleep, regardless of attempt

    def __call__(self, request):
        for attempt in range(self.max_retries + 1):
            try:
                return self.get_response(request)
            except OperationalError as e:
                if attempt < self.max_retries and is_transient(e):
                    capped = min(self.max_delay, self.base_delay * (2 ** attempt))
                    delay = random.uniform(0, capped)
                    logger.warning(
                        "Transient DB error (attempt %d/%d), retrying in %.2fs: %s",
                        attempt + 1, self.max_retries, delay, e
                    )
                    connection.close()
                    time.sleep(delay)
                    continue
                raise

Como ATOMIC_REQUESTS é False, as views que alteram dados têm de iniciar a sua própria transação. Envolva o bloco atomic() com @retry_on_transient para que cada nova tentativa execute uma nova transação:

# myapp/views.py
from django.db import transaction
from django.http import JsonResponse

from myproject.retry import retry_on_transient
from .models import Order


# Exponential backoff with full jitter: sleeps random within [0,2], [0,4], [0,8] seconds.
@retry_on_transient(max_retries=3, base_delay=2)
def submit_order(request, order_id):
    with transaction.atomic():
        order = Order.objects.select_for_update().get(id=order_id)
        order.status = "submitted"
        order.save()
    return JsonResponse({"id": order.id, "status": order.status})

Note

Esta configuração base implementa tentativas de repetição a dois níveis. O middleware atua como um backstop para o acesso à base de dados fora das vistas decoradas, como o admin, signals ou outro middleware. O decorador @retry_on_transient dá aos autores de vistas um controlo mais preciso sobre quais as operações que são repetidas. Se um erro transitório escapar ao decorador, o middleware tenta novamente o pedido completo, pelo que, no pior caso, pode haver até nove tentativas antes de o cliente receber um erro. Se esse teto for demasiado alto para o teu orçamento de latência, coloca uma camada ou menos max_retries na camada que mantiveres.

Para mais informações sobre cada parte desta configuração, consulte Referência de configuração, Opções de ligação, Agrupamento de ligações, Lógica de repetição e resiliência da ligação e Autenticação do Microsoft Entra.

Principais características

  • Backend drop-in para Django: Defina ENGINE como "mssql" e o ORM, as migrações, a administração e os comandos de gestão do Django funcionam com o SQL Server.
  • Baseado em pyodbc e ODBC Driver 18: ligações encriptadas com TLS por predefinição e amplo suporte para Windows, Linux e macOS.
  • Matriz de versões amplas: Django 3.2 a 6.0, Python 3.8 a 3.14, e SQL Server 2016 a 2025.
  • Autenticação do Microsoft Entra ID: Ligações sem palavra-passe com identidade gerida, service principal e fluxos interativos e integrados através de extra_params.
  • Migrações do Django: Migrações de esquema para o SQL Server, incluindo tipos de colunas específicos do SQL Server.
  • Suporte JSONField: Nativo JSONField apoiado pelo armazenamento nvarchar(max ) e pelas consultas no Django.
  • Always Encrypted: Encriptação do lado do cliente para colunas sensíveis.
  • Operações em massa: bulk_create e bulk_update contra SQL Server com tamanhos de lote sensatos.
  • Retentativa transitória: Tratamento incorporado para erros transitórios comuns do SQL do Azure durante a execução da ligação e da consulta.
  • inspectdb: Gerar modelos Django a partir de esquemas SQL Server existentes.

Introdução

Artigo Description
Installation Instalar mssql-django e o driver Microsoft ODBC para SQL Server.
Início Rápido: Ligue o Django ao SQL Server Ligue um projeto Django ao SQL Server e execute a sua primeira migração.

Configurar e ligar

Artigo Description
Referência de configuração Referência completa para o dicionário Django DATABASES com mssql-django.
Opções de ligação OPTIONS, extra_params, tempos limite e a configuração do controlador ODBC.
Pool de conexões CONN_MAX_AGE, CONN_HEALTH_CHECKS e integração com pools externos.
Lógica de repetição e resiliência da conexão Detetar erros transitórios e tentar novamente ligações e consultas.
Autenticação do Microsoft Entra Autenticação sem palavra-passe com identidade gerida, principal de serviço, fluxos interativos e integrados.
Práticas recomendadas de segurança Parametrização, gestão de segredos, privilégios mínimos e encriptação.
Sempre criptografado Configure a encriptação do lado do cliente para colunas sensíveis.

Modelos, migrações e tipos de dados

Artigo Description
Migrações de bases de dados Execute migrações do Django contra o SQL Server, incluindo tipos de colunas específicas do SQL Server.
Campo Django para mapeamentos do tipo SQL Server Como os campos do modelo Django correspondem aos tipos de dados do SQL Server.
Suporte ao JSONField Utilize JSONField com pesquisas do SQL Server e do Django.
Fazer engenharia inversa de modelos com inspectdb Gerar modelos Django a partir de esquemas SQL Server existentes.
Suporte para fusos horários USE_TZ, datetimeoffset e datas e horas com reconhecimento de fuso horário.

Consulta e trabalho com dados

Artigo Description
Operações em massa bulk_create, bulk_update, e a afinação do tamanho do lote.
Gestão de transações atomic, níveis de isolamento, pontos de salvaguarda e tratamento de interbloqueios.
Consultas SQL brutas RawSQL, connection.cursor(), e sintaxe específica do SQL Server.
Procedimentos armazenados Chame procedimentos armazenados do SQL Server no Django.

Implantar, testar e ajustar

Artigo Description
Implementar no Serviço de Aplicações do Azure Implementar um site Django no Serviço de Aplicações do Azure com o mssql-django.
Contentores e desenvolvimento local Contentores Docker, devcontainers e pipelines de CI para Django + SQL Server.
Testing Executa conjuntos de testes Django contra SQL Server.
Afinação de desempenho Índices, padrões de consulta, reutilização de ligações e tamanhos de lote.
Troubleshooting Erros comuns, diagnósticos ODBC e registo.

Migrar para mssql-django

Artigo Description
Migrar de django-mssql-backend Mude do pacote comunitário django-mssql-backend para mssql-django.
Migrar a partir de outras bases de dados Mover um projeto Django de outro backend de base de dados para o SQL Server.
Migrar a partir do PostgreSQL Guia completo para programadores de Django na migração do PostgreSQL para o SQL Server.
Artigo Description
Ciclo de vida do suporte Suportava versões para Django, Python e SQL Server.
Novidades Histórico de versões e destaques de lançamentos.
Limitações e funcionalidades não suportadas no mssql-django Limitações do backend e funcionalidades não suportadas.
Perguntas Frequentes Perguntas frequentes.