Ответ
Связь «многие-ко-многим» в Django ORM создается с помощью поля models.ManyToManyField. Django автоматически создает промежуточную (join) таблицу для управления этими отношениями.
Это позволяет, например, связать одного автора с несколькими книгами и одну книгу с несколькими авторами.
Базовый пример
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=100)
# Определение связи many-to-many
authors = models.ManyToManyField(Author, related_name='books')
def __str__(self):
return self.title
Основные операции
Для управления связями используются специальные методы менеджера:
add(): добавляет объекты в связь.remove(): удаляет объекты из связи.set(): полностью заменяет набор связанных объектов.clear(): удаляет все объекты из связи.
# Получаем объекты
author1 = Author.objects.get(name='Лев Толстой')
book = Book.objects.get(title='Война и мир')
# Добавляем автора к книге
book.authors.add(author1)
# Фильтрация по связанной модели
books_by_tolstoy = Book.objects.filter(authors__name='Лев Толстой')
Пользовательская промежуточная модель (through)
Если вам нужно хранить дополнительные данные о самой связи (например, дату вступления участника в группу), используется опция through.
class Membership(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
# Дополнительное поле
role = models.CharField(max_length=50, default='author')
# Модель Book теперь ссылается на Membership
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, through='Membership') Ответ 18+ 🔞
А, ManyToManyField! Ну это ж классика, блядь, ёпта! Сейчас объясню, как эта штука работает, а то некоторые думают, что это какая-то хуйня непонятная.
Смотри, представь себе авторов и книги. Один автор может написать дохуя книг, да? А одна книга может быть написана дохуя авторами — вот тебе и связь «многие-ко-многим». Django, умная жопа, сам создаёт промежуточную таблицу, чтобы это всё связать. Не надо руками в SQL лезть и JOIN'ы городить — всё за тебя сделают, красота!
Вот смотри, как это выглядит в коде, блядь:
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=100)
# Вот она, мать её, связь! Говорим: "у книги много авторов"
authors = models.ManyToManyField(Author, related_name='books')
def __str__(self):
return self.title
Видишь? Всё просто, как три копейки! Авторы отдельно, книги отдельно, а связь между ними — магия, блядь!
А теперь самое интересное — как этим пользоваться. Тут есть специальные методы, которые делают всё за тебя. Запоминай, а то потом будешь голову ломать!
# Нашли нашего графомана
author1 = Author.objects.get(name='Лев Толстой')
# И его творение
book = Book.objects.get(title='Война и мир')
# Привязываем автора к книге — раз и готово!
book.authors.add(author1)
# А теперь хотим все книги Толстого найти — фильтруем по связанной модели
books_by_tolstoy = Book.objects.filter(authors__name='Лев Толстой')
Но это ещё цветочки, блядь! Бывает, что в самой связи нужно хранить дополнительные данные. Например, не просто «автор написал книгу», а «автор написал книгу в роли главного редактора» или там «соавтора». Вот тут на сцену выходит опция through — пользовательская промежуточная модель, ёпта!
class Membership(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
# А вот и доп поле! Теперь можем указать роль
role = models.CharField(max_length=50, default='author')
# И в модели Book теперь ссылаемся через Membership
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, through='Membership')
Вот так вот, блядь! Теперь у тебя в связи есть дополнительные поля, и ты можешь хранить там что угодно — дату, роль, процент авторского взноса, хоть цвет носков автора в момент написания! Главное — не перемудрить, а то потом сам не разберёшься, что накодил, в рот меня чих-пых!
Короче, ManyToManyField — это мощный инструмент, который экономит кучу времени. Используй на здоровье, только не забудь миграции сделать, а то ничего не заработает, и будешь сидеть, чесать репу, как тот самый Герасим, который только «Му-му» говорить умел!