Bemærk
Adgang til denne side kræver godkendelse. Du kan prøve at logge på eller ændre mapper.
Adgang til denne side kræver godkendelse. Du kan prøve at ændre mapper.
mssql-django is Microsoft's Django database backend for SQL Server, Azure SQL Database, Azure SQL Managed Instance, and SQL database in Microsoft Fabric. Set ENGINE to "mssql" in your Django DATABASES configuration to connect. The backend builds on pyodbc and the Microsoft ODBC Driver for SQL Server, and supports Django 3.2 through 6.0, Python 3.8 through 3.14, and SQL Server 2016 through 2025.
Choose your starting point
- To get a Django project talking to SQL Server quickly, start with Quickstart: Connect Django to SQL Server.
- To connect Django to Azure SQL with passwordless authentication, start with Microsoft Entra authentication and Configuration reference.
- To bring an existing SQL Server database into Django, go to Reverse engineer models with inspectdb.
- To deploy a Django site to Azure, go to Deploy to Azure App Service and Container and local development.
- To migrate from another Django backend or database, go to Migrate from django-mssql-backend, Migrate from other databases, or Migrate from PostgreSQL.
Production baseline for Azure SQL
Use this snippet as a starting point for a production-oriented Azure SQL configuration. It combines four files: settings.py (the Django database configuration, middleware registration, and logging), myproject/retry.py (the transient-error catalog and retry_on_transient decorator), myproject/middleware.py (the request-level retry middleware), and myapp/views.py (an example transactional view).
# 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,
},
},
})
Define the shared transient-error catalog and the 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
Define the request-level middleware in myproject/middleware.py. It reuses is_transient so both layers recognize the same set of error codes:
# 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
Because ATOMIC_REQUESTS is False, mutating views must open their own transaction. Wrap the atomic() block with @retry_on_transient so each retry runs a fresh transaction:
# 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
This baseline registers retry at two layers. The middleware acts as a backstop for database access outside of decorated views, such as the admin, signals, or other middleware. The @retry_on_transient decorator gives view authors finer control over which operations retry. If a transient error escapes the decorator, the middleware retries the whole request, so the worst case is up to nine attempts before the client sees an error. If that ceiling is too high for your latency budget, drop one layer or lower max_retries on the layer you keep.
For more information about each part of this configuration, see Configuration reference, Connection options, Connection pooling, Retry logic and connection resilience, and Microsoft Entra authentication.
Key features
- Drop-in Django backend: Set
ENGINEto"mssql"and Django's ORM, migrations, admin, and management commands work against SQL Server. - Built on pyodbc and ODBC Driver 18: TLS-encrypted connections by default and broad platform support on Windows, Linux, and macOS.
- Wide version matrix: Django 3.2 through 6.0, Python 3.8 through 3.14, and SQL Server 2016 through 2025.
- Microsoft Entra ID authentication: Passwordless connections with managed identity, service principal, interactive, and integrated flows via
extra_params. - Django migrations: Schema migrations against SQL Server, including SQL Server-specific column types.
- JSONField support: Native
JSONFieldbacked by the nvarchar(max) storage and Django lookups. - Always Encrypted: Client-side encryption for sensitive columns.
- Bulk operations:
bulk_createandbulk_updateagainst SQL Server with sensible batch sizes. - Transient retry: Built-in handling for common Azure SQL transient errors during connection and query execution.
inspectdb: Generate Django models from existing SQL Server schemas.
Get started
| Article | Description |
|---|---|
| Installation | Install mssql-django and the Microsoft ODBC Driver for SQL Server. |
| Quickstart: Connect Django to SQL Server | Connect a Django project to SQL Server and run your first migration. |
Configure and connect
| Article | Description |
|---|---|
| Configuration reference | Full reference for the Django DATABASES dictionary with mssql-django. |
| Connection options | OPTIONS, extra_params, timeouts, and ODBC driver configuration. |
| Connection pooling | CONN_MAX_AGE, CONN_HEALTH_CHECKS, and external pool integration. |
| Retry logic and connection resilience | Detect transient errors and retry connections and queries. |
| Microsoft Entra authentication | Passwordless authentication with managed identity, service principal, interactive, and integrated flows. |
| Security best practices | Parameterization, secrets management, least privilege, and encryption. |
| Always Encrypted | Configure client-side encryption for sensitive columns. |
Models, migrations, and data types
| Article | Description |
|---|---|
| Database migrations | Run Django migrations against SQL Server, including SQL Server-specific column types. |
| Django field to SQL Server type mappings | How Django model fields map to SQL Server data types. |
| JSONField support | Use JSONField with SQL Server and Django lookups. |
| Reverse engineer models with inspectdb | Generate Django models from existing SQL Server schemas. |
| Time zone support | USE_TZ, datetimeoffset, and time zone-aware datetimes. |
Query and work with data
| Article | Description |
|---|---|
| Bulk operations | bulk_create, bulk_update, and batch size tuning. |
| Transaction management | atomic, isolation levels, savepoints, and deadlock handling. |
| Raw SQL queries | RawSQL, connection.cursor(), and SQL Server-specific syntax. |
| Stored procedures | Call SQL Server stored procedures from Django. |
Deploy, test, and tune
| Article | Description |
|---|---|
| Deploy to Azure App Service | Ship a Django site to Azure App Service with mssql-django. |
| Container and local development | Docker containers, devcontainers, and CI pipelines for Django + SQL Server. |
| Testing | Run Django test suites against SQL Server. |
| Performance tuning | Indexes, query patterns, connection reuse, and batch sizes. |
| Troubleshooting | Common errors, ODBC diagnostics, and logging. |
Migrate to mssql-django
| Article | Description |
|---|---|
| Migrate from django-mssql-backend | Move from the community django-mssql-backend package to mssql-django. |
| Migrate from other databases | Move a Django project from another database backend to SQL Server. |
| Migrate from PostgreSQL | One-stop guide for Django developers moving from PostgreSQL to SQL Server. |
Related tasks
| Article | Description |
|---|---|
| Support lifecycle | Supported Django, Python, and SQL Server versions. |
| What's new | Version history and release highlights. |
| Limitations and unsupported features in mssql-django | Backend limitations and unsupported features. |
| FAQ | Frequently asked questions. |