На попередніх лекціях ми познайомилися з основними типами зв’язків між моделями: OneToOne, ForeignKey і ManyToMany. Ми розібралися, як правильно видаляти об'єкти, щоб потім не довелося кусати лікті, а також дізналися про оптимізацію запитів за допомогою методів select_related() і prefetch_related().
Тепер час розібратися, як налаштувати зворотний доступ до пов'язаних об'єктів за допомогою параметрів related_name (ім'я зворотного зв’язку) та related_query_name (ім'я для зворотних запитів).
У цій лекції ми дізнаємося, як налаштувати related_name для покращення читабельності та зручності роботи із зворотними зв’язками. Також розберемося з поняттям related_query_name та його використанням у фільтраціях і зворотних запитах.
Що таке related_name?
Коли ми створюємо зв'язок між двома моделями, наприклад через ForeignKey, Django автоматично додає "зворотнє" ім'я для доступу до пов'язаних об'єктів. Проте це ім'я може бути не завжди зручним чи інтуїтивно зрозумілим.
Приклад:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
З цим визначенням у вас є два способи доступу до об'єктів:
- Від книги до автора:
book.author - Від автора до всіх його книг:
author.book_set.all()
Зверніть увагу на book_set. Django автоматично створює це ім'я з додаванням _set до імені моделі в нижньому регістрі. Це корисно, але не завжди зручно.
Налаштування related_name
Щоб налаштувати ім'я зворотного зв'язку, ми можемо використовувати параметр related_name у полях ForeignKey або ManyToManyField.
Приклад з related_name:
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
Тепер замість author.book_set.all() можна використовувати більш читабельне author.books.all().
Основні переваги related_name:
- Покращення читабельності коду: більш зрозумілі імена полегшують розуміння коду.
- Уникнення конфліктів: якщо у вас кілька зв'язків між двома моделями, ви можете налаштувати різні
related_nameдля кожного зв'язку.
Приклад з кількома зв'язками:
class Editor(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Editor, on_delete=models.CASCADE, related_name='authored_articles')
reviewed_by = models.ForeignKey(Editor, on_delete=models.SET_NULL, null=True, related_name='reviewed_articles')
Тут у редактора є дві ролі:
- Автор статей (
editor.authored_articles.all()). - Рецензент статей (
editor.reviewed_articles.all()).
Практичний приклад з використанням related_name
Створимо просту бібліотечну систему:
class Library(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='books')
Тепер ми можемо писати:
library = Library.objects.get(name="Міська бібліотека")
books_in_library = library.books.all() # Отримання всіх книг у бібліотеці
Що таке related_query_name?
У попередньому прикладі ми використовували related_name для доступу до пов'язаних об'єктів. Але коли ми фільтруємо об'єкти через пов'язані моделі, Django автоматично призначає ім'я для фільтрації. Це ім'я може бути не дуже описовим.
Приклад фільтрації без related_query_name:
# Обираємо всі бібліотеки, де є книга з назвою "1984"
libraries_with_book = Library.objects.filter(books__title="1984")
Тут books__title — це ім'я автоматично створеного зворотного зв'язку, яке відповідає related_name або _set. Якщо ім'я зв'язку стає складним, ми можемо використовувати related_query_name для покращення фільтрації.
Налаштування related_query_name
Ми можемо задати зрозуміле ім'я для фільтрацій через параметр related_query_name.
Приклад використання related_query_name:
class Book(models.Model):
title = models.CharField(max_length=100)
library = models.ForeignKey(
Library,
on_delete=models.CASCADE,
related_name='books',
related_query_name='book'
)
Тепер фільтрацію можна записати більш явно:
libraries_with_book = Library.objects.filter(book__title="1984")
Різниця між related_name та related_query_name:
related_nameвикористовується для доступу до об'єктів (наприклад,library.books.all()).related_query_nameвикористовується лише у фільтрах (наприклад,Library.objects.filter(book__title="1984")).
Практичний приклад із використанням related_query_name
Додамо модель Author для роботи з книгами та бібліотеками:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(
Author,
on_delete=models.CASCADE,
related_name='books',
related_query_name='book'
)
library = models.ForeignKey(
Library,
on_delete=models.CASCADE,
related_name='books',
related_query_name='library_book'
)
Тепер ми можемо виконувати запити, використовуючи задані related_query_name:
# Фільтр усіх авторів, які написали книгу з назвою "1984"
authors_with_book = Author.objects.filter(book__title="1984")
# Фільтр усіх бібліотек, що містять книгу з назвою "1984"
libraries_with_book = Library.objects.filter(library_book__title="1984")
Корисні поради та типові помилки
Конфлікти імен: якщо у вас багато зв’язків між одними й тими ж моделями, використовуйте унікальні імена для
related_nameтаrelated_query_name. Це позбавить вас від помилок "Ambiguous field name".Не плутайте
related_nameта ім'я моделі: часто початківці розробники плутаютьrelated_nameз ім'ям моделі. Пам’ятайте, щоrelated_name— це просто рядок, який ви задаєте на свій розсуд.Не використовуйте пробіли або спеціальні символи в
related_name: хоча Django дозволяє задавати будь-які рядки, намагайтеся використовувати осмислені ідентифікатори, щоб не ускладнювати підтримку проєкту.Не забувайте про міграції: будь-яка зміна
related_nameабоrelated_query_nameвимагає пересоздання міграцій та застосування їх до бази даних.
Приклади для самостійної практики
Створіть модель
Publisher(Видавець) і зв'яжіть її з моделлюBook. Налаштуйтеrelated_nameякpublished_booksі виконайте запит для отримання всіх книг конкретного видавця.Налаштуйте
related_query_nameдля моделіAuthor, щоб можна було фільтрувати книги за параметромauthor_book. Виконайте запит для отримання всіх авторів, які написали певну книгу.Спробуйте використовувати різні
on_deleteналаштуванняCASCADE,SET_NULLразом зrelated_name, щоб зрозуміти, як вони впливають на видалення об'єктів.
Тепер у вас є інструменти як для організації чистого коду, так і для оптимізації запитів!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ