Django Back-End für SQL Server - mssql-django

mssql-django ist Microsofts Django-Datenbankbackend für SQL Server, Azure SQL-Datenbank, Azure SQL Managed Instance und SQL-Datenbank in Microsoft Fabric. Setzen Sie ENGINE in Ihrer Django-DATABASES-Konfiguration auf "mssql", um eine Verbindung herzustellen. Das Back-End basiert auf Pyodbc und dem Microsoft ODBC-Treiber für SQL Server und unterstützt Django 3.2 bis 6.0, Python 3.8 bis 3.14 und SQL Server 2016 bis 2025.

Auswählen des Startpunkts

Produktionsbasisplan für Azure SQL

Verwenden Sie diesen Codeausschnitt als Ausgangspunkt für eine produktionsorientierte Azure SQL Konfiguration. Es fasst vier Dateien zusammen: settings.py (die Django-Datenbankkonfiguration, die Registrierung der Middleware und die Protokollierung), myproject/retry.py (den Katalog vorübergehender Fehler und den Decorator retry_on_transient), myproject/middleware.py (die Middleware für Wiederholungsversuche auf Anfrageebene) und myapp/views.py (eine beispielhafte transaktionale Ansicht).

# 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,
        },
    },
})

Definieren Sie den gemeinsamen Katalog für vorübergehende Fehler und den retry_on_transient Decorator in 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

Definieren Sie die Middleware auf Anforderungsebene in myproject/middleware.py. is_transient wird wiederverwendet, sodass beide Ebenen dieselbe Menge an Fehlercodes erkennen:

# 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

Da ATOMIC_REQUESTSFalse ist, müssen Ansichten, die Änderungen vornehmen, ihre eigene Transaktion öffnen. Umschließen Sie den atomic()-Block mit @retry_on_transient, sodass jeder Wiederholungsversuch in einer neuen Transaktion ausgeführt wird:

# 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

Dieser Basisplan registriert wiederholungsversuche auf zwei Ebenen. Die Middleware fungiert als Backstop für den Datenbankzugriff außerhalb der eingerichteten Ansichten, z. B. des Administrators, der Signale oder anderer Middleware. Der @retry_on_transient Dekorator gibt Autoren von Ansichten eine genauere Kontrolle darüber, für welche Vorgänge Wiederholungsversuche erfolgen. Wenn ein vorübergehender Fehler dem Decorator entgeht, wiederholt die Middleware die gesamte Anfrage, sodass im schlimmsten Fall bis zu neun Versuche unternommen werden, bevor dem Client ein Fehler angezeigt wird. Wenn diese Obergrenze für Ihr Latenzbudget zu hoch ist, lassen Sie eine Ebene weg oder verringern Sie max_retries in der Ebene, die Sie beibehalten.

Weitere Informationen zu jedem Teil dieser Konfiguration finden Sie unter Konfigurationsreferenz, Verbindungsoptionen, Verbindungspooling, Wiederholungslogik und Verbindungsresilienz sowie Microsoft Entra Authentifizierung.

Wichtigste Funktionen

  • Direkt einsetzbares Django-Backend: Setzen Sie ENGINE auf "mssql", und Djangos ORM, Migrationen, Admin-Oberfläche und Verwaltungsbefehle arbeiten mit SQL Server.
  • Basiert auf Pyodbc und ODBC Driver 18: TLS-verschlüsselte Verbindungen standardmäßig und umfassende Plattformunterstützung für Windows, Linux und macOS.
  • Breite Versionsmatrix: Django 3.2 bis 6.0, Python 3.8 bis 3.14 und SQL Server 2016 bis 2025.
  • Authentifizierung mit Microsoft Entra ID: Kennwortlose Verbindungen mit verwalteter Identität, Dienstprinzipal sowie interaktiven und integrierten Abläufen über extra_params.
  • Django-Migrationen: Schemamigrationen für SQL Server, einschließlich SQL Server-spezifischen Spaltentypen.
  • JSONField-Unterstützung: Native JSONField unterstützt durch den nvarchar(max) -Speicher und Django-Lookups.
  • Immer verschlüsselt: Clientseitige Verschlüsselung für vertrauliche Spalten.
  • Massenvorgänge: bulk_create und bulk_update gegen SQL Server mit sinnvollen Batchgrößen.
  • Vorübergehender Wiederholungsvorgang: Integrierte Behandlung für häufige Azure SQL vorübergehende Fehler während der Verbindungs- und Abfrageausführung.
  • inspectdb: Generieren Sie Django-Modelle aus vorhandenen SQL Server Schemas.

Get started

Artikel Description
Installation Installieren mssql-django und den Microsoft ODBC-Treiber für SQL Server.
Schnellstart: Verbinden von Django mit SQL Server Verbinden Sie ein Django-Projekt mit SQL Server, und führen Sie Ihre erste Migration aus.

Konfigurieren und Verbinden

Artikel Description
Konfigurationsreferenz Vollständige Referenz für das Django-Wörterbuch DATABASES mit mssql-django.
Verbindungsoptionen OPTIONS, extra_params, Timeouts und ODBC-Treiberkonfiguration.
Verbindungspooling CONN_MAX_AGE, CONN_HEALTH_CHECKS und Integration externer Pools.
Wiederholungslogik und Verbindungsresilienz Erkennen sie vorübergehende Fehler, und wiederholen Sie Verbindungen und Abfragen.
Microsoft Entra-Authentifizierung Kennwortlose Authentifizierung mit verwalteter Identität, Dienstprinzipal, interaktiven und integrierten Flüssen.
Bewährte Methoden für Sicherheit Parametrisierung, geheime Verwaltung, geringste Berechtigungen und Verschlüsselung.
Immer verschlüsselt Konfigurieren sie die clientseitige Verschlüsselung für vertrauliche Spalten.

Modelle, Migrationen und Datentypen

Artikel Description
Datenbankmigrationen Führen Sie Django-Migrationen für SQL Server aus, einschließlich SQL Server spezifischer Spaltentypen.
Zuordnungen von Django-Feldern zu SQL-Server-Datentypen Wie Django-Modellfelder SQL Server Datentypen zugeordnet werden.
JSONField-Unterstützung Verwenden Sie JSONField mit SQL Server und Django-Lookups.
Reverse Engineering-Modelle mit inspectdb Generieren Sie Django-Modelle aus vorhandenen SQL Server Schemas.
Unterstützung für Zeitzonen USE_TZ, datetimeoffset und Datums- und Uhrzeitwerte mit Zeitzonenbezug.

Abfragen und Arbeiten mit Daten

Artikel Description
Massenaktionen bulk_create, bulk_update und Optimierung der Batchgröße.
Transaktionsverwaltung atomic, Isolationsstufen, Speicherpunkte und Deadlock-Behandlung.
Rohe SQL-Abfragen RawSQL, connection.cursor()und SQL Server-spezifische Syntax.
Gespeicherten Prozeduren Rufen Sie SQL Server gespeicherte Prozeduren aus Django auf.

Bereitstellen, Testen und Optimieren

Artikel Description
Bereitstellen in Azure App Service Eine Django-Website mit mssql-django in Azure App Service bereitstellen.
Container und lokale Entwicklung Docker-Container, Devcontainer und CI-Pipelines für Django + SQL Server.
Testen Führen Sie Django-Testsuiten mit SQL Server aus.
Leistungsoptimierung Indizes, Abfragemuster, Verbindungswiederverwendung und Batchgrößen.
Problembehandlung Häufige Fehler, ODBC-Diagnose und Protokollierung.

Migrieren zu mssql-django

Artikel Description
Migration von django-mssql-backend Wechseln sie vom Communitypaket django-mssql-backend zu mssql-django.
Migrieren von anderen Datenbanken Verschieben Sie ein Django-Projekt aus einem anderen Datenbank-Back-End in SQL Server.
Migrieren von PostgreSQL One-Stop Guide für Django-Entwickler, die von PostgreSQL zu SQL Server wechseln.
Artikel Description
Supportlebenszyklus Unterstützte Django-, Python- und SQL Server-Versionen.
Neuerungen Versionsverlauf und Versionshighlights.
Einschränkungen und nicht unterstützte Features in mssql-django Back-End-Einschränkungen und nicht unterstützte Features.
Häufig gestellte Fragen Häufig gestellte Fragen.