mssql-django는 SQL Server, Azure SQL Database, Azure SQL Managed Instance 및 Microsoft Fabric의 SQL 데이터베이스를 위한 Microsoft의 Django용 데이터베이스 백엔드입니다. 연결하려면 Django ENGINE 구성에서 "mssql"을(를) DATABASES(으)로 설정하세요. 버전 2.0은 Django 5.2부터 6.1, Python 3.10부터 3.14, SQL Server 2017부터 2025까지 지원합니다. 기본값인 Microsoft ODBC Driver for SQL Server와 함께 pyodbc를 통해 또는 Microsoft의 mssql-python 드라이버를 통해 연결됩니다.
시작점 선택
- 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;"
# Parallel dials to all resolved IPs; safe on single-IP targets.
"MultiSubnetFailover=Yes;"
# 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})
메모
이 기준값은 두 계층에서 재시도를 수행합니다. 미들웨어는 관리자, 신호 또는 기타 미들웨어와 같이 데코레이팅된 뷰 외부에서 데이터베이스 액세스를 위한 백스톱 역할을 합니다. 데코레이터는 @retry_on_transient 뷰 작성자가 재시도하는 작업을 더 세부적으로 제어할 수 있게 해줍니다. 일시적 오류가 데코레이터에서 처리되지 않고 넘어가면 미들웨어가 전체 요청을 다시 시도하므로, 최악의 경우 클라이언트에 오류가 표시되기 전까지 최대 아홉 번 시도할 수 있습니다. 그 상한이 지연 시간 예산에 비해 너무 높다면, 레이어를 하나 줄이거나 유지할 레이어에서 max_retries를 낮추세요.
이 구성의 각 부분에 대한 자세한 내용은 구성 참조, 연결 옵션, 연결 풀링, 재시도 논리 및 연결 복원력 및Microsoft Entra 인증을 참조하세요.
주요 기능
-
드롭인 Django 백엔드:
ENGINE을"mssql"(으)로 설정하면 Django의 ORM, 마이그레이션, 관리자 사이트 및 관리 명령이 SQL Server에서 작동합니다. -
mssql-python 지원: 데이터베이스 별칭에 대해 Microsoft 드라이버를
mssql-python선택하고 별도의 ODBC 드라이버 설치를 건너뛰세요. 기본 드라이버는 외부에 설치된 Microsoft ODBC 드라이버를pyodbc사용합니다. -
기본적으로 암호화된 연결: 경로상
pyodbc의 기본값인 SQL Server용 ODBC 드라이버 18은 Windows, Linux, macOS에서 연결을 암호화하고 서버 인증서를 검증합니다. - 현재 버전 매트릭스: Django 5.2부터 6.1, Python 3.10부터 3.14, SQL Server 2017부터 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 |
pyodbc 및 기본 mssql-django 경로의 경우 Microsoft ODBC Driver for SQL Server를 설치하세요. |
| 빠른 시작: Django를 SQL Server 연결 | Django 프로젝트를 연결하여 SQL Server 첫 번째 마이그레이션을 실행합니다. |
구성 및 연결
| 조항 | Description |
|---|---|
| 구성 참조 | mssql-django를 사용하는 Django DATABASES 사전에 대한 전체 참조입니다. |
| 연결 옵션 |
OPTIONS
extra_params, , 타임아웃, MARS와 ODBC 드라이버 구성이 포함됩니다. |
| 데이터베이스 드라이버를 선택합니다 | 기본 pyodbc 드라이버 대신 데이터베이스 별칭을 선택하세요mssql-python. |
| 연결 풀링 |
CONN_MAX_AGE, CONN_HEALTH_CHECKS, 및 외부 풀 통합. |
| 재시도 논리 및 연결 복원력 | 일시적인 오류를 검색하고 연결 및 쿼리를 다시 시도합니다. |
| Microsoft Entra 인증 | 관리 ID, 서비스 주체, 대화형 및 통합 흐름을 사용한 암호 없는 인증 |
| 보안 모범 사례 | 매개 변수화, 비밀 관리, 최소 권한 및 암호화. |
| 항상 암호화되어 있습니다 | 중요한 열에 대한 클라이언트 쪽 암호화를 구성합니다. |
모델, 마이그레이션 및 데이터 형식
| 조항 | 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) | 자주 묻는 질문 |