При использовании Django ORM есть методы .values() и .only(), которые позволяют получать только определенные поля для оптимизации производительности.
Я подробно разбирал метод .values() в Django QuerySet в предыдущей записи, и, если вы еще не успели ознакомиться, рекомендую вам это сделать. 😊

Чтобы посмотреть предыдущую запись, нажмите! 

Что такое метод .values() в Django QuerySet?

Так как я пишу о .values(), будет полезно также объяснить метод .only(), который работает похожим, но все же отличным образом, чтобы глубже понять Django ORM, и я подготовил этот пост. 🚀

1️⃣ Различия между .only() и .values()

  .only() .values()
Форма возврата Модельный экземпляр (объект модели) Список словарей (dict list)
Цель использования Сохранение объектной модели + загрузка только некоторых полей Получение только определенных полей и возврат их в виде списка словарей
Сохранение функциональности ORM ✅ Сохранена (.save(), .delete() доступны) ❗ Методы модели недоступны (.save(), .delete() ❌)
Дополнительная ленивые загрузки ❗ При доступе к заранее не загруженным полям происходит дополнительный запрос ✅ Дополнительных запросов нет

2️⃣ Способ использования и особенности .only()

.only() - это способ сохранить объект модели, заранее загружая только определенные поля. Однако, если вы получите доступ к полям, не указанным заранее, произойдет ленивая загрузка, что может привести к выполнению дополнительных запросов.

from myapp.models import Post

# QuerySet, загружающий только поля title и author
qs = Post.objects.only("title", "author")

# Проверьте вывод (сам QuerySet готовится к выполнению с задержкой)
print(qs)  # SQL не выполняется

# Доступ к полям
for post in qs:  # ✅ здесь выполняется SQL
    print(post.title)  # ✅ заранее загруженное поле (дополнительных запросов нет)
    print(post.body)   # 🚨 заранее не загруженное поле → дополнительный запрос

🔹 Примечание:
.only() незамедлительно загружает только указанные поля, остальные поля будут загружены с помощью дополнительных запросов по мере необходимости.
Чтобы избежать ненужных запросов, лучше указывать все необходимые поля в .only().

3️⃣ Способ использования и особенности .values()

.values() возвращает только определенные поля в виде списка словарей. Поскольку он возвращает не объект модели, использование функциональности ORM невозможно.
Тем не менее, сам QuerySet сохраняется, поэтому методы такие как .filter(), .annotate() по-прежнему доступны.

# Получите только title и author, возвращая результат в виде словаря
qs = Post.objects.values("title", "author")

# Сам QuerySet подготавливается к выполнению с задержкой (SQL не выполняется)
print(qs)

# Используйте данные словаря (здесь выполняется SQL)
for post in qs:
    print(post["title"])  # ✅ дополнительных запросов нет

🔹 Примечание:
При использовании .values(), поля ForeignKey возвращают по умолчанию только значение ID.
Если вам нужно значение конкретного поля связанной модели, вы должны явно указать его, например, как "author__name".

# Получите конкретное значение поля ForeignKey
qs = Post.objects.values("title", "author__name")

for post in qs:
    print(post["author__name"])  # ✅ получаем поле name объекта author

В приведенном выше примере мы указали поле "author__name", поэтому в результате будет выведено ожидаемое значение author.name, но если бы мы указали "author", то просто была бы выведена ID объекта author.

4️⃣ Когда использовать .only() и .values()?

Цель использования Рекомендуется .only() Рекомендуется .values()
Когда нужно сохранить объект модели
Необходимость использовать функциональность ORM (.save(), .delete(), .update())
Оптимизация производительности (предотвращение загрузки ненужных полей)
Предотвращение дополнительных ленивых загрузок ❌ (возможны дополнительные запросы) ✅ (дополнительных запросов нет)

5️⃣ .values() также имеет ленивую оценку!

.values() может казаться немедленно оцениваемым, но на самом деле QuerySet в Django по умолчанию все имеет ленивую оценку.
То есть, SQL не выполняется, когда вы вызываете .values(), а оценивается, когда вы пытаетесь использовать реальные данные. 🚀

.values() тоже имеет ленивую оценку (SQL не выполняется немедленно)

qs = Post.objects.values("title", "author")  # ❌ SQL не выполняется
print(qs)  # ❌ выводится только информация об объекте QuerySet (SQL не выполняется)

for post in qs:  # ✅ на этом этапе выполняется SQL
    print(post["title"])

✅ Когда происходит оценка QuerySet?

QuerySet, включая .values(), выполняется немедленно (SQL оценивается) в следующих случаях:

  1. Когда происходят итерации в for цикле
  2. Когда вызывается list(qs)
  3. Когда вызывается bool(qs) (в условиях, таких как if qs:)
  4. Когда вызываются такие методы, как .count(), .exists(), .first(), .last()

📌 Заключение

.only()сохранение объектной модели + предварительная загрузка определенных полей
     🔹 доступные функциональности ORM (.save(), .delete())
     🔹 однако при доступе к заранее не загруженным полям могут возникать дополнительные запросы

.values()возвращает список словарей + отсутствуют дополнительные запросы
     🔹 не может использоваться .save(), .delete() из-за отсутствия объектной модели
     🔹 сам QuerySet сохраняется, так что можно использовать .filter(), .annotate()
     🔹 поля ForeignKey по умолчанию возвращают только значение ID → необходимо указывать как author__name

💡 Таким образом, если нужно сохранить объект модели, используйте .only(), а для простого извлечения данных выбирайте .values()! 🚀

🎯 Оптимизация производительности при использовании Django ORM имеет большое значение.

Когда вы сомневаетесь, какую функцию использовать, обратитесь к этому посту, чтобы выбрать оптимальный способ для вашего приложения.
Желаю, чтобы ваши проекты работали более эффективно и быстро! 🔥

Django QuerySet .only() vs .values() flowchart