Ответ
Когда Django ORM недостаточно для сложных запросов (оконные функции, рекурсивные CTE, специфичные JOIN), используются сырые SQL-запросы или расширения ORM.
Способы работы с сырым SQL в Django:
-
Manager.raw(): Выполнение SELECT-запросов с маппингом результатов в модели.from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) # Сырой запрос с параметрами для безопасности people = Person.objects.raw(''' SELECT id, first_name, last_name FROM myapp_person WHERE last_name = %s ORDER BY first_name DESC ''', [requested_last_name]) -
Прямое подключение к БД (
django.db.connection): Для запросов, не возвращающих модели (UPDATE, вызов функций).from django.db import connection def my_custom_sql(self): with connection.cursor() as cursor: cursor.execute(""" SELECT COUNT(*) AS url_count FROM myapp_url WHERE path LIKE %s """, ['/api/%']) row = cursor.fetchone() return row[0] -
Выражения
RawSQL: Встраивание SQL-фрагментов прямо в QuerySet.from django.db.models.expressions import RawSQL queryset = Person.objects.annotate( custom_field=RawSQL("some_column - %s", (param,)) )
Почему осторожно?
- SQL-инъекции: Всегда используйте параметризованные запросы (
%s), а не конкатенацию строк. - Переносимость: Сырой SQL привязывает код к конкретной СУБД (PostgreSQL, MySQL).
- Поддержка: Усложняет миграции и может обойти валидацию ORM.
Лучшая практика: Сначала изучите возможности ORM (F(), Q(), Window, Subquery). К сырому SQL прибегайте только в случае необходимости.
Ответ 18+ 🔞
Ох, блядь, смотри-ка, какой вопрос подкинули. Ну что ж, давай разжую, как есть, про эти ваши сырые запросы в Джанге. Ситуация, в общем, стандартная: сидит программист, пыхтит над ORM, а она, сука, упёрлась рогом и не хочет делать какую-нибудь навороченную хуйню вроде оконных функций или рекурсивных CTE. Ну, или JOIN'ы там такие, что сам чёрт ногу сломит. Что делать? Правильно, брать в руки SQL и ебашить напрямую в базу. Но не как попало, а с умом, а то так и до инъекций недалеко.
Так, блядь, как же в Джанге с SQL'ем работать, если ORM сдала назад?
-
Manager.raw()— для ленивых, но осторожных. Это когда тебе нужно просто выбрать данные, но чтобы они вернулись в виде твоих родных моделей, а не какой-то левой хуйни. Как будто ORM, но под капотом — твой кривой запрос.from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) # Смотри, сука, главное — параметры через %s, а не строки склеивать! people = Person.objects.raw(''' SELECT id, first_name, last_name FROM myapp_person WHERE last_name = %s ORDER BY first_name DESC ''', [requested_last_name]) # Вот этот список — наше всё. Безопасность, блядь.Выглядит как ORM, пахнет как ORM, а внутри — твой личный SQL. Удобно, но только для SELECT'ов.
-
Прямое подключение (
django.db.connection) — для отчаянных. Это когда тебе вообще похуй на модели. Надо что-то посчитать, обновить, процедуру какую-нибудь дернуть. Полная свобода, а значит и полная ответственность, чувак.from django.db import connection def my_custom_sql(self): with connection.cursor() as cursor: # Открываем курсор, как банку пива cursor.execute(""" SELECT COUNT(*) AS url_count FROM myapp_url WHERE path LIKE %s """, ['/api/%']) # Опять эти долбаные %s, не забывай! row = cursor.fetchone() # Выковыриваем одну строку return row[0] # И возвращаем то, что нам нужноЗдесь ты уже сам всё контролируешь. И сам же наступаешь на все грабли, если невнимательный.
-
RawSQL— хитрая жопа. Это когда тебе в целом QuerySet норм, но вот одну колонку нужно посчитать какой-то ебаной формулой, которую ORM в жизни не сгенерит. Встраиваем кусочек SQL прямо в аннотацию.from django.db.models.expressions import RawSQL queryset = Person.objects.annotate( custom_field=RawSQL("some_column - %s", (param,)) # И опять параметры! Видишь закономерность? )Точечный укол SQL'ем прямо в тело ORM. Изящно, но опасно, если перестараться.
А теперь, блядь, самое важное — почему это всё надо делать с оглядкой?
- SQL-инъекции — это пиздец. Я не шучу. Если ты будешь склеивать строки типа
f"WHERE name = '{user_input}'", то тебя выебут, обворуют и сольют базу в паблик быстрее, чем ты скажешь "в рот меня чих-пых". Всегда, блядь, ВСЕГДА используй параметризованные запросы (%s). ORM за тебя это делает, а тут ты сам. - Переносимость накрылась медным тазом. Написал кучу сырого SQL под PostgreSQL? Готовься к боли, если завтра начальство скажет переезжать на MySQL. ORM — это абстракция, она защищает от этого дерьма. Сырой SQL — это прямой билет в ад конкретной СУБД.
- Поддержка превращается в пытку. Миграции могут сломаться, потому что ORM не знает про твои левые таблицы или колонки в сыром запросе. Отладка усложняется в три раза.
Так что, золотое правило, ёпта: Сначала выеби мозг документации Джанги. Посмотри на F(), Q(), Window, Subquery — может, ORM таки сможет то, что тебе нужно, просто ты не знал как спросить. К сырому SQL иди только тогда, когда все остальные пути отрезаны, и ты точно знаешь, что делаешь. А иначе — сам виноват будет.