Это расширение возможностей можно представить в виде кривой. На одном конце базовый вариант, который прост в написании, но ограничивает возможности контроля. На противоположном конце кривой будет специально созданный класс для форм со статическим у
До выхода в свет версии Django 1.2 для ORM такая кривая имела аналогичный вид, за одним исключением: существенный скачок в конце. Этот скачок появлялся в связи с тем, что при необходимости создания нестандартного
Старый способ
До выхода версии Django 1.2 при необходимости создать SQL запрос, нужно было написать нечто подобное:from django.db import connection
from library.models import Author
cursor = connection.cursor()
query = "SELECT * FROM library_author"
cursor.execute(query)
results = cursor.fetchall()
authors = []
for result in results:
author = Author(*result)
authors.append(author)Не то чтобы это было совсем ужасно, но здесь мы теряем доступ к функционалу ORM во всём, что не касается создания SQL запросов. В частности, недоступна автоматическая трансформация результатов запроса в экземпляр модели. В меру трудоёмкие способы восстановить утраченную функциональность, конечно, существуют, но фактически это будет изобретением велосипеда.
Новый способ
В версии Django 1.2 для создания прямого SQL запроса нужно написать следующее:from library.models import Author query = "SELECT * FROM library_author" authors = Author.objects.raw(query)
authors здесь будет экземпляром RawQuerySet. RawQuerySet во многом похож на QuerySet. В частности, сходство в том, что это — итерируемый объект, который возвращает экземпляр модели из результатов запроса с каждой итерацией. Отличие его от QuerySet состоит в том, что его нельзя встроить в цепочку. Но здесь это и не важно, поскольку запросы больше не формируются автоматически.
Как и при использовании БД курсора мы можем передать набор параметров запроса, Django заботливо их экранирует.
query = "SELECT * FROM library_author WHERE first_name = %s"
params = ('bob',)
authors = Author.objects.raw(query, params)Так это же здорово! Код SQL защищён от атак, у нас экземпляр модели, который мы хотели, и никакого изобретения велосипеда.
«Но и это ещё не всё!»
Как и большинство инструментов Django, метод raw () оставляет пространство для использования дополнительных функций в неудобных ситуациях или для особо сложных запросов:Независимый порядок полей
Для метода Model.objects.raw () неважно, в каком порядке возвращаются поля по запросу. Единственное, что важно — соответствуют ли имена полей запроса полям в модели.# All of these queries will work the same
Author.objects.raw("SELECT * FROM library_author")
Author.objects.raw("SELECT id, first_name, last_name FROM library_author")
Author.objects.raw("SELECT last_name, id, first_name FROM library_author")Аннотации
Если в ответ на запрос мы получаем поля, которые не существуют в классе модели, они добавляются в качестве аннотаций к тем экземплярам модели, которые возвращает метод RawQueryset. Это с лёгкостью позволяет использовать все преимущества действий или вычислений, выполнение которых более эффективно на уровне базы данных.>>> authors = Author.objects.raw("SELECT *, age(birth_date) as age FROM library_authors")
>>> for author in authors:
... print "%s is %s." % (author.first_name, author.age)
John is 37.
Jane is 42.
...Определения соотношения между полями модели и запроса
Если поЧтобы сопоставить поля запроса с полями модели, нужно просто использовать словарь, содержащий требуемые соответствия, в качестве одного из параметров метода raw (). Соответствия необходимо определить только для тех полей, которые не удалось сопоставить с полями модели.
field_map = {'first': 'first_name', 'last': 'last_name'}
query = 'SELECT id, first_name AS first, last_name as last FROM library_author'
authors = Author.objects.raw(query, translations=field_map) 
