Kueri SQL mentah di mssql-django

Artikel ini menjelaskan cara menjalankan kueri SQL mentah terhadap SQL Server dari aplikasi Django. SQL mentah berguna untuk operasi yang tidak diekspos melalui ORM Django, seperti Transact-SQL kompleks (T-SQL), kueri spasial, atau operasi kritis performa.

Gunakan connection.cursor()

Akses kursor database langsung melalui objek 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]

Pernyataan with memastikan bahwa kursor ditutup dengan benar setelah digunakan.

Kueri dengan parameter

Selalu gunakan kueri berparameter untuk mencegah injeksi SQL. Berikan parameter sebagai daftar:

Note

Contoh berikut menggunakan konvensi <app_label>_<model_name> penamaan tabel default Django (misalnya, myapp_product). Jika Anda mengambil alih db_table dalam model, ganti nama tersebut Meta. Anda juga dapat membaca nama hasil resolusi saat runtime dengan 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

Jangan pernah menggunakan pemformatan string atau f-string untuk menyematkan nilai dalam kueri SQL. Selalu gunakan kueri berparameter (%s tempat penampung dengan daftar parameter) untuk mencegah injeksi SQL.

Ambil hasil

Kursor Django menyediakan beberapa metode untuk mengambil hasil:

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

Mengembalikan hasil sebagai kamus

Konversi baris menjadi kamus menggunakan 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)

Gunakan Manager.raw() untuk melakukan kueri pada model

Ketika Anda menginginkan SQL mentah tetapi masih menginginkan instans model Django, gunakan 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}")

Kueri harus mengembalikan semua bidang yang ditentukan dalam kunci primer model. Bidang tambahan dimuat saat diperlukan.

Menjalankan pernyataan DDL

Gunakan SQL mentah untuk operasi skema yang tidak didukung Django secara langsung:

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

Beberapa koneksi database

Jika Anda menggunakan beberapa database, tentukan koneksi mana yang akan digunakan:

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]