Модуль 16

Class-Based Views (CBV)

Ось твій урок у стилі CS50. Вмикай проектор, поїхали! 🚀


🎓 Тема: Class-Based Views (CBV) — Еволюція твого коду

Привіт, друзі! 👋

Уявіть, що ви працюєте в мерії міста. Ваше завдання — видавати довідки про місце проживання.

Як виглядає ваш день? Приходить людина. Ви берете чистий аркуш паперу. Пишете від руки: "Довідка. Видана такому-то... Адреса така-то... Дата... Підпис..." Приходить наступна. Ви знову берете чистий аркуш. Знову пишете все те саме, змінюючи лише прізвище та вулицю.

До вечора рука відвалюється. 😫

Риторичне питання: Чи не простіше було б мати бланк, де 90% тексту вже надруковано, а вам треба лише вписати ім’я в порожню клітинку?

Власне, у веб-розробці (зокрема в Django): * Function-Based Views (FBV) — це писати все від руки щоразу. * Class-Based Views (CBV) — це той самий бланк.

Сьогодні ми розберемося, як перестати писати один і той самий код знову і знову, і почати жити щасливо.


1. 🔥 Вступ: Проблема «Дня бабака»

Давайте поглянемо на код, який ви, ймовірно, вже писали сотні разів. Уявіть, що ми робимо блог. Нам треба сторінку для відображення списку статей.

Ось типова функція (FBV):

def article_list(request):
    # 1. Дістаємо дані з бази
    articles = Article.objects.all()

    # 2. Готуємо контекст
    context = {'articles': articles}

    # 3. Рендеримо шаблон
    return render(request, 'blog/article_list.html', context)

А тепер уявіть: вам треба зробити список товарів. Список коментарів. Список користувачів. Список замовлень. Ви будете копіювати цей код, змінюючи лише назву моделі та шаблону?

А якщо треба додати пагінацію (сторінки 1, 2, 3...)? Вам доведеться дописувати логіку пагінації у кожну з цих функцій. Це пекло підтримки коду. 🤯

Без CBV не обійтись, коли ваш проєкт переростає стадію "Hello World". Якщо ви хочете масштабуватися і не порушувати принцип DRY (Don't Repeat Yourself) — вам потрібні класи.


2. 🧠 Теоретична база: Що там «під капотом»?

Давайте без академічної нудьги.

Class-Based View (CBV) — це Python-клас, який знає, як обробляти HTTP-запити, тому що він успадковує цю здатність від батьківських класів.

Головна ідея: Спадкування (Inheritance)

Уявіть собі "універсальний автомобіль". У нього є колеса, двигун, кермо. * Якщо вам потрібна вантажівка — ви берете "універсальний автомобіль" і додаєте кузов. * Якщо вам потрібен автобус — ви берете "універсальний автомобіль" і додаєте сидіння.

Вам не треба щоразу винаходити колесо!

У Django (та інших фреймворках) вже написали класи для: 1. Показу простої сторінки (TemplateView). 2. Показу списку (ListView). 3. Показу однієї детальної сторінки (DetailView). 4. Створення/редагування/видалення (CreateView, UpdateView, DeleteView).

⚙️ Механіка: Метод dispatch()

Це — "регулювальник" на перехресті. Коли запит приходить на CBV, найпершим спрацьовує метод .dispatch(). Він дивиться на запит і каже: — "Ага, це GET-запит? Тоді я передаю керування методу .get()". — "Це POST? Тоді йди до методу .post()".

Що треба запам’ятати залізно:

CBV — це не магія. Це просто набір методів, які розбивають обробку запиту на логічні шматки. Ви можете перевизначити (override) будь-який шматок.


3. 🧪 Приклади: Від рутини до елегантності

Приклад 1: Просто показати HTML ("Hello World")

Як було (Function):

def about_page(request):
    return render(request, 'about.html')

Як стало (Class):

from django.views.generic import TemplateView

class AboutView(TemplateView):
    template_name = "about.html"

Зачекайте, скажете ви. Коду стало навіть більше (на 1 рядок). Навіщо це? Терпіння! Сила класів розкривається, коли стає складніше.


Приклад 2: Список статей (Реальна економія)

Ми хочемо показати список статей із бази даних.

Як це робить CBV ListView:

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = "blog/article_list.html"
    context_object_name = "articles"  # Як ми назвемо змінну в HTML

Що тут відбулося? Ми не писали запит Article.objects.all(). Ми не писали return render(...). Клас ListView зробив це за нас. Ми просто налаштували його: "Візьми модель Article, поклади в шаблон такий-то".

Це декларативний стиль: ми кажемо ЩО ми хочемо, а не ЯК це робити.


Приклад 3: Створення статті (Форми без болю)

Пам'ятаєте обробку форм у функціях? if request.method == 'POST': form = ... if form.is_valid(): ... save() ... else: form = ... Жах, правда?

Дивіться сюди:

from django.views.generic import CreateView
from .models import Article

class ArticleCreateView(CreateView):
    model = Article
    fields = ['title', 'content', 'author'] # Які поля показати
    template_name = "blog/article_form.html"
    success_url = "/blog/" # Куди перенаправити після успіху

Все! Цей клас сам: 1. Створить форму. 2. Покаже її при GET-запиті. 3. Перевірить валідацію при POST-запиті. 4. Збереже в базу. 5. Зробить редірект.

5 рядків коду замість 15. 😎


4. 🛠 Практична частина

Час "забруднити руки" кодом. У вас є 6 завдань.

🔹 Завдання 1 (Рефакторинг): У вас є функція contact_us, яка просто рендерить сторінку контактів. Перепишіть її на TemplateView.

🔹 Завдання 2 (Створення списку): Створіть модель Book (назва, автор). Напишіть BookListView, щоб вивести всі книги.

🔹 Завдання 3 (Ламаємо код): В BookListView приберіть рядок context_object_name. Питання: Як тепер звертатися до списку книг у HTML-шаблоні? (Підказка: Django дає стандартне ім'я, спробуйте вгадати або "нагуглити").

🔹 Завдання 4 (Кастомізація): Вам треба вивести не всі книги, а тільки ті, що написані "Тарасом Шевченком". Підказка: Вам треба перевизначити метод get_queryset() у вашому класі.

def get_queryset(self):
    return Book.objects.filter(...) # допишіть тут

🔹 Завдання 5 (Реальний кейс): Створіть BookUpdateView. Це клас для редагування існуючої книги. Який URL-параметр йому обов’язково потрібен, щоб знати, яку саме книгу редагувати? (pk або slug).

🔹 Завдання 6 (А що, якщо...): А що, якщо ми хочемо передати в шаблон не тільки книги, а ще й поточну дату? Дослідження: Знайдіть метод get_context_data і додайте туди змінну current_date.


5. 💡 Мислення як у розробника

Ви тепер знаєте синтаксис. Але як думає профі?

⚠️ Типова помилка новачка: "CBV для всього"

Новачки іноді намагаються запхати складну, нестандартну логіку в стандартні CBV. Якщо ваша логіка вимагає переписати 80% методів класу — зупиніться. Краще напишіть звичайну функцію (FBV). Класи потрібні для типових задач.

🕵️‍♂️ Порада сеньйора: Використовуй шпаргалки

Класи в Django мають складну ієрархію. Ніхто (навіть я!) не пам'ятає напам'ять усі атрибути та методи всіх міксинів. Закладка №1 для вас: ccbv.co.uk (Classy Class-Based Views). Це "рентген" для класів. Заходите туди, тицяєте на ListView і бачите все, з чого він складається.

🧩 Філософія

Коли ви пишете клас, ви не пишете алгоритм. Ви пишете конфігурацію. "Я хочу сторінку, яка поводиться як список, але бере дані ось звідси і фільтрує їх отак".


6. 🧩 Підсумок

Отже, що ми сьогодні отримали?

  1. Ми зрозуміли, що FBV — це ручне управління, а CBV — це автопілот.
  2. Ми навчилися використовувати ListView та CreateView, щоб писати в 3 рази менше коду.
  3. Ми дізналися, що головна сила — у спадкуванні та перевизначенні методів (як get_queryset).

Тепер ви вмієте: Швидко розгортати стандартні CRUD-інтерфейси (Create, Read, Update, Delete) без копіпасту.

📢 Тизер наступного уроку: Окей, ми створили сторінку редагування статті. Але що, якщо її спробує відредагувати анонімний хакер? 😱 На наступному уроці ми поговоримо про Mixins та Декоратори — як захистити наші Класи і пускати туди тільки "своїх".

А поки що — вперед кодити! Practice makes perfect! 💻