در جنگو، برای تعامل با پایگاه داده و اجرای دستورات SQL میتوان از QuerySet استفاده کرد که یک API سطح بالا برای انجام عملیات پایگاه داده فراهم میکند. اما در برخی مواقع نیاز دارید که دستورات SQL سفارشی را اجرا کنید. جنگو این امکان را به شما میدهد که به راحتی دستورات SQL خام را از طریق QuerySet اجرا کنید.
۱. اجرای دستورات SQL با استفاده از ()raw
برای اجرای دستورات SQL به صورت خام در جنگو، میتوان از متد ()raw استفاده کرد. این متد به شما اجازه میدهد تا یک دستور SQL سفارشی را به طور مستقیم اجرا کنید و نتایج آن را به صورت یک QuerySet دریافت کنید.
مثال:
فرض کنید یک مدل به نام Book داریم و میخواهیم یک دستور SQL برای گرفتن همه کتابها با یک نویسنده خاص اجرا کنیم.
مدل:
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
published_date = models.DateTimeField()
برای اجرای دستور SQL خام برای بازیابی تمام کتابها از نویسنده خاص، از کد زیر استفاده میکنیم:
# اجرای دستور SQL خام
books = Book.objects.raw('SELECT * FROM myapp_book WHERE author = %s', ['J.K. Rowling'])
# نمایش نتایج
for book in books:
print(book.title)
در این مثال:
- دستور SQL به صورت SELECT * FROM myapp_book WHERE author = %s نوشته شده است که در آن %s به عنوان placeholder برای پارامتر استفاده میشود.
- پارامتر 'J.K. Rowling' در آرایه به دستور SQL تزریق میشود.
۲. استفاده از ()connection.cursor برای اجرای دستورات SQL بدون استفاده از QuerySet
در برخی مواقع ممکن است بخواهید که به صورت مستقیم دستورات SQL را اجرا کنید (نه فقط SELECT). برای این منظور میتوانید از connection.cursor() استفاده کنید که به شما این امکان را میدهد که دستورات SQL را اجرا کنید و نتایج را مدیریت کنید.
مثال:
# گرفتن یک cursor برای اجرای دستورات SQL
with connection.cursor() as cursor:
cursor.execute("INSERT INTO myapp_book (title, author, published_date) VALUES (%s, %s, %s)", ['New Book', 'John Doe', '2025-03-09'])
در اینجا:
- از ()connection.cursor برای گرفتن یک cursor استفاده میکنیم.
- دستور INSERT با پارامترها به پایگاه داده ارسال میشود.
- توجه کنید که استفاده از with باعث میشود که cursor بعد از استفاده به طور خودکار بسته شود.
۳. دستورات SELECT سفارشی و دسترسی به نتایج
اگر بخواهید نتیجه دستورات SQL را به صورت سفارشی پردازش کنید (مثل استفاده از یک JOIN پیچیده یا محاسبات خاص)، میتوانید از raw() یا connection.cursor() برای دریافت دادهها استفاده کنید.
مثال:
فرض کنید میخواهیم مجموع تعداد کتابها را برای هر نویسنده در پایگاه داده محاسبه کنیم:
# اجرای دستور SQL برای محاسبه مجموع تعداد کتابها برای هر نویسنده
with connection.cursor() as cursor:
cursor.execute("SELECT author, COUNT(*) FROM myapp_book GROUP BY author")
result = cursor.fetchall()
# نمایش نتایج
for row in result:
print(f"Author: {row[0]}, Number of Books: {row[1]}")
در اینجا:
- دستور SQL یک GROUP BY را اجرا میکند تا تعداد کتابها برای هر نویسنده را محاسبه کند.
- نتیجه دستور SQL با استفاده از ()fetchall دریافت میشود که یک لیست از دادهها را به شکل tuple باز میگرداند.
۴. احتیاطهای امنیتی در استفاده از دستورات SQL
- جلوگیری از حملات SQL Injection: همیشه از placeholderها (مثل %s) برای تزریق پارامترها به دستور SQL استفاده کنید تا از حملات SQL injection جلوگیری کنید. دستورات SQL خام بدون استفاده از placeholderها میتوانند بسیار خطرناک باشند.
- استفاده از ()raw فقط برای عملیاتهای خاص: اگر امکانپذیر است، از QuerySetهای پیشفرض جنگو برای انجام عملیاتهای پایگاه داده استفاده کنید تا مزایای امنیتی و عملکرد بهینه را دریافت کنید.
نتیجهگیری
در جنگو میتوانید از روشهای مختلفی برای اجرای دستورات SQL استفاده کنید، از جمله:
- ()raw برای اجرای دستورات SELECT و بازگشت نتایج به صورت یک QuerySet.
- ()connection.cursor برای اجرای دستورات SQL بدون استفاده از QuerySet و انجام دستورات INSERT، UPDATE، DELETE و SELECT پیچیدهتر.
این قابلیتها به شما کمک میکنند تا دستورات SQL را به صورت سفارشی و با دقت بیشتر در پروژههای جنگویی خود اجرا کنید.
