На предыдущих лекциях мы познакомились с основными типами связей между моделями: 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, чтобы понять, как они влияют на удаление объектов.
Теперь у вас есть инструменты как для организации чистого кода, так и для оптимизации запросов!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ