JavaRush /Курси /Модуль 3: Django /Обхід пов'язаних об'єктів

Обхід пов'язаних об'єктів

Модуль 3: Django
Рівень 9 , Лекція 7
Відкрита

Створювати зв'язки між моделями — це круто, але зв'язок марний, якщо ти не можеш його ефективно використовувати. Уяви, що у тебе є класна Wi-Fi мережа, але немає пароля до неї. От ми цю "мережу" моделей вже побудували, тепер займемося тим, як витягувати потрібні дані. Django ORM надає зручні інструменти та методи для обходу пов'язаних об'єктів, і ми розглянемо їх детально.

Основи обходу пов'язаних об'єктів

1. Як працювати з об'єктами, пов'язаними через ForeignKey

ForeignKey створює зв'язок "один-до-багатьох". Це означає, що у об'єкта в одній таблиці може бути багато пов'язаних об'єктів з іншої таблиці.

Припустимо, у нас є дві моделі: Author та Book. Один автор може написати багато книг. Цей зв'язок реалізується через ForeignKey.

# models.py
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

    def __str__(self):
        return self.title

Доступ до пов'язаних об'єктів

Тепер, якщо у нас є об'єкт Author, ми можемо отримати всі його книги, використовуючи атрибут related_name, який ми налаштували як books:

# Отримаємо автора
author = Author.objects.get(name="Джордж Мартін")

# Усі книги цього автора
books = author.books.all()  # Поверне QuerySet з книгами
print(books)

Якщо ти не вкажеш related_name в полі ForeignKey, Django автоматично створить атрибут виду book_set. Тобто доступ до книг можна буде отримати через author.book_set.all().

2. Як працювати з об'єктами, пов'язаними через ManyToManyField

Зв'язок "багато-до-багатьох" дозволяє одному об'єкту бути пов'язаним із кількома об'єктами іншої моделі і навпаки.

Розберемо зв'язок між Student та Course. Один студент може записатися на кілька курсів, а один курс може бути доступним для різних студентів.

# models.py
class Course(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Student(models.Model):
    name = models.CharField(max_length=100)
    courses = models.ManyToManyField(Course, related_name='students')

    def __str__(self):
        return self.name

Доступ до пов'язаних об'єктів

Якщо у нас є об'єкт Student, ми можемо отримати всі курси, на які записаний студент:

# Отримаємо студента
student = Student.objects.get(name="Іван Іванов")

# Усі курси, на які записаний студент
courses = student.courses.all()
print(courses)

Так само ми можемо отримати всіх студентів, записаних на конкретний курс:

# Отримаємо курс
course = Course.objects.get(name="Математика")

# Усі студенти, записані на курс
students = course.students.all()
print(students)

3. Як працювати з об'єктами, пов'язаними через OneToOneField

Зв'язок "один-до-одного" створює унікальну пару між двома об'єктами. Наприклад, у кожного користувача може бути тільки один профіль, і кожен профіль належить тільки одному користувачу.

Приклад

# models.py
from django.contrib.auth.models import User

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    bio = models.TextField()

    def __str__(self):
        return f"{self.user.username}'s Profile"

Доступ до пов'язаних об'єктів

Якщо у нас є об'єкт User, профіль можна отримати через атрибут related_name (або просто за назвою моделі у нижньому регістрі, якщо related_name не вказаний):

# Отримаємо користувача
user = User.objects.get(username="john_doe")

# Доступ до профілю користувача
profile = user.profile
print(profile.bio)

А якщо ми працюємо з об'єктом Profile, то, наприклад, ім'я користувача можна отримати через зв'язок:

# Отримаємо профіль
profile = Profile.objects.get(user__username="john_doe")

# Доступ до пов'язаного користувача
user = profile.user
print(user.username)

Практика: обхід об'єктів у шаблонах

Приклад отримання даних про користувача та його пости для відображення на HTML-сторінці.

# models.py
class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")

    def __str__(self):
        return self.title

У представленні ми передамо об'єкт User і його пов'язані пости:

# views.py
from django.shortcuts import render
from django.contrib.auth.models import User

def user_profile(request, username):
    user = User.objects.get(username=username)
    posts = user.posts.all()  # Отримуємо всі пости користувача
    return render(request, "user_profile.html", {"user": user, "posts": posts})

У шаблоні:

<!-- user_profile.html -->
<h1>Профіль користувача: {{ user.username }}</h1>
<h2>Пости:</h2>
<ul>
  {% for post in posts %}
    <li>{{ post.title }} - {{ post.content }}</li>
  {% empty %}
    <li>Немає постів</li>
  {% endfor %}
</ul>

Особливі випадки: використання методів all(), add(), remove() і clear()

  1. Отримання пов'язаних об'єктів через all()

Метод all() повертає всі об'єкти, пов'язані з поточною моделлю. Ви вже бачили його приклади вище.

  1. Додавання об'єктів через add()

Щоб пов'язати об'єкт з моделлю, можна використати метод add():

# Пов'язуємо студента з курсом
student.courses.add(course)
  1. Видалення зв'язків через remove()

Якщо потрібно прибрати зв'язок між об'єктами:

# Видаляємо курс у студента
student.courses.remove(course)
  1. Видалення всіх зв'язків через clear()

Якщо потрібно видалити всі зв'язки:

# Видаляємо всі курси у студента
student.courses.clear()

Що може піти не так?

Одна з найпоширеніших помилок — спроба доступу до пов'язаних об'єктів, коли вони ще не створені. Наприклад, якщо у користувача немає профілю, виклик user.profile призведе до помилки. Щоб уникнути цього, варто робити перевірки:

if hasattr(user, 'profile'):
    profile = user.profile
else:
    profile = None

Практична користь

Робота з пов'язаними об'єктами — життєво важливий навик для створення реальних застосунків. Це дозволяє ефективно отримувати дані, організовувати взаємопов'язані сутності та покращувати продуктивність завдяки оптимізації запитів. Корисно на співбесідах, а також під час розробки складних систем, таких як CRM, інтернет-магазини чи освітні платформи.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ