Ответ
Атрибут related_query_name в полях ForeignKey, OneToOneField и ManyToManyField в Django используется для кастомизации имени, по которому можно фильтровать объекты из связанной модели.
Он решает проблему неоднозначности и делает обратные запросы (reverse lookups) более читаемыми, особенно когда на одну модель есть несколько ссылок.
Ключевое отличие от related_name:
related_name: Имя для доступа к связанным объектам от экземпляра. Например,author.books.all().related_query_name: Имя для использования в фильтрах (filter,exclude) на уровнеQuerySet. Например,Author.objects.filter(book__title=...).
Если related_query_name не задан, Django по умолчанию использует значение related_name.
Пример:
Предположим, у пользователя есть два типа постов: созданные и отредактированные.
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='authored_posts',
related_query_name='authored_post' # Имя для фильтрации
)
last_editor = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='edited_posts',
related_query_name='edited_post' # Имя для фильтрации
)
Теперь мы можем выполнять интуитивно понятные запросы:
# Найти всех пользователей, которые являются авторами постов с заголовком 'Django Intro'
User.objects.filter(authored_post__title='Django Intro')
# Найти всех пользователей, которые редактировали посты с заголовком 'Django Intro'
User.objects.filter(edited_post__title='Django Intro')
Без related_query_name пришлось бы использовать authored_posts__title и edited_posts__title, что может быть менее очевидно.
Ответ 18+ 🔞
А, слушай, вот эта штука related_query_name в Django — она как та самая хитрая жопа, которая всегда прячется за углом, пока ты не наступишь на неё. Вроде бы всё понятно, а потом бац — и ты уже в дебаге сидишь, блядь, три часа, потому что запрос не работает.
Короче, представь себе такую хуйню. У тебя есть модель Post и модель User. И вот ты такой: "О, я умный, я сделаю две связи на одну модель!" И пишешь:
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='authored_posts')
last_editor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='edited_posts')
Всё вроде окей. related_name — это как кличка, по которой из юзера можно до его постов достучаться. user.authored_posts.all() — вот это вот всё.
Но потом ты хочешь отфильтровать юзеров по постам. И пишешь, по привычке:
# Хочу всех юзеров, которые написали пост с заголовком 'Про Django'
User.objects.filter(authored_posts__title='Про Django')
А потом:
# Хочу всех юзеров, которые редактировали пост с заголовком 'Про Django'
User.objects.filter(edited_posts__title='Про Django')
И тут вроде всё логично, ёпта. authored_posts и edited_posts — это же related_name. Но представь, что related_name у тебя какой-нибудь заковыристый, вроде posts_where_this_dude_was_the_author. Ну, для читаемости в коде. И тогда твой фильтр превращается в:
User.objects.filter(posts_where_this_dude_was_the_author__title='Про Django')
Выглядит как бред сумасшедшего, блядь. И вот тут на сцену выходит наш герой — related_query_name. Это как псевдоним специально для фильтров, чтобы не позориться.
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='posts_where_this_dude_was_the_author', # Пусть будет так, для прикола
related_query_name='author_of' # А вот это — для фильтров!
)
last_editor = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='posts_where_this_dude_messed_up',
related_query_name='editor_of'
)
И теперь, в рот меня чих-пых, магия:
# Ищем юзеров, которые написали пост про Django
User.objects.filter(author_of__title='Про Django')
# Ищем юзеров, которые его редактировали
User.objects.filter(editor_of__title='Про Django')
Красота же, блядь? Чисто, понятно, без этих многоэтажных posts_where_this_dude_was_the_author.
А если не задать related_query_name? Да похуй, Django возьмёт значение из related_name и будет использовать его. Так что если тебя устраивает твой posts_where_this_dude_messed_up в фильтрах — можешь не париться.
Короче, суть в чём: related_name — это как обращаться от юзера к его постам. А related_query_name — это как обращаться к юзеру из запроса, когда фильтруешь по связанным постам. Чтобы не было путаницы, когда связей на одну модель — овердохуища.
Запомни, и всё у тебя будет пиздато. А не запомнишь — будешь как Герасим, только "Му-му" мычать, глядя на ошибку FieldError.