mssql-django는 SQL Server, Azure SQL Database, Azure SQL Managed Instance 및 Microsoft Fabric의 SQL 데이터베이스를 위한 Microsoft의 Django용 데이터베이스 백엔드입니다. 연결하려면 Django DATABASES 구성에서 ENGINE을(를) "mssql"(으)로 설정하세요. 백 엔드는 pyodbc 및 Microsoft ODBC Driver for SQL Server 기반으로 하며 Django 3.2~6.0, Python 3.8~ 3.14, 2016~2025년 SQL Server 지원합니다.
시작점 선택
- Django 프로젝트가 SQL Server 빠르게 통신하도록 하려면 빠른 시작: Django를 SQL Server 연결합니다.
- 암호 없는 인증을 사용하여 Django를 Azure SQL 연결하려면 Microsoft Entra 인증 및 구성 참조로 시작합니다.
- 기존 SQL Server 데이터베이스를 Django로 가져오려면 inspectdb를 사용하여 리버스 엔지니어링 모델로 이동합니다.
- Django 사이트를 Azure에 배포하려면 Azure App Service에 배포 및 컨테이너 및 로컬 개발로 이동합니다.
- 다른 Django 백 엔드 또는 데이터베이스에서 마이그레이션하려면 django-mssql-backend에서 마이그레이션, 다른 데이터베이스에서 마이그레이션 또는 PostgreSQL에서 마이그레이션으로 이동합니다.
Azure SQL 대한 프로덕션 기준
이 코드 조각을 프로덕션 지향 Azure SQL 구성의 시작점으로 사용합니다. 4개의 파일 settings.py (Django 데이터베이스 구성, 미들웨어 등록 및 로깅), myproject/retry.py (일시적인 오류 카탈로그 및 retry_on_transient 데코레이터), myproject/middleware.py (요청 수준 재시도 미들웨어) 및 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,
},
},
})
myproject/retry.py에서 공유 임시 오류 카탈로그와 retry_on_transient 데코레이터를 정의합니다:
# 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})
메모
이 기준값은 두 계층에서 재시도를 수행합니다. 미들웨어는 관리자, 신호 또는 기타 미들웨어와 같이 데코레이팅된 뷰 외부에서 데이터베이스 액세스를 위한 백스톱 역할을 합니다. 데코레이터는 @retry_on_transient 뷰 작성자가 재시도하는 작업을 더 세부적으로 제어할 수 있게 해줍니다. 일시적 오류가 데코레이터에서 처리되지 않고 넘어가면 미들웨어가 전체 요청을 다시 시도하므로, 최악의 경우 클라이언트에 오류가 표시되기 전까지 최대 아홉 번 시도할 수 있습니다. 그 상한이 지연 시간 예산에 비해 너무 높다면, 레이어를 하나 줄이거나 유지할 레이어에서 max_retries를 낮추세요.
이 구성의 각 부분에 대한 자세한 내용은 구성 참조, 연결 옵션, 연결 풀링, 재시도 논리 및 연결 복원력 및Microsoft Entra 인증을 참조하세요.
주요 기능
-
드롭인 Django 백엔드:
ENGINE을"mssql"(으)로 설정하면 Django의 ORM, 마이그레이션, 관리자 사이트 및 관리 명령이 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를 통한 관리되는 ID, 서비스 주체, 대화형 및 통합 흐름의 암호 없는 연결. - Django 마이그레이션: SQL Server 전용 열 형식을 포함하여 SQL Server에 대한 스키마 마이그레이션.
-
JSONField 지원:
JSONFieldnvarchar(max) 저장소와 Django 조회 기능을 기반으로 하는 기본 지원. - Always Encrypted: 중요한 열에 대한 클라이언트 쪽 암호화입니다.
-
대량 작업: SQL Server를 대상으로
bulk_create및bulk_update를 적절한 배치 크기로 수행합니다. - 일시적 재시도: 연결 및 쿼리 실행 중 일반적인 Azure SQL 일시적인 오류에 대한 기본 제공 처리입니다.
-
inspectdb: 기존 SQL Server 스키마에서 Django 모델을 생성합니다.
Get started
| 조항 | Description |
|---|---|
| Installation |
mssql-django 및 SQL Server용 Microsoft ODBC Driver를 설치합니다. |
| 빠른 시작: Django를 SQL Server 연결 | Django 프로젝트를 연결하여 SQL Server 첫 번째 마이그레이션을 실행합니다. |
구성 및 연결
| 조항 | Description |
|---|---|
| 구성 참조 | mssql-django를 사용하는 Django DATABASES 사전에 대한 전체 참조입니다. |
| 연결 옵션 |
OPTIONS, extra_params, 시간 제한 및 ODBC 드라이버 구성. |
| 연결 풀링 |
CONN_MAX_AGE, CONN_HEALTH_CHECKS, 및 외부 풀 통합. |
| 재시도 논리 및 연결 복원력 | 일시적인 오류를 검색하고 연결 및 쿼리를 다시 시도합니다. |
| Microsoft Entra 인증 | 관리 ID, 서비스 주체, 대화형 및 통합 흐름을 사용한 암호 없는 인증 |
| 보안 모범 사례 | 매개 변수화, 비밀 관리, 최소 권한 및 암호화. |
| Always Encrypted | 중요한 열에 대한 클라이언트 쪽 암호화를 구성합니다. |
모델, 마이그레이션 및 데이터 형식
| 조항 | Description |
|---|---|
| 데이터베이스 마이그레이션 | SQL Server 특정 열 형식을 포함하여 SQL Server 대해 Django 마이그레이션을 실행합니다. |
| Django 필드의 SQL Server 형식 매핑 | Django 모델 필드가 SQL Server 데이터 형식에 매핑되는 방식 |
| JSONField 지원 |
JSONField를 SQL Server 및 Django 조회 기능과 함께 사용합니다. |
| inspectdb를 사용하여 모델 리버스 엔지니어링 | 기존 SQL Server 스키마에서 Django 모델을 생성합니다. |
| 표준 시간대 지원 |
USE_TZ, datetimeoffset 및 시간대 정보가 포함된 날짜/시간. |
데이터 쿼리 및 작업
| 조항 | Description |
|---|---|
| 대량 작업 |
bulk_create, bulk_update, 그리고 배치 크기 조정. |
| 트랜잭션 관리 |
atomic, 격리 수준, 저장점 및 교착 상태 처리 |
| 원시 SQL 쿼리 |
RawSQL, connection.cursor()및 SQL Server 관련 구문입니다. |
| 저장 프로시저 | Django에서 SQL Server 저장 프로시저를 호출합니다. |
배포, 테스트 및 튜닝
| 조항 | Description |
|---|---|
| Azure App Service에 배포 | mssql-django를 사용하여 Django 사이트를 Azure App Service에 배포합니다. |
| 컨테이너 및 로컬 개발 | Django + SQL Server용 Docker 컨테이너, devcontainers 및 CI 파이프라인 |
| Testing | SQL Server 대해 Django 테스트 제품군을 실행합니다. |
| 성능 튜닝 | 인덱스, 쿼리 패턴, 연결 재사용 및 일괄 처리 크기입니다. |
| Troubleshooting | 일반적인 오류, ODBC 진단 및 로깅. |
mssql-django로 마이그레이션
| 조항 | Description |
|---|---|
| django-mssql-backend에서 마이그레이션 | 커뮤니티 django-mssql-backend 패키지에서 mssql-django로 이동합니다. |
| 다른 데이터베이스에서 마이그레이션 | Django 프로젝트를 다른 데이터베이스 백 엔드에서 SQL Server 이동합니다. |
| PostgreSQL에서 마이그레이션 | PostgreSQL에서 SQL Server 이동하는 Django 개발자를 위한 원스톱 가이드입니다. |
관련 작업
| 조항 | Description |
|---|---|
| 지원 수명 주기 | 지원되는 Django, Python 및 SQL Server 버전입니다. |
| 새로운 기능 | 버전 기록 및 릴리스 하이라이트. |
| mssql-django의 제한 사항 및 지원되지 않는 기능 | 백 엔드 제한 사항 및 지원되지 않는 기능. |
| 자주 묻는 질문(FAQ) | 자주 묻는 질문 |