Сьогодні на порядку денному — F-об'єкти. Вони дозволяють звертатися до полів моделі "як є" на рівні бази даних. Ми навчимося використовувати їх для створення ефективних запитів, щоб не витягувати дані в Python тільки для простих операцій.
Що таке F-об'єкти?
F-об'єкти — це інструмент із модуля django.db.models, який надає можливість напряму працювати з полями моделі в рамках SQL-запитів. Це зручно для виконання операцій між полями одного або кількох записів без необхідності витягувати дані в Python-код, обробляти їх, а потім відправляти зміни назад у базу.
Тобто, F-об'єкти допомагають перенести логіку обчислень із Python у саму базу даних, зберігаючи запит атомарним (хвала ACID-парадигмі!). Це не лише робить код чистішим, але й значно підвищує продуктивність застосунку.
Для чого потрібні F-об'єкти? Уявіть, що ми створюємо інтернет-магазин. Для оновлення інформації, наприклад, про знижки чи залишки на складі, доводиться витягувати поточні дані товару, змінювати їх у коді й записувати назад. Якщо б над одним і тим самим товаром працювали кілька користувачів одночасно, то можна було б легко "перезаписати" зміни. Це небезпечно і недобре.
F-об'єкти вирішують цю проблему, дозволяючи змінювати дані прямо на рівні бази даних. Замість "витягни-зміни-збережи" ви просто говорите запиту "додай до цього поля 5". І база сама розбереться з атомарністю та цілісністю даних.
Приклад використання F-об'єктів
Для початку створимо модель товарів для нашого інтернет-магазину:
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField(default=0) # кількість на складі
def __str__(self):
return self.name
Припустимо, у нас є записи в базі даних для товарів:
| ID | Назва | Ціна | Залишок |
|---|---|---|---|
| 1 | Крута клавіатура | 4000 | 10 |
| 2 | Геймерська миша | 2000 | 5 |
| 3 | Монітор 4К | 20000 | 3 |
Приклад 1: зменшення залишку на складі
Припустимо, клієнт купив 1 одиницю товару. Ми хочемо зменшити кількість stock на 1. З Python-підходом це виглядало б так:
from myapp.models import Product
product = Product.objects.get(id=1)
product.stock -= 1 # Зменшуємо залишок
product.save()
З використанням F-об'єктів ми можемо написати більш елегантний та безпечний запит:
from django.db.models import F
from myapp.models import Product
Product.objects.filter(id=1).update(stock=F('stock') - 1)
Що тут відбувається?
- Ми використовуємо метод
update()для масового оновлення записів. - Замість конкретного значення для
stockвикористовуємо F-об'єкт, який вказує: "зменши поточне значення поляstockна 1".
Приклад 2: підвищення ціни товарів
Припустимо, ми вирішили підвищити ціну на товари через інфляцію (життя жорстке). Наприклад, збільшити ціну на 10%:
Product.objects.all().update(price=F('price') * 1.1)
База даних автоматично помножить значення поля price на 1.1 для кожного продукту.
І наш оновлений стан:
| ID | Назва | Ціна | Залишок |
|---|---|---|---|
| 1 | Крута клавіатура | 4400 | 10 |
| 2 | Геймерська миша | 2200 | 5 |
| 3 | Монітор 4К | 22000 | 3 |
Особливості застосування F-об'єктів
Операції між полями
F-об'єкти також дозволяють виконувати операції між різними полями однієї моделі. Наприклад, якщо ми хочемо забезпечити знижку тільки для тих товарів, у яких залишок більше 5 штук, і ціна вище 5000:
Product.objects.filter(stock__gt=5, price__gt=5000).update(price=F('price') - F('price') * 0.2)
У цьому запиті:
- Ми фільтруємо товари, де
stock > 5іprice > 5000. - Зменшуємо ціну на 20% тільки для відповідних товарів.
Складні обчислення
F-об'єкти підтримують складні обчислення. Наприклад, ми хочемо встановити залишок на складі таким чином, щоб він був рівний половині поточного:
Product.objects.update(stock=F('stock') // 2)
Тут // — оператор цілочисельного ділення. У результаті кількість товарів у наявності скоротиться рівно вдвічі.
Типові помилки при використанні F-об'єктів
- Спроба оновити значення після його отримання
Якщо ви намагаєтесь виконати щось на кшталт:
product = Product.objects.get(id=1)
product.stock = F('stock') - 1
product.save()
Це не спрацює, тому що F('stock') не може бути використаний для обчислень у Python; він потрібен лише для SQL-запитів. Замість цього використовуйте метод update().
- Невідповідність типів даних
Якщо ви спробуєте виконати операцію з несумісними полями (наприклад, скласти рядок і число), Django видасть помилку:
Product.objects.update(stock=F('name') + 1) # викличе помилку
База даних не зможе обробити такий вираз, оскільки типи даних name (рядок) і 1 (число) несумісні.
Практичне завдання
Уявіть, що ви розробляєте застосунок для управління складом. Спробуйте впоратися з наступними задачами:
- Ви створюєте акцію: збільшуєте залишок на складі (поле
stock) товарів, у яких залишок менше 10, на 5 одиниць. - Збільшіть ціну всіх товарів на 15%, які коштують менше 5000.
- Встановіть залишок на складі кожного товару рівним поточній ціні, поділеній на 100 (цілочисельне ділення).
Напишіть код для виконання цих дій у вашому проєкті.
Де це корисно?
У реальних проєктах F-об'єкти допомагають:
- Оновлювати дані без конфліктів у конкурентних середовищах.
- Зменшувати кількість запитів до бази і навантаження на сервер.
- Прискорювати виконання задач, переносячи обчислення з Python у SQL.
Для управління складом, обробки акцій чи масового оновлення даних F-об'єкти стають справжніми рятівниками розробника!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ