← Назад к вопросам
Как обратится к связанным полям через ORM Django?
1.3 Junior🔥 161 комментариев
#Django#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Доступ к связанным полям в Django ORM
Django ORM позволяет работать с отношениями между моделями (ForeignKey, OneToOneField, ManyToManyField) с помощью специального синтаксиса с двойным подчеркиванием (__).
ForeignKey — один ко многим
Определение моделей:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
published_date = models.DateField()
pages = models.IntegerField()
def __str__(self):
return self.title
Доступ от книги к автору:
# Получить книгу с её автором
book = Book.objects.get(id=1)
print(book.title) # "Django for Beginners"
print(book.author.name) # "Jane Doe" (доступ к связанному объекту)
print(book.author.email) # "jane@example.com"
# Доступ через точку — это SQL запрос!
# SELECT * FROM books WHERE id=1;
# SELECT * FROM authors WHERE id=...;
Оптимизированный доступ с select_related():
# НЕОПТИМАЛЬНО
books = Book.objects.all()
for book in books:
print(f"{book.title} by {book.author.name}")
# Это выполнит 1 запрос для книг + N запросов для авторов!
# ОПТИМАЛЬНО
books = Book.objects.select_related('author')
for book in books:
print(f"{book.title} by {book.author.name}")
# Выполнит всего 1 запрос (JOIN)
Фильтрация по связанным полям:
# Найти все книги автора Jane Doe
books = Book.objects.filter(author__name="Jane Doe")
# author__name — доступ к полю связанного объекта
for book in books:
print(book.title)
# Несколько условий
books = Book.objects.filter(
author__name__startswith="J",
published_date__year=2023
)
# Фильтрация по id связанного объекта
book = Book.objects.filter(author_id=42).first()
Обратное отношение (Reverse ForeignKey)
Доступ от автора к его книгам:
# Получить автора
author = Author.objects.get(name="Jane Doe")
# Доступ к его книгам (автоматически создается обратное отношение)
books = author.book_set.all() # По умолчанию: <model>_set
for book in books:
print(book.title)
# Или с custom related_name
class Book(models.Model):
author = models.ForeignKey(
Author,
on_delete=models.CASCADE,
related_name="books" # Вместо book_set
)
# Теперь можно:
books = author.books.all() # Более понятно!
OneToOneField — один к одному
Определение:
class UserProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name="profile"
)
bio = models.TextField()
avatar = models.ImageField()
Доступ:
# От User к Profile
user = User.objects.get(id=1)
profile = user.profile
print(profile.bio)
# От Profile к User
profile = UserProfile.objects.get(id=1)
user = profile.user
print(user.username)
# Фильтрация
users = User.objects.filter(
profile__bio__contains="Developer"
)
ManyToManyField — многие ко многим
Определение:
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
title = models.CharField(max_length=100)
students = models.ManyToManyField(
Student,
related_name="courses"
)
Доступ:
# От Course к Students
course = Course.objects.get(id=1)
students = course.students.all()
for student in students:
print(student.name)
# От Student к Courses
student = Student.objects.get(id=1)
courses = student.courses.all()
for course in courses:
print(course.title)
# Добавить связь
student.courses.add(course)
# Удалить связь
student.courses.remove(course)
# Проверить наличие
if course in student.courses.all():
print("Student enrolled")
# Удалить все связи
student.courses.clear()
Фильтрация ManyToMany:
# Найти все курсы, в которых учится Alice
courses = Course.objects.filter(
students__name="Alice"
)
# Найти всех студентов конкретного курса
students = Student.objects.filter(
courses__title="Python Basics"
)
# Найти студентов, которые учатся на двух конкретных курсах
students = Student.objects.filter(
courses__title="Python Basics"
).filter(
courses__title="Web Development"
)
Цепочка отношений
class Publisher(models.Model):
name = models.CharField(max_length=100)
city = models.CharField(max_length=100)
class Author(models.Model):
name = models.CharField(max_length=100)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# Доступ через цепочку (book → author → publisher)
books = Book.objects.filter(
author__publisher__city="New York"
)
# Найти все книги авторов, издатели которых в Нью-Йорке
# Оптимизировать
books = Book.objects.select_related(
'author__publisher' # Загрузит author и publisher в один запрос
)
Практический пример: Blog
class User(models.Model):
username = models.CharField(max_length=100)
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="posts"
)
published = models.BooleanField(default=False)
class Comment(models.Model):
text = models.TextField()
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name="comments"
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="comments"
)
# Получить все посты пользователя
user = User.objects.get(username="alice")
user_posts = user.posts.all()
# Получить все комментарии к определенному посту
post = Post.objects.get(id=1)
post_comments = post.comments.all()
# Найти все посты с комментариями от Bob
posts = Post.objects.filter(
comments__author__username="bob"
).distinct()
# Найти все комментарии постов Alice
comments = Comment.objects.filter(
post__author__username="alice"
)
# Оптимизированный запрос
posts = Post.objects.filter(
published=True
).select_related('author').prefetch_related('comments')
for post in posts:
print(post.title)
print(post.author.username) # select_related загрузил
for comment in post.comments.all(): # prefetch_related загрузил
print(comment.text)
Лучшие практики
1. select_related для ForeignKey и OneToOneField:
books = Book.objects.select_related('author')
2. prefetch_related для ManyToManyField и обратных отношений:
books = Book.objects.prefetch_related('author__books')
3. Используй only() для выбора нужных полей:
books = Book.objects.only('title', 'author').select_related('author')
4. Избегай запросов в циклах:
# НЕПРАВИЛЬНО
for book in Book.objects.all():
author = book.author # Запрос в цикле!
# ПРАВИЛЬНО
for book in Book.objects.select_related('author'):
author = book.author # Уже загружено
Понимание связанных полей в Django ORM критично для создания эффективных запросов и оптимизации производительности приложения.