Серверная часть Django для SQL Server — mssql-django

mssql-django — это интерфейс Django к базе данных от Microsoft для SQL Server, Базы данных SQL Azure, Управляемого экземпляра SQL Azure и базы данных SQL в Microsoft Fabric. Установите значение ENGINE"mssql" в конфигурации Django DATABASES для подключения. Серверная часть строится на pyodbc и Microsoft ODBC Driver for SQL Server и поддерживает Django 3.2–6.0, Python 3.8–3.14 и SQL Server 2016 по 2025 год.

Выберите начальную точку

Производственные базовые показатели для Azure SQL

Используйте этот фрагмент в качестве отправной точки для рабочей Azure SQL конфигурации. Он объединяет четыре файла: settings.py (конфигурация базы данных Django, регистрация промежуточного ПО и ведение журнала), myproject/retry.py (каталог временных ошибок и декоратор retry_on_transient), myproject/middleware.py (middleware повторных попыток на уровне запроса) и myapp/views.py (пример транзакционного представления).

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

Определите общий каталог временных ошибок и декоратор retry_on_transient в 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

Определите промежуточное ПО на уровне запроса в myproject/middleware.py. Он повторно использует is_transient, чтобы оба слоя распознавали один и тот же набор кодов ошибок:

# 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

Так как ATOMIC_REQUESTS является False, изменяющие представления должны открывать собственную транзакцию. Оберните блок atomic() в @retry_on_transient, чтобы каждая повторная попытка выполнялась в новой транзакции:

# 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

Эта базовая конфигурация предусматривает повторные попытки на двух уровнях. ПО промежуточного слоя выступает в качестве серверной части для доступа к базе данных за пределами декорированных представлений, таких как администратор, сигналы или другое ПО промежуточного слоя. Декоратор @retry_on_transient предоставляет авторам представлений более гибкий контроль над тем, для каких операций выполняется повторная попытка. Если временная ошибка проходит через декоратор, промежуточный слой повторно выполняет весь запрос, поэтому в худшем случае возможно до девяти попыток, прежде чем клиент увидит ошибку. Если этот предел слишком высок для вашего бюджета задержки, уберите один слой или уменьшите max_retries в том слое, который оставляете.

Дополнительные сведения о каждой части этой конфигурации см. в справочнике по конфигурации, параметрах подключения, пуле подключений, логике повторных попыток и устойчивости подключений и Microsoft Entra проверке подлинности.

Ключевые особенности

  • Подключаемый backend Django: установите ENGINE в значение "mssql", и ORM Django, миграции, админ-панель и команды управления будут работать с SQL Server.
  • Основан на pyodbc и ODBC Driver 18: tls-зашифрованные подключения по умолчанию и широкая поддержка платформы на Windows, Linux и macOS.
  • Матрица широкой версии: Django 3.2–6.0, Python 3.8 до 3.14 и SQL Server 2016 по 2025 год.
  • Аутентификация Microsoft Entra ID: подключения без пароля с использованием управляемого удостоверения, субъекта-службы, интерактивных и интегрированных потоков через extra_params.
  • Миграции Django: миграция схем в SQL Server, включая типы столбцов SQL Server.
  • Поддержка JSONField: нативный JSONField, поддерживаемый хранилищем nvarchar(max) и операциями поиска Django.
  • Always Encrypted: шифрование на стороне клиента для конфиденциальных столбцов.
  • Массовые операции: bulk_create и bulk_update против SQL Server с разумными размерами пакетов.
  • Временная повторная попытка: встроенная обработка распространенных Azure SQL временных ошибок во время подключения и выполнения запроса.
  • inspectdb: создание моделей Django из существующих схем SQL Server.

Get started

Статья Описание
Installation Установите mssql-django и Microsoft драйвер ODBC для SQL Server.
Краткое руководство. Подключение Django к SQL Server Подключите проект Django к SQL Server и выполните первую миграцию.

Настройка и подключение

Статья Описание
Справочник по конфигурации Полный справочник по словарю Django с mssql-django DATABASES .
Параметры подключения OPTIONS, extra_params, тайм-ауты и конфигурация драйвера ODBC.
Организация пулов соединений CONN_MAX_AGE, CONN_HEALTH_CHECKS и интеграция с внешним пулом.
Логика повторных попыток и устойчивость подключений Обнаруживайте временные ошибки и повторяйте попытки подключений и запросов.
Аутентификация Microsoft Entra Аутентификация без пароля с использованием управляемой идентичности, субъекта-службы, интерактивных и интегрированных потоков аутентификации.
Лучшие методики обеспечения безопасности Параметризация, управление секретами, наименьшие привилегии и шифрование.
Always Encrypted Настройте шифрование на стороне клиента для конфиденциальных столбцов.

Модели, миграции и типы данных

Статья Описание
Миграция баз данных Выполняйте миграции Django для SQL Server, включая специфичные для SQL Server типы столбцов.
Поле Django для сопоставления типов SQL Server Сопоставление полей модели Django с SQL Server типами данных.
Поддержка JSONField Используйте JSONField с SQL Server и операциями поиска Django.
Выполните обратное проектирование моделей с помощью inspectdb Создайте модели Django из существующих схем SQL Server.
Поддержка часового пояса USE_TZ, datetimeoffset и объекты datetime с учётом часового пояса.

Запрос и работа с данными

Статья Описание
Массовые операции bulk_create, bulk_update, и настройка размера пакета.
Управление транзакциями atomic, уровни изоляции, точки сохранения и обработка взаимоблокировок.
Необработанные запросы SQL RawSQL, connection.cursor()и синтаксис, зависящий от SQL Server.
Хранимые процедуры Вызывайте хранимые процедуры SQL Server из Django.

Развертывание, тестирование и настройка

Статья Описание
Развернуть в Службу приложений Azure Отправьте сайт Django в Служба приложений Azure с помощью mssql-django.
Контейнер и локальная разработка Контейнеры Docker, devcontainers и конвейеры CI для Django + SQL Server.
Testing Запустите наборы тестов Django для SQL Server.
Настройка производительности Индексы, шаблоны запросов, повторное использование подключений и размеры пакетов.
Troubleshooting Распространенные ошибки, диагностика ODBC и ведение журнала.

Переход на mssql-django

Статья Описание
Переход с django-mssql-backend Перейдите с пакета Community django-mssql-backend на mssql-django.
Перейдите с других баз данных Переместите проект Django из другой серверной части базы данных в SQL Server.
Миграция из PostgreSQL Исчерпывающее руководство для разработчиков Django, переходящих с PostgreSQL на SQL Server.
Статья Описание
Жизненный цикл поддержки Поддерживаемые версии Django, Python и SQL Server.
Новые возможности Журнал версий и основные моменты выпуска.
Ограничения и неподдерживаемые функции в mssql-django Ограничения серверной части и неподдерживаемые функции.
FAQ Часто задаваемые вопросы.