使用 mssql-django 进行容器和本地开发

本指南涵盖使用 mssql-django 后端的 Django 开发人员在 Windows、Linux、macOS、Docker 容器、devcontainers 和 CI 管道中的环境配置。

先决条件

  • Python 3.8 或更高版本(Django 6.0 需要Python 3.12 及更高版本)
  • Docker Desktop (用于基于容器的开发)
  • 适用于 SQL Server 的 Microsoft ODBC Driver 17 或 18。 请参阅下载适用于 SQL Server 的 ODBC 驱动程序

sqlcmd (Go) 实用工具可以在单个命令中创建SQL Server容器。 它会自动处理 Docker 映像拉取、密码生成、端口分配和连接上下文:

sqlcmd create mssql --accept-eula

若要创建已附加示例数据库的容器,

sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak

创建后, sqlcmd 存储连接上下文,以便可以立即查询:

sqlcmd query "SELECT @@VERSION"

配置 Django,使用 sqlcmd 在创建时输出的连接信息进行连接。 使用 sqlcmd config view 以便稍后检索它们:

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "master",
        "USER": "sa",
        "PASSWORD": "<password from sqlcmd output>",
        "HOST": "localhost",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "TrustServerCertificate=yes",
        },
    },
}

完成后,停止或删除容器:

sqlcmd stop
sqlcmd delete

Tip

运行 sqlcmd create mssql --user-database mydb 以创建一个容器,其中包含一个可供开发的空用户数据库。

Visual Studio Code中的本地SQL Server

用于Visual Studio Code的 MSSQL 扩展可以直接从编辑器创建本地SQL Server容器:

  1. 在活动栏中打开SQL Server视图。
  2. 选择“添加连接>创建本地SQL Server”(或使用命令面板:MS SQL:创建本地SQL Server)。
  3. 选择SQL Server版本并接受 EULA。
  4. 该扩展会拉取容器映像,生成密码,并自动添加连接配置文件。

容器运行后,可以在切换到 Django 代码之前浏览数据库、运行查询和管理Visual Studio Code中的对象。

使用 Docker 的本地SQL Server

如果希望直接管理容器,官方SQL Server容器映像适用于两个环境变量:

docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=YourStr0ngP@ssword" \
  -p 1433:1433 --name sql1 \
  -d mcr.microsoft.com/mssql/server:2022-latest

Important

对 SQL Server 容器使用 MSSQL_SA_PASSWORD。 旧 SA_PASSWORD 变量已弃用。 密码必须满足SQL Server复杂性要求:至少 8 个字符,包含大写、小写、数字和特殊字符。

等待几秒钟,让容器启动,然后运行迁移:

python manage.py migrate
python manage.py createsuperuser

Django 应用程序的 Dockerfile

为连接到 SQL Server 的 Django 应用程序创建最小 Dockerfile。 ODBC 驱动程序是 Python 基础镜像未附带的关键依赖项:

FROM python:3-slim

# Install ODBC Driver 18 for SQL Server
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl gnupg2 && \
    curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
        gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg && \
    echo "deb [signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > \
        /etc/apt/sources.list.d/mssql-release.list && \
    apt-get update && \
    ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 unixodbc-dev && \
    apt-get purge -y curl gnupg2 && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

你的 requirements.txt

django>=5.2
mssql-django>=1.5
gunicorn>=22.0

生成并运行:

docker build -t mydjango .
docker run -e DB_HOST=host.docker.internal -e DB_NAME=mydb \
  -e DB_USER=<your-username> -e DB_PASSWORD=<your-password> \
  -p 8000:8000 mydjango

Note

在 Docker Desktop(Windows 和 macOS)中使用 host.docker.internal 连接到主机上的 SQL Server。 在 Linux 上,请改用 --network host

Devcontainer 设置

为 Visual Studio Code 创建一个.devcontainer/devcontainer.json,其中包含作为 sidecar 服务的 SQL Server:

{
    "name": "Django + SQL Server",
    "image": "mcr.microsoft.com/devcontainers/python:3",
    "features": {
        "ghcr.io/devcontainers/features/docker-in-docker:2": {}
    },
    "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
    "postCreateCommand": "bash .devcontainer/post-create.sh",
    "forwardPorts": [1433, 8000],
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-mssql.mssql"
            ]
        }
    }
}

此 devcontainer 安装 ODBC 驱动程序和Python依赖项,但不包括SQL Server实例。 在 devcontainer 内部使用 sqlcmd create mssql --accept-eula 启动一个实例(因为支持 Docker-in-Docker),或者使用 Docker Compose 方法来使用内置的 SQL Server 服务。

创建.devcontainer/post-create.sh以安装 ODBC 驱动程序并Python依赖项:

#!/bin/bash
set -e

# Install ODBC Driver 18
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
    sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
echo "deb [signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" | \
    sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-dev

pip install -r requirements.txt

将SQL Server包含在 Docker Compose 中

若要将SQL Server作为服务包含在 devcontainer 中,请使用 Docker Compose:

.devcontainer/docker-compose.yml

services:
  app:
    image: mcr.microsoft.com/devcontainers/python:3
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    depends_on:
      - db

  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "YourStr0ngP@ssword"
    ports:
      - "1433:1433"

.devcontainer/devcontainer.json (撰写版本):

{
    "name": "Django + SQL Server",
    "dockerComposeFile": "docker-compose.yml",
    "service": "app",
    "workspaceFolder": "/workspace",
    "postCreateCommand": "bash .devcontainer/post-create.sh",
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-mssql.mssql"
            ]
        }
    }
}

按名称将 Django 连接到 SQL Server 服务:

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "mydb",
        "USER": "sa",
        "PASSWORD": "<password>",
        "HOST": "db",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "TrustServerCertificate=yes",
        },
    },
}

用于开发的身份验证

根据应用程序运行的位置和托管数据库的位置选择身份验证方法。

针对Azure SQL的本地开发

对于针对 Azure SQL 的本地开发,请在 OPTIONS["extra_params"] 中使用 Authentication=ActiveDirectoryDefault(需配合 mssql-django 1.7.3 及更高版本,以及兼容的 Microsoft ODBC Driver),或配合 DefaultAzureCredential 使用 TOKEN 设置。 DefaultAzureCredential 自动检测到您的 az login 会话:

from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
token = credential.get_token("https://database.windows.net/.default").token

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "mydb",
        "HOST": "myserver.database.windows.net",
        "PORT": "1433",
        "TOKEN": token,
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
        },
    },
}

有关完整身份验证矩阵和警告,请参阅Microsoft Entra使用 mssql-django 进行身份验证

针对Azure SQL的容器开发

对于在 Azure 中运行的容器,请将 TOKEN 设置与 ManagedIdentityCredential 配合使用,以显式获取 Microsoft Entra 访问令牌:

from azure.identity import ManagedIdentityCredential

credential = ManagedIdentityCredential()
token = credential.get_token("https://database.windows.net/.default").token

DATABASES = {
  "default": {
    "ENGINE": "mssql",
    "NAME": "mydb",
    "HOST": "myserver.database.windows.net",
    "PORT": "1433",
    "TOKEN": token,
    "OPTIONS": {
      "driver": "ODBC Driver 18 for SQL Server",
    },
  },
}

有关身份验证方法的完整列表,请参阅Microsoft Entra使用 mssql-django 进行身份验证

CI 管道设置

针对 CI 管道中的SQL Server服务容器运行 Django 测试套件。

GitHub Actions

name: Django Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      sqlserver:
        image: mcr.microsoft.com/mssql/server:2022-latest
        env:
          ACCEPT_EULA: Y
          MSSQL_SA_PASSWORD: YourStr0ngP@ssword
        ports:
          - 1433:1433
        options: >-
          --health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P \"$$MSSQL_SA_PASSWORD\" -C -Q 'SELECT 1'"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"

      - name: Install ODBC Driver
        run: |
          curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
              sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
          echo "deb [signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/$(lsb_release -rs)/prod $(lsb_release -cs) main" | \
              sudo tee /etc/apt/sources.list.d/mssql-release.list
          sudo apt-get update
          sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-dev

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run tests
        env:
          DB_HOST: localhost
          DB_NAME: master
          DB_USER: <username>
          DB_PASSWORD: <password>
        run: python manage.py test

Tip

对于共享管道,请将内联占位符密码替换为加密的机密(${{ secrets.SQL_PWD }}),并将SQL Server服务映像固定到摘要中。

Azure Pipelines

trigger:
  - main

resources:
  containers:
    - container: sqlserver
      image: mcr.microsoft.com/mssql/server:2022-latest
      env:
        ACCEPT_EULA: Y
        MSSQL_SA_PASSWORD: YourStr0ngP@ssword
      ports:
        - 1433:1433

pool:
  vmImage: ubuntu-latest

services:
  sqlserver: sqlserver

steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: "3.x"

  - script: |
      curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
          sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
      echo "deb [signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/$(lsb_release -rs)/prod $(lsb_release -cs) main" | \
          sudo tee /etc/apt/sources.list.d/mssql-release.list
      sudo apt-get update
      sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-dev
      pip install -r requirements.txt
    displayName: Install dependencies

  - script: python manage.py test
    displayName: Run tests
    env:
      DB_HOST: localhost
      DB_NAME: master
      DB_USER: <username>
      DB_PASSWORD: <password>

基于环境的 settings.py

settings.py 配置为从环境变量中读取数据库凭据。 此单一配置适用于本地开发、Docker 和 CI:

import os

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": os.environ.get("DB_NAME", "mydb"),
        "USER": os.environ.get("DB_USER", ""),
        "PASSWORD": os.environ.get("DB_PASSWORD", ""),
        "HOST": os.environ.get("DB_HOST", "localhost"),
        "PORT": os.environ.get("DB_PORT", "1433"),
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": os.environ.get("DB_EXTRA_PARAMS", "TrustServerCertificate=yes"),
        },
    },
}

将凭据存储在用于本地开发的 .env 文件中(将 .env 添加到 .gitignore 中):

DB_HOST=localhost
DB_NAME=mydb
DB_USER=<username>
DB_PASSWORD=<password>

使用 django-environpython-dotenv 加载环境变量:

pip install django-environ
import environ

env = environ.Env()
environ.Env.read_env()  # Reads .env file

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": env("DB_NAME"),
        "USER": env("DB_USER", default=""),
        "PASSWORD": env("DB_PASSWORD", default=""),
        "HOST": env("DB_HOST", default="localhost"),
        "PORT": env("DB_PORT", default="1433"),
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
        },
    },
}

注意

切勿将 .env 文件提交到源代码管理系统。 将 .env 添加到 .gitignore 文件。

排查常见容器问题

症状 原因 修复
Can't open lib 'ODBC Driver 18 for SQL Server' 未安装在容器中的 ODBC 驱动程序。 在 Dockerfile 或 post-create 脚本中安装 msodbcsql18
端口 1433 上的连接被拒绝 SQL Server容器未就绪。 添加运行状况检查或等待服务启动。
Login failed for user '<username>' 凭据不正确或密码不符合复杂性要求。 为容器使用正确的 SQL 登录名,并确保密码满足复杂性要求。
Cannot open database 数据库尚不存在。 在运行 migrate 之前创建数据库,或使用 master 进行初始设置。
容器内首次连接缓慢 DNS 解析或凭证链启动过程。 对于本地SQL Server,请使用localhost而不是主机名。
SSL Provider: [error:0A000086] 使用自签名证书的 TLS 证书验证失败。 仅用于开发时,将 TrustServerCertificate=yes 添加到 extra_params 中。