← Назад к вопросам

Что такое поле related_name в Django?

2.3 Middle🔥 241 комментариев
#Django

Комментарии (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!

Важные правила

  1. Всегда используй related_name для clarity
  2. Имя должно быть понятным (books, comments, orders)
  3. Для M:M используй множественное число (authors, tags)
  4. Для 1:M используй множественное число (posts, comments)
  5. Если есть дублирование (User → author → posts, User → comments) используй разные имена (authored_posts, authored_comments)
  6. Используй для фильтрации через двойное подчёркивание (publisher__books__published)

related_name — это один из самых важных параметров ForeignKey, который делает код более читаемым и удобным для работы с обратными связями!

Что такое поле related_name в Django? | PrepBro