Зачем нужен related_name в Django?
В мире Django, ORM (Object-Relational Mapping) играет важную роль в взаимодействии с базой данных. Однако, иногда возникают ситуации, когда нужно обращаться к связанным моделям. Вот здесь на помощь приходит related_name .
Допустим, у нас есть две модели: Book и Author . Одна книга может иметь много авторов, и один автор может написать много книг. В таком случае, мы скажем, что у модели Book и Author есть отношение «многие ко многим» или ManyToMany .
from django.db import models class Book(models.Model): title = models.CharField(max_length=200) authors = models.ManyToManyField('Author') class Author(models.Model): name = models.CharField(max_length=100)
Когда мы хотим получить все книги определенного автора, мы можем просто использовать author.book_set.all() . Здесь book_set — это автоматически создаваемое Django имя для обратной связи от модели Author к Book .
Но что, если мы хотим использовать более осмысленное имя вместо book_set ? Тут на помощь приходит related_name .
from django.db import models class Book(models.Model): title = models.CharField(max_length=200) authors = models.ManyToManyField('Author', related_name='books') class Author(models.Model): name = models.CharField(max_length=100)
Теперь, вместо book_set , можно использовать books для обращения ко всем книгам автора. Таким образом, related_name используется для создания более осмысленного и удобного имени для обратной связи между моделями.
В заключение хотелось бы подчеркнуть, что использование related_name повышает читаемость и понимание кода, что особенно важно в больших и сложных проектах.
Использование related_name во view-функции
Оно не должно совпадать с другими related_name для указанной модели.
В примере из вашего кода, что я привел выше, для модели User доступно обращение к связанным объектам модели Post по имени posts . Т.о. Больше нигде вы не сможете указать related_name=’posts’ если это связь с моделью User .
Если обращение из другой модели не требуется, можно указать related_name=’+’
Зачем
related_name позволяет обращаться к из связанных объектов к тем, от которых эта связь была создана.
class Post(models.Model): text = models.TextField() pub_date = models.DateTimeField(auto_now_add=True) author = models.ForeignKey( User, on_delete=models.CASCADE, related_name='posts' ) group = models.ForeignKey(Group, on_delete=models.CASCADE, max_length=200, blank=True, null=True, related_name='group')
related_name дожно быть posts , чтобы из модели Group , а вернее из объектов этой модели, можно было достать все связанные объекты Post по логичному наименованию.
В общем должно быть так
class Post(models.Model): text = models.TextField() pub_date = models.DateTimeField(auto_now_add=True) author = models.ForeignKey( User, on_delete=models.CASCADE, related_name='posts' ) group = models.ForeignKey(Group, on_delete=models.CASCADE, max_length=200, blank=True, null=True, related_name='posts')
И тогда для группы можно будет получить все посты следущим способом
posts = group.posts.all()
Ревью
Что касается ревью, то на основе описанного выше должно получиться так
def group_posts(request, slug): group = get_object_or_404(Group, slug=slug) posts = group.posts.order_by('-pub_date')[:10] context = < 'group': group, 'posts': posts, >return render(request, 'posts/group_list.html', context)
Надеюсь объяснил доступно
Как проверить related_name
Шаг первый — находим в коде модель данных с related_name . Для примера возьмём код онлайн-библиотеки:
class Book(models.Model): author = models.ForeignKey( User, verbose_name='автор', related_name='authors' )
У нас есть книги и их авторы. Поле related_name позволяет развернуть это отношение и для каждого автора получить список его книг.
Теперь открываем Django shell и пишем запрос с related_name . Выберем любого пользователя из БД и узнаем какие книги он написал:
$ python manage.py shell >>> from users.models import User >>> user = User.objects.first() >>> user.authors.all()
Внимательно перечитываем свой код и видим: хотели книги — books , а получили неких авторов authors . Что за дичь здесь происходит ?!
Исправляем неудачное название related_name на логичное и понятное:
user.author_books.all()
Осторожнее с пользователями!
В примере выше вместо author_books можно написать books . Так получится короче и смысл не потеряется. Так может показаться на первый взгляд, но это не так. Очень часто в модели данных содержится сразу несколько ссылок на учётки пользователей. У книги помимо авторов могут быть рецензенты, читатели, фоловеры и много кого ещё. Всё это ссылки на пользователей и у каждой связи есть свой собственный related_name . Если назвать related_name без уточнений как books , то в связях легко будет запутаться, не ясно о чём речь в запросе об авторстве или о лайках.
Если в модели данных одна связь с пользователями, то это ещё не значит, что в будущем их не станет больше. Функционал сайта постоянно расширяется и лишь одно остаётся в мире неизменным — “требования меняются всегда!”
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.
Python-сообщество
- Начало
- » Django
- » related_name зачем оно?
#1 Сен. 7, 2008 02:00:08
romankrv От: Зарегистрирован: 2008-05-23 Сообщения: 513 Репутация: 0 Профиль Отправить e-mail
related_name зачем оно?
You can override the FOO_set name by setting the related_name parameter in the ForeignKey() definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, related_name=’entries’), the above example code would look like this:
Понятно что этим мы перекрываем название менеджера FOO_set который возвращает все экземпляры молели по схеме бэкворд (foirgin key) на свой.
Вопрос для каких практических целей это используется так как это вроде вносит лишние имена при работе. Что в этом есть удобного ?
#2 Сен. 7, 2008 08:43:40
Lolka От: Зарегистрирован: 2007-09-29 Сообщения: 128 Репутация: 0 Профиль Отправить e-mail
related_name зачем оно?
Пример – модель трижды завешена на User по разным причинам :
model Labyrinth(models.Model):
designer = models.ForeignKey(User, null=False, related_name='designer') # дизайнер
curator = models.ForeignKey(User, null=True, related_name='curator') # куратор
manager = models.ForeignKey(User, null=True, related_name='manager') # менеджер
Если не указать related_name, то получится такое:
Error: One or more models did not validate:
labyrinths.labyrinth: Accessor for field 'designer' clashes with related field 'User.labyrinth_set'. Add a related_name argument to the definition for 'designer'.
labyrinths.labyrinth: Accessor for field 'curator' clashes with related field 'User.labyrinth_set'. Add a related_name argument to the definition for 'curator'.
.