mssql-django の生 SQL クエリ

この記事では、Django アプリケーションからSQL Serverに対して生の SQL クエリを実行する方法について説明します。 Raw SQL は、複雑な Transact-SQL (T-SQL)、空間クエリ、パフォーマンスクリティカルな操作など、Django ORM を介して公開されない操作に役立ちます。

connection.cursor() を使用する

Django の connection オブジェクトを介してデータベース カーソルに直接アクセスします。

from django.db import connection

def get_server_version():
    with connection.cursor() as cursor:
        cursor.execute("SELECT @@VERSION;")
        row = cursor.fetchone()
    return row[0]

with ステートメントは、使用後にカーソルが正しく閉じられるようにします。

パラメーター化されたクエリ

SQL インジェクションを防ぐには、常にパラメーター化されたクエリを使用します。 パラメーターをリストとして渡します。

Note

次の例では、Django の既定のテーブル名前付け規則 <app_label>_<model_name> (たとえば、 myapp_product) を使用します。 モデルのdb_tableMetaをオーバーライドする場合は、その名前に置き換える必要があります。 Product._meta.db_tableを使用して、実行時に解決された名前を読み取ることもできます。

from django.db import connection

def get_products_by_price(min_price, max_price):
    with connection.cursor() as cursor:
        cursor.execute(
            "SELECT id, name, price FROM myapp_product WHERE price BETWEEN %s AND %s;",
            [min_price, max_price],
        )
        results = cursor.fetchall()
    return results

Important

SQL クエリに値を埋め込むには、文字列の書式設定や f 文字列を使用しないでください。 SQL インジェクションを防ぐために、常にパラメーター化クエリ (パラメーター リストを含むプレースホルダー%s ) を使用します。

結果を取得

Django のカーソルには、結果を取得するためのメソッドがいくつか用意されています。

from django.db import connection

def demonstrate_fetch_methods():
    with connection.cursor() as cursor:
        cursor.execute("SELECT id, name FROM myapp_product;")

        # Fetch one row
        row = cursor.fetchone()

        # Fetch the next 10 rows (continues from where fetchone stopped)
        rows = cursor.fetchmany(10)

        # Fetch all remaining rows (continues from where fetchmany stopped)
        all_rows = cursor.fetchall()

結果をディクショナリとして返す

cursor.descriptionを使用して行をディクショナリに変換する:

from django.db import connection

def dictfetchall(cursor):
    columns = [col[0] for col in cursor.description]
    return [dict(zip(columns, row)) for row in cursor.fetchall()]

def get_all_products():
    with connection.cursor() as cursor:
        cursor.execute("SELECT id, name, price FROM myapp_product;")
        return dictfetchall(cursor)

モデル クエリに Manager.raw() を使用する

生の SQL が必要でも、Django モデル インスタンスが必要な場合は、 Manager.raw()を使用します。

from myapp.models import Product

products = Product.objects.raw(
    "SELECT id, name, price FROM myapp_product WHERE price > %s",
    [10.00],
)

for product in products:
    print(f"{product.name}: ${product.price}")

クエリは、モデルの主キーで定義されているすべてのフィールドを返す必要があります。 追加のフィールドは遅延読み込みされます。

DDL ステートメントの実行

Django が直接サポートしていないスキーマ操作には生 SQL を使用します。

from django.db import connection

def create_index():
    with connection.cursor() as cursor:
        cursor.execute(
            "CREATE INDEX IX_product_name ON myapp_product (name) "
            "INCLUDE (price);"
        )

複数のデータベース接続

複数のデータベースを使用する場合は、使用する接続を指定します。

from django.db import connections

def query_reporting_db():
    with connections["reporting"].cursor() as cursor:
        cursor.execute("SELECT COUNT(*) FROM myapp_product;")
        return cursor.fetchone()[0]