Nezpracované dotazy SQL v mssql-django

Tento článek vysvětluje, jak spouštět nezpracované dotazy SQL na SQL Server z aplikací Django. Nezpracovaný SQL je užitečný pro operace, které nejsou vystaveny prostřednictvím Django ORM, jako jsou komplexní Transact-SQL (T-SQL), prostorové dotazy nebo kritické operace s výkonem.

Použijte connection.cursor()

Přejděte k kurzoru databáze přímo prostřednictvím objektu connection Django:

from django.db import connection

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

Příkaz with zajistí, že po použití bude kurzor správně zavřený.

Parametrizované dotazy

Vždy používejte parametrizované dotazy, abyste zabránili injektáži SQL. Předání parametrů jako seznamu:

Note

Následující příklady používají výchozí konvenci <app_label>_<model_name> pojmenování tabulek Django (například myapp_product). Pokud v Meta modelu přepíšete db_table, nahraďte jej tímto názvem. Pomocí Product._meta.db_table si také můžete za běhu přečíst vyhodnocený název.

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

K vkládání hodnot do dotazů SQL nikdy nepoužívejte formátování řetězců nebo f-string. Pokud chcete zabránit injektáži SQL, vždy používejte parametrizované dotazy (%s zástupné symboly se seznamem parametrů).

Načíst výsledky

Kurzor Django poskytuje několik metod pro načítání výsledků:

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()

Vrátit výsledky jako slovníky

Převod řádků na slovníky pomocí 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)

Použití Manager.raw() pro dotazy modelu

Pokud chcete nezpracovaný SQL, ale přesto chcete instance modelu Django, použijte 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}")

Dotaz musí vrátit všechna pole definovaná v primárním klíči modelu. Další pole jsou načítána opožděně.

Spouštění příkazů DDL

Pro operace schématu, které Django nepodporuje přímo, použijte nezpracovaný 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);"
        )

Více databázových připojení

Pokud používáte více databází, určete, které připojení se má použít:

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]