Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
related_name в Django: обратные связи между моделями
related_name — это параметр для ForeignKey и ManyToManyField, который определяет имя обратной связи (reverse relation). Он позволяет получать доступ к связанным объектам с противоположной стороны отношения.
Без related_name: стандартное имя
Если не указать related_name, Django сам создаёт имя автоматически (модель_lowercase + "_set"):
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE) # Без related_name
# Django создаст автоматическое имя: book_set
author = Author.objects.get(id=1)
books = author.book_set.all() # Все книги автора (автоматическое имя)
Это работает, но неудобно и непонятно. Вместо book_set лучше написать что-то осмысленное:
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
Author,
on_delete=models.CASCADE,
related_name='books' # ← Теперь явное имя
)
# Теперь
author = Author.objects.get(id=1)
books = author.books.all() # Намного понятнее!
Как это работает
model Book:
author = ForeignKey(Author, related_name='books')
↑
Это имя создаёт обратную связь
Директ связь: book.author ← получить автора книги
Обратная связь: author.books.all() ← получить все книги автора
Основные примеры
Пример 1: Отношение один-ко-многим (1:M)
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
publisher = models.ForeignKey(
Publisher,
on_delete=models.CASCADE,
related_name='books' # Обратная связь
)
# Использование
publisher = Publisher.objects.get(id=1)
# Прямая связь
book = Book.objects.get(id=1)
print(book.publisher) # <Publisher: Random House>
# Обратная связь
all_books = publisher.books.all() # Все книги издателя
count = publisher.books.count() # Количество книг
first_book = publisher.books.first() # Первая книга
Пример 2: Отношение многие-ко-многим (M:M)
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
authors = models.ManyToManyField(
Author,
related_name='authored_books' # Обратная связь
)
# Использование
author = Author.objects.get(id=1)
# Прямая связь
book = Book.objects.get(id=1)
book_authors = book.authors.all() # Все авторы этой книги
# Обратная связь
author_books = author.authored_books.all() # Все книги этого автора
author_books_count = author.authored_books.count() # Сколько книг написал
Пример 3: Самоссылающаяся модель
class Employee(models.Model):
name = models.CharField(max_length=100)
manager = models.ForeignKey(
'self', # Ссылка на саму себя
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='subordinates' # Обратная связь
)
# Использование
manager = Employee.objects.get(id=1)
team = manager.subordinates.all() # Все сотрудники, которыми управляет менеджер
employee = Employee.objects.get(id=5)
if employee.manager:
print(f"Boss: {employee.manager.name}")
Именование related_name
Хорошие примеры
class Post(models.Model):
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='posts' # Понятно: posts юзера
)
class Comment(models.Model):
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name='comments' # Понятно: comments поста
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='authored_comments' # Различаем от posts
)
user = User.objects.get(id=1)
user_posts = user.posts.all() # Посты пользователя
user_comments = user.authored_comments.all() # Комментарии пользователя
Плохие примеры
# ❌ Непонятные имена
class Book(models.Model):
publisher = models.ForeignKey(
Publisher,
on_delete=models.CASCADE,
related_name='x' # Что это? "x"?
)
# ❌ Слишком длинные
class Comment(models.Model):
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name='comments_made_on_this_post_by_users' # Слишком!)
)
# ❌ Автоматическое имя (без related_name)
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE) # book_set?
Практические примеры
Пример 1: Блог
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Category(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='posts' # user.posts.all()
)
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='posts' # category.posts.all()
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Comment(models.Model):
text = models.TextField()
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name='comments' # post.comments.all()
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='comments' # user.comments.all()
)
created_at = models.DateTimeField(auto_now_add=True)
# Использование
user = User.objects.get(id=1)
user_posts = user.posts.all() # Все посты пользователя
user_comments = user.comments.all() # Все комментарии
post = Post.objects.get(id=1)
post_comments = post.comments.all() # Все комментарии поста
comment_count = post.comments.count() # Количество комментариев
category = Category.objects.get(id=1)
category_posts = category.posts.all() # Все посты в категории
Пример 2: E-commerce
class Customer(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
class Order(models.Model):
customer = models.ForeignKey(
Customer,
on_delete=models.CASCADE,
related_name='orders' # customer.orders.all()
)
created_at = models.DateTimeField(auto_now_add=True)
total = models.DecimalField(max_digits=10, decimal_places=2)
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
class OrderItem(models.Model):
order = models.ForeignKey(
Order,
on_delete=models.CASCADE,
related_name='items' # order.items.all()
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
related_name='order_items' # product.order_items.all()
)
quantity = models.PositiveIntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
# Использование
customer = Customer.objects.get(id=1)
all_orders = customer.orders.all() # Все заказы клиента
total_spent = sum(o.total for o in customer.orders.all())
order = Order.objects.get(id=1)
order_items = order.items.all() # Все товары в заказе
product = Product.objects.get(id=1)
where_ordered = product.order_items.all() # Где этот товар был заказан
QuerySet методы с related_name
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
publisher = models.ForeignKey(
Publisher,
on_delete=models.CASCADE,
related_name='books'
)
# Filter на обратной связи
publisher = Publisher.objects.get(id=1)
published_books = publisher.books.filter(published=True)
# Count
book_count = publisher.books.count()
# Exists
has_books = publisher.books.exists()
# First/Last
first_book = publisher.books.first()
last_book = publisher.books.last()
# Aggregate
from django.db.models import Sum, Avg
total_sales = publisher.books.aggregate(total=Sum('sales'))['total']
avg_price = publisher.books.aggregate(avg=Avg('price'))['avg']
# Delete
publisher.books.all().delete() # Удалит все книги издателя
Обратная фильтрация (Reverse filtering)
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
authors = models.ManyToManyField(Author, related_name='books')
# Найти всех авторов, у которых есть хотя бы одна опубликованная книга
from django.db.models import Q
published_authors = Author.objects.filter(
books__published=True # ← Используем related_name
).distinct()
# Найти авторов, у которых ровно 3 книги
from django.db.models import Count
authors_with_3_books = Author.objects.annotate(
book_count=Count('books') # ← Используем related_name
).filter(book_count=3)
Отключение обратной связи
# Если не нужна обратная связь, используй related_name='+'
class InternalLog(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='+' # Нет обратной связи
)
# Теперь это не будет работать:
# user.internallog_set.all() # AttributeError!
Важные правила
- Всегда используй related_name для clarity
- Имя должно быть понятным (books, comments, orders)
- Для M:M используй множественное число (authors, tags)
- Для 1:M используй множественное число (posts, comments)
- Если есть дублирование (User → author → posts, User → comments) используй разные имена (authored_posts, authored_comments)
- Используй для фильтрации через двойное подчёркивание (publisher__books__published)
related_name — это один из самых важных параметров ForeignKey, который делает код более читаемым и удобным для работы с обратными связями!