У цій лекції ми зануримося в можливості роботи з даними та більш детально розглянемо методи all(), filter() та get() у Django ORM.
Навіщо нам all(), filter() і get()?
Обробка даних у додатку потребує функціональних і зручних інструментів для отримання інформації. Методи all(), filter() і get() є основоположними для взаємодії з базою даних через ORM.
Може виникнути закономірне питання: а чому б нам просто не писати сирі SQL-запити? Це можливо, але:
- Їх складно підтримувати: уявіть, що бізнес-логіка змінюється. Що тоді? Ручний рефакторинг SQL-запитів!
- Це ненадійно: за безпеку має відповідати ORM, а не доводити себе до нервового тику від SQL-ін'єкцій.
- Та ще й нудно! Django ORM дає вам Python, а не SQL. Навіщо ускладнювати собі життя?
Метод all()
Метод all() використовується для отримання всіх записів з таблиці, пов'язаної з моделлю.
Приклад використання
# Модель для прикладу
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.CharField(max_length=100)
published_year = models.IntegerField()
Отримаємо всі книги з бази даних:
# Отримання всіх записів
books = Book.objects.all()
# Перегляд результату
for book in books:
print(f"{book.title} — {book.author}, {book.published_year}")
Особливості
all()повертає QuerySet. Це означає:- Він лінивий (лінується виконувати запити, поки ти до нього не звернешся).
- Можна використовувати ланцюжки методів (наприклад, комбінувати з
filter()чиorder_by()).
- Якщо в таблиці немає даних, повернеться порожній QuerySet, а не
None.
Приклад ланцюжка методів
Додамо сортування одразу після методу all():
# Отримання всіх книг за спаданням року публікації
books = Book.objects.all().order_by('-published_year')
for book in books:
print(f"{book.title} — {book.published_year}")
Метод filter()
filter() використовується для отримання записів, що відповідають одній або кільком умовам.
Приклади використання
- Фільтрація за одним полем:
# Знайти всі книги автора "Дмитро Глуховський" books = Book.objects.filter(author="Дмитро Глуховський") for book in books: print(book.title)
- Фільтрація за кількома умовами:
# Знайти книги автора "Дмитро Глуховський", опубліковані після 2005 року books = Book.objects.filter(author="Дмитро Глуховський", published_year__gt=2005) for book in books: print(book.title)
- Використання складних умов з
Q(з попередньої лекції ти напевно пам'ятаєшQ):from django.db.models import Q # Знайти книги, опубліковані до 2000 року або написані автором "Лев Толстой" books = Book.objects.filter(Q(published_year__lt=2000) | Q(author="Лев Толстой")) for book in books: print(book.title)
Особливості
filter()повертає QuerySet (аналогічноall()).- Якщо в таблиці немає записів, що відповідають умовам, повернеться порожній QuerySet.
Метод get()
get() витягує рівно один запис, який відповідає заданим умовам.
Приклад використання
- Отримання запису за ID:
# Знайти книгу з ID = 5 book = Book.objects.get(id=5) print(book.title)
- Фільтрація за полями моделі:
# Знайти книгу з назвою "1984" і автором "Джордж Орвелл" book = Book.objects.get(title="1984", author="Джордж Орвелл") print(f"{book.title} — {book.author}")
Важлива різниця: get() vs filter()
get()повертає один об'єкт моделі (а не QuerySet).- Якщо запис не знайдено, кидається виняток
DoesNotExist. Будь уважним — краще обертати вtry...except:try: book = Book.objects.get(id=9999) # ID, якого немає except Book.DoesNotExist: print("Такої книги немає!") - Якщо умовам відповідає більше одного запису, ти отримаєш
MultipleObjectsReturned. Ось тобі ще одна причина не використовуватиget()без впевненості!
Коли використовувати get()?
Використовуй його тільки тоді, коли впевнений, що запит поверне рівно один запис. В інших випадках filter() безпечніше.
Відмінності між all(), filter() та get()
| Метод | Повертає | Коли використовувати |
|---|---|---|
all() |
QuerySet, всі записи | Коли потрібно отримати повний список даних |
filter() |
QuerySet, записи за умовою | Для вибірки записів, що відповідають одній або декільком умовам |
get() |
Один об'єкт моделі | Для отримання одного конкретного об'єкта, якщо впевнені, що він існує |
Кращі практики та типові помилки
Ліниве завантаження:
методиall()таfilter()повертають лінивий QuerySet. Якщо ти випадково не "матеріалізував" QuerySet (наприклад, перебрав його в циклі), SQL-запит просто не виконається. Щоб перевірити запит, можна скористатися методом.query:books = Book.objects.filter(author="Дмитро Глуховський") print(books.query) # Друкує SQL-запитВикористання
get()на невідповідний запит: ніколи не використовуйget(), якщо запит може повернути більше одного запису. Наприклад:# Це викличе MultipleObjectsReturned, якщо є дві однакові книги book = Book.objects.get(author="Лев Толстой")Обробка порожніх результатів: завжди перевіряй результат виклику
filter()абоall()на наявність записів перед виконанням операцій:books = Book.objects.filter(author="Невідомий автор") if not books.exists(): print("Книги не знайдені!")
Застосування на практиці
Давайте додамо в наш додаток просту функціональність. Уявіть, що нам потрібно реалізувати пошук книг для бібліотеки.
Крок 1: Створюємо представлення
# views.py
from django.shortcuts import render
from .models import Book
def search_books(request):
query = request.GET.get('q', '') # Отримати пошуковий запит від користувача
books = Book.objects.filter(title__icontains=query) # Фільтр за заголовком
return render(request, 'search_results.html', {'books': books, 'query': query})
Крок 2: Додаємо URL-маршрут
# urls.py
from django.urls import path
from .views import search_books
urlpatterns = [
path('search/', search_books, name='search_books'),
]
Крок 3: Створюємо простий шаблон
<!-- templates/search_results.html -->
<form method="get" action="{% url 'search_books' %}">
<input type="text" name="q" placeholder="Шукати...">
<button type="submit">Пошук</button>
</form>
<h2>Результати пошуку для "{{ query }}"</h2>
<ul>
{% for book in books %}
<li>{{ book.title }} — {{ book.author }}</li>
{% empty %}
<p>Нічого не знайдено</p>
{% endfor %}
</ul>
Тепер наша бібліотека може шукати книги за назвою з використанням filter()!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ