JavaRush /Курси /Модуль 3: Django /Робота з related_name та related_query_name

Робота з related_name та related_query_name

Модуль 3: Django
Рівень 9 , Лекція 4
Відкрита

На попередніх лекціях ми познайомилися з основними типами зв’язків між моделями: 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:

  1. Покращення читабельності коду: більш зрозумілі імена полегшують розуміння коду.
  2. Уникнення конфліктів: якщо у вас кілька зв'язків між двома моделями, ви можете налаштувати різні 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")

Корисні поради та типові помилки

  1. Конфлікти імен: якщо у вас багато зв’язків між одними й тими ж моделями, використовуйте унікальні імена для related_name та related_query_name. Це позбавить вас від помилок "Ambiguous field name".

  2. Не плутайте related_name та ім'я моделі: часто початківці розробники плутають related_name з ім'ям моделі. Пам’ятайте, що related_name — це просто рядок, який ви задаєте на свій розсуд.

  3. Не використовуйте пробіли або спеціальні символи в related_name: хоча Django дозволяє задавати будь-які рядки, намагайтеся використовувати осмислені ідентифікатори, щоб не ускладнювати підтримку проєкту.

  4. Не забувайте про міграції: будь-яка зміна related_name або related_query_name вимагає пересоздання міграцій та застосування їх до бази даних.

Приклади для самостійної практики

  1. Створіть модель Publisher (Видавець) і зв'яжіть її з моделлю Book. Налаштуйте related_name як published_books і виконайте запит для отримання всіх книг конкретного видавця.

  2. Налаштуйте related_query_name для моделі Author, щоб можна було фільтрувати книги за параметром author_book. Виконайте запит для отримання всіх авторів, які написали певну книгу.

  3. Спробуйте використовувати різні on_delete налаштування CASCADE, SET_NULL разом з related_name, щоб зрозуміти, як вони впливають на видалення об'єктів.

Тепер у вас є інструменти як для організації чистого коду, так і для оптимізації запитів!

3
Опитування
Зв’язки між моделями, рівень 9, лекція 4
Недоступний
Зв’язки між моделями
Зв’язки між моделями
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ