Ось готовий урок, створений за твоїм майстер-промптом. Я обрав контекст Django ORM, оскільки термін QuerySet є візитною карткою саме цього фреймворку.
🎓 CS50-style: QuerySet та Query API (Django ORM)
Привіт, друзі! Радий бачити вас на занятті.
Сьогодні ми відкриваємо «чорну скриньку» нашого додатку. Ми вже вміємо створювати моделі (таблиці в базі даних), але який з них сенс, якщо ми не вміємо діставати звідти інформацію?
Уявіть, що ви — власник найбільшої бібліотеки у світі. У вас мільйони книг. І ось приходить відвідувач і каже: "Мені потрібна синя книга". Якби ви були комп'ютером без правильних інструментів, ви б пішли до першої полиці, взяли книгу, перевірили колір, поклали назад. Взяли другу... І так мільйон разів. Це довго. Це неефективно. Це, чесно кажучи, безглуздо.
Сьогодні ми навчимося бути розумним бібліотекарем. Ми розберемо QuerySet — інструмент, який дозволяє знаходити голку в копиці сіна за мілісекунди.
Готові? Поїхали! 🚀
1. 🔥 Вступ: проблема та мотивація
Уявіть, що ви розробляєте інтернет-магазин. У вас у базі даних 100 000 товарів. Вам потрібно показати користувачеві: "Всі смартфони, дешевші за 20 000 грн, які є в наявності, відсортовані за рейтингом".
Риторичне запитання: Як би ви це робили без спеціальних інструментів? Писали б "сирий" SQL-запит?
SELECT * FROM products WHERE category_id = 5 AND price < 20000 AND stock > 0 ORDER BY rating DESC;
Виглядає ніби ок? А якщо я скажу, що назва таблиці змінилася? Або ви випадково допустили помилку в синтаксисі й «поклали» базу? Або, що найгірше, користувач через поле пошуку ввів шкідливий код (SQL Injection) і вкрав дані всіх ваших клієнтів?
Навіщо нам QuerySet? QuerySet (КверіСет) — це ваш адвокат і перекладач. Ви кажете йому мовою Python: "Дай мені смартфони", а він сам безпечно і максимально швидко пояснює це базі даних її мовою.
Без цього ви не зможете побудувати жоден динамічний сайт. Це міст між вашим кодом і даними.
2. 🧠 Теоретична база (без нудьги)
Давайте розберемося, що це за звір.
Що таке QuerySet?
Це набір (список) об'єктів із вашої бази даних. Але це не просто список, як list у Python. Це розумний список.
Головний секрет: Лінивість (Laziness) 🦥
Це найважливіше, що треба зрозуміти сьогодні. QuerySet — лінивий.
Уявіть, що ви прийшли в ресторан і читаєте меню. 1. Ви дивитесь на "Борщ". 2. Ви дивитесь на "Вареники". 3. Ви дивитесь на "Узвар".
Чи почав кухар готувати борщ, поки ви просто читаєте рядок у меню? Ні. Кухар почне готувати тільки тоді, коли ви скажете офіціанту: "Неси!".
Так само працює QuerySet:
* Ви можете створити запит: users = User.objects.filter(age=25)
* Ви можете додати умову: users = users.exclude(is_active=False)
* Ви можете відсортувати: users = users.order_by('name')
До цього моменту база даних навіть не знає про ваше існування. Жодного запиту не було відправлено.
Запит полетить у базу тільки тоді, коли ви спробуєте використати дані: вивести їх на екран, запустити цикл for або взяти перший елемент.
Як це працює "під капотом"?
Ви будуєте конструктор з Lego. Кожен метод (filter, all, exclude) додає кубик до інструкції. Коли ви нарешті просите дані, Django бере цю інструкцію, конвертує її в ідеальний SQL і надсилає в базу даних.
🔑 Ключові методи (запам'ятати):
all()— дай мені все.filter(умова)— дай тільки те, що підходить (як сито).exclude(умова)— дай все, КРІМ цього.get(умова)— дай мені рівно один об'єкт (обережно з ним!).
3. 🧪 Приклади (від простого до реального)
Припустимо, у нас є модель Article (Стаття) з полями: title (назва), views (перегляди), is_published (чи опубліковано).
Приклад 1: "Дай усе"
# Запит
articles = Article.objects.all()
# Тут SQL ще не виконався! 🦥
# А ось тут виконується:
print(articles)
Що ми отримаємо?
QuerySet, який виглядає як список усіх статей: <QuerySet [<Article: Hello>, <Article: World>]>.
Приклад 2: Фільтрація (Реальний кейс)
Нам треба показати на головній сторінці тільки опубліковані статті.
Питання до вас: Що буде, якщо ми не використаємо фільтр, а просто переберемо всі статті циклом if у Python?
Відповідь: Ми завантажимо з бази тисячі чернеток, заб'ємо пам'ять сервера, і тільки потім Python їх відкине. Це повільно.
Робіть це на рівні бази:
# Правильно:
published_articles = Article.objects.filter(is_published=True)
Приклад 3: Ланцюжки (Chaining) ⛓️
Це найкрутіша фішка. Ми можемо нанизувати методи один на одного.
Задача: Знайти опубліковані статті, у яких понад 100 переглядів, і відсортувати їх від найпопулярніших.
top_content = Article.objects.filter(is_published=True).filter(views__gt=100).order_by('-views')
(Примітка: views__gt означає "Greater Than" — більше ніж).
Пояснення: Ми взяли весь список -> відсіяли неопубліковані -> відсіяли непопулярні -> посортували. І все це перетвориться в один ефективний SQL-запит.
4. 🛠 Практична частина
Уяви, що ти працюєш з базою даних студентів: Student (поля: name, age, gpa (середній бал), faculty).
Твої завдання:
- 🔹 Розігрів: Напиши запит, щоб отримати всіх студентів факультету "Computer Science".
- 🔹 Ускладнюємо: Отримай студентів, яким 20 років І в яких середній бал (gpa) вище 3.5.
- 🔹 Виключення: Знайди всіх студентів, окрім тих, хто вчиться на "History".
- 🔹 Ланцюжок: Знайди топ-5 наймолодших студентів факультету "Math" (підказка: використовуй
order_byта зрізи, як у списку[:5]). - 🔹 Виправ помилку:
python # Задача: знайти студента з ім'ям "Ivan" student = Student.objects.filter(name="Ivan") print(student.age) # ПОМИЛКА! Чому?Як виправити код, щоб отримати доступ до поляage? - 🔹 Міні-кейс: Тобі дзвонить декан. Треба терміново список студентів на відрахування (GPA менше 2.0). Але давай їм останній шанс — не включай у цей список першокурсників (age < 18). Напиши цей запит.
5. 💡 Мислення як у розробника
Як відрізнити новачка від профі, дивлячись на код QuerySet?
🚫 Типова помилка новачка: N+1 проблема
Це класика. Дивіться:
# Погано 😱
books = Book.objects.all() # 1 запит
for book in books:
print(book.author.name) # +1 запит ДЛЯ КОЖНОЇ книги!
Якщо книг 1000, ви зробите 1001 запит до бази. Ваша база «впаде», адмін буде злий.
Як думає профі: "Мені треба витягнути дані одним махом".
(Рішення: select_related — але це тема для окремого уроку, просто знайте, що така проблема існує).
🚫 Помилка: Python vs DB
Новачок: Витягує Book.objects.all(), перетворює в список Python і фільтрує через if.
Профі: Максимально використовує filter() та exclude(). База даних написана на C++, вона оптимізована роками. Вона фільтрує швидше, ніж ваш Python-код. Довіряйте базі.
💡 Порада:
Завжди запитуйте себе: "Чи можу я відфільтрувати це ще до того, як дані потраплять у Python?" Якщо так — робіть це в QuerySet.
6. 🧩 Підсумок
Фух! Давайте видихнемо. Що ми сьогодні зрозуміли?
- QuerySet — це не дані, це інструкція. Він лінивий 🦥.
- Ми використовуємо методи
all,filter,exclude, щоб будувати складні запити простими словами. - Ми не пишемо SQL вручну (здебільшого), ми дозволяємо Django робити цю брудну роботу за нас.
- Чим більше роботи зробить база даних (фільтрація, сортування), тим швидше працює наш сайт.
Тепер ви вмієте: Знаходити потрібну інформацію в базі даних, не перебираючи кожен запис вручну. Ви — той самий розумний бібліотекар!
🕵️ Що далі? Зараз ми працювали з однією таблицею. Але світ складний. Студенти мають курси, автори мають книги. На наступному уроці ми дізнаємось, як пов'язувати таблиці між собою і робити магію з Relationships (зв'язками).
А поки — вперед до практики! Код сам себе не напише! 😉👨💻