Onbewerkte SQL-query's in mssql-django

In dit artikel wordt uitgelegd hoe u onbewerkte SQL-query's uitvoert op SQL Server vanuit Django-toepassingen. Onbewerkte SQL is handig voor bewerkingen die niet worden weergegeven via de Django ORM, zoals complexe Transact-SQL (T-SQL), ruimtelijke query's of prestatiekritieke bewerkingen.

Connection.cursor() gebruiken

Open de databasecursor rechtstreeks via het object van 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]

De with instructie zorgt ervoor dat de cursor na gebruik correct wordt gesloten.

Geparameteriseerde query's

Gebruik altijd geparameteriseerde query's om SQL-injectie te voorkomen. Parameters doorgeven als een lijst:

Note

In de volgende voorbeelden wordt de standaardconventie <app_label>_<model_name> voor tabelnamen van Django gebruikt (bijvoorbeeld myapp_product). Als u db_table overschrijft in de Meta van een model, vervangt u die naam. U kunt ook de opgeloste naam tijdens runtime lezen met 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

Gebruik nooit tekenreeksopmaak of f-tekenreeksen om waarden in TE sluiten in SQL-query's. Gebruik altijd geparameteriseerde query's (%s tijdelijke aanduidingen met een parameterlijst) om SQL-injectie te voorkomen.

Resultaten ophalen

Django's cursor biedt verschillende methoden voor het ophalen van resultaten:

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

Resultaten retourneren als woordenlijsten

Rijen converteren naar woordenlijsten met behulp van 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() gebruiken voor modelquery's

Als u onbewerkte SQL wilt, maar nog steeds Django-modelexemplaren wilt, gebruikt u 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}")

De query moet alle velden retourneren die zijn gedefinieerd in de primaire sleutel van het model. Aanvullende velden worden pas geladen wanneer dat nodig is.

DDL-instructies uitvoeren

Gebruik onbewerkte SQL voor schemabewerkingen die Django niet rechtstreeks ondersteunt:

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);"
        )

Meerdere databaseverbindingen

Als u meerdere databases gebruikt, geeft u op welke verbinding u wilt gebruiken:

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]