Backend Django untuk SQL Server - mssql-django

mssql-django adalah backend basis data Django dari Microsoft untuk SQL Server, Azure SQL Database, Azure SQL Managed Instance, dan basis data SQL di Microsoft Fabric. Atur ENGINE ke "mssql" dalam konfigurasi Django DATABASES Anda untuk menyambungkan. Backend dibangun pada pyodbc dan Driver ODBC Microsoft untuk SQL Server, dan mendukung Django 3.2 hingga 6.0, Python 3.8 hingga 3.14, dan SQL Server 2016 hingga 2025.

Pilih titik awal Anda

Garis besar produksi untuk Azure SQL

Gunakan cuplikan ini sebagai titik awal untuk konfigurasi Azure SQL berorientasi produksi. Ini menggabungkan empat file: settings.py (konfigurasi database Django, pendaftaran middleware, dan pengelogan), myproject/retry.py (katalog kesalahan sementara dan retry_on_transient dekorator), myproject/middleware.py (middleware coba lagi tingkat permintaan), dan myapp/views.py (contoh tampilan transaksional).

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

Tentukan katalog kesalahan sementara bersama dan retry_on_transient dekorator di 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

Definisikan middleware pada level permintaan di myproject/middleware.py. Ini menggunakan kembali is_transient sehingga kedua lapisan mengenali kumpulan kode kesalahan yang sama:

# 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

Karena ATOMIC_REQUESTS adalah False, tampilan yang dapat diubah harus membuka transaksinya sendiri. Bungkus atomic() blok dengan @retry_on_transient sehingga setiap percobaan ulang menjalankan transaksi baru:

# 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

Baseline ini mencatat percobaan ulang di dua lapisan. Middleware bertindak sebagai backstop untuk akses database di luar tampilan yang didekorasi, seperti admin, sinyal, atau middleware lainnya. Dekorator @retry_on_transient memberi penulis view kontrol yang lebih terperinci terhadap operasi mana yang akan dicoba kembali. Jika kesalahan sementara tidak tertangani oleh dekorator, middleware akan mencoba ulang seluruh permintaan, sehingga dalam skenario terburuk ada hingga sembilan kali percobaan sebelum klien menerima kesalahan. Jika batas atas itu terlalu tinggi untuk bujet latensi Anda, kurangi satu lapisan atau turunkan max_retries pada lapisan yang Anda pertahankan.

Untuk informasi selengkapnya tentang setiap bagian konfigurasi ini, lihat Referensi konfigurasi, Opsi koneksi, Pengumpulan koneksi, Logika coba lagi dan ketahanan koneksi, dan autentikasi Microsoft Entra.

Fitur utama

  • Backend Django drop-in: Atur ENGINE ke "mssql" dan perintah ORM, migrasi, admin, dan manajemen Django bekerja melawan SQL Server.
  • Dibangun di atas pyodbc dan ODBC Driver 18: Koneksi terenkripsi TLS secara default dan dukungan platform yang luas di Windows, Linux, dan macOS.
  • Matriks versi lebar: Django 3.2 hingga 6.0, Python 3.8 hingga 3.14, dan SQL Server 2016 hingga 2025.
  • autentikasi Microsoft Entra ID: Koneksi tanpa kata sandi dengan identitas terkelola, perwakilan layanan, interaktif, dan alur terintegrasi melalui extra_params.
  • Migrasi Django: Migrasi skema terhadap SQL Server, termasuk jenis kolom khusus SQL Server.
  • Dukungan JSONField: Native JSONField dengan dukungan penyimpanan nvarchar(max) dan lookup Django.
  • Always Encrypted: Enkripsi sisi klien untuk kolom sensitif.
  • Operasi massal: bulk_create dan bulk_update terhadap SQL Server dengan ukuran batch yang masuk akal.
  • Coba lagi sementara: Penanganan bawaan untuk kesalahan umum Azure SQL sementara selama koneksi dan eksekusi kueri.
  • inspectdb: Hasilkan model Django dari skema SQL Server yang ada.

Get started

Artikel Description
Installation Instal mssql-django dan driver ODBC Microsoft untuk SQL Server.
Mulai cepat: Menyambungkan Django ke SQL Server Sambungkan proyek Django ke SQL Server dan jalankan migrasi pertama Anda.

Mengonfigurasi dan menyambungkan

Artikel Description
Referensi konfigurasi Referensi lengkap untuk kamus Django DATABASES dengan mssql-django.
Opsi koneksi OPTIONS, extra_params, batas waktu, dan konfigurasi driver ODBC.
Pengumpulan koneksi CONN_MAX_AGE, CONN_HEALTH_CHECKS, dan integrasi kumpulan eksternal.
Coba lagi logika dan ketahanan koneksi Mendeteksi kesalahan sementara dan mencoba kembali koneksi dan kueri.
Autentikasi Microsoft Entra Autentikasi tanpa kata sandi dengan identitas terkelola, prinsipal layanan, serta alur interaktif dan terintegrasi.
Praktik terbaik keamanan Parameterisasi, manajemen rahasia, hak istimewa terkecil, dan enkripsi.
Always Encrypted Mengonfigurasi enkripsi sisi klien untuk kolom sensitif.

Model, migrasi, dan jenis data

Artikel Description
Migrasi database Jalankan migrasi Django terhadap SQL Server, termasuk jenis kolom khusus SQL Server.
Pemetaan field Django ke tipe SQL Server Bagaimana field model Django dipetakan ke tipe data SQL Server.
Dukungan JSONField Gunakan JSONField dengan pencarian SQL Server dan Django.
Merekayasa balik model dengan inspectdb Hasilkan model Django dari skema SQL Server yang ada.
Dukungan zona waktu USE_TZ, datetimeoffset, dan datetime yang mendukung zona waktu.

Mengkueri dan bekerja dengan data

Artikel Description
Operasi massal bulk_create, bulk_update, dan penyetelan ukuran batch.
Manajemen transaksi atomic, tingkat isolasi, titik penyimpanan, dan penanganan kebuntuan.
Kueri SQL langsung RawSQL, connection.cursor(), dan sintaks khusus SQL Server.
Prosedur tersimpan Panggil prosedur tersimpan SQL Server di Django.

Menerapkan, menguji, dan menyesuaikan

Artikel Description
Sebarkan ke Azure App Service Kirim situs Django ke Azure App Service dengan mssql-django.
Kontainer dan pengembangan lokal Kontainer docker, devcontainer, dan alur CI untuk Django + SQL Server.
Pengujian Jalankan Rangkaian pengujian Django terhadap SQL Server.
Penyesuaian kinerja Indeks, pola kueri, penggunaan kembali koneksi, dan ukuran batch.
Troubleshooting Kesalahan umum, diagnostik ODBC, dan pengelogan.

Bermigrasi ke mssql-django

Artikel Description
Beralih dari django-mssql-backend Pindah dari paket komunitas django-mssql-backend ke mssql-django.
Beralih dari database lain Pindahkan proyek Django dari backend database lain ke SQL Server.
Migrasi dari PostgreSQL Panduan lengkap bagi pengembang Django yang berpindah dari PostgreSQL ke SQL Server.
Artikel Description
Siklus hidup dukungan Versi Django, Python, dan SQL Server yang didukung.
Apa yang baru Riwayat versi dan sorotan rilis.
Batasan dan fitur yang tidak didukung di mssql-django Batasan backend dan fitur yang tidak didukung.
FAQ Tanya jawab umum.