Sobes.tech
Middle

Jak zaimplementować relację wiele do wielu w Django?

sobes.tech AI

Odpowiedź od AI

W Django relacja "wiele do wielu" (many-to-many) jest realizowana za pomocą pola ManyToManyField. To pole łączy dwa modele, tworząc tabelę pośrednią w bazie danych do przechowywania relacji.

Załóżmy, że mamy modele Author i Book. Jeden książka może być napisana przez wielu autorów, a jeden autor może napisać wiele książek.

# 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)
    authors = models.ManyToManyField(Author) # Pole ManyToManyField

    def __str__(self):
        return self.title

Dodając ManyToManyField do modelu Book, Django automatycznie tworzy tabelę pośrednią (zwykle o nazwie appname_book_authors), która łączy Book i Author. Ta tabela będzie miała kolumny dla kluczy obcych do obu modeli (book_id i author_id).

Aby pracować z tym związkiem, można użyć następującej składni:

Dodawanie autorów do książki:

# Przykład użycia
from myapp.models import Author, Book

author1 = Author.objects.create(name="Lew Tołstoj")
author2 = Author.objects.create(name="Fiodor Dostojewski")

book = Book.objects.create(title="Wojna i pokój")
book.authors.add(author1)
book.authors.add(author2) # Dodanie autorów do książki

Pobieranie wszystkich książek autora:

author = Author.objects.get(name="Lew Tołstoj")
books_by_tolstoy = author.book_set.all() # Relacja odwrotna

# Relacja odwrotna jest dostępna domyślnie przez "_set"
# Nazwę relacji odwrotnej można zmienić za pomocą `related_name`

Pobieranie wszystkich autorów książki:

book = Book.objects.get(title="Wojna i pokój")
authors_of_book = book.authors.all() # Dostęp do powiązanych autorów

Usuwanie autorów z książki:

book = Book.objects.get(title="Wojna i pokój")
author1 = Author.objects.get(name="Lew Tołstoj")
book.authors.remove(author1) # Usunięcie autora z książki

Usuwanie wszystkich autorów z książki:

book = Book.objects.get(title="Wojna i pokój")
book.authors.clear() # Usunięcie wszystkich autorów z książki

Dodawanie wielu autorów naraz:

book = Book.objects.get(title="Wojna i pokój")
author3 = Author.objects.create(name="Michaił Bułhakow")
author4 = Author.objects.create(name="Anton Czechow")
book.authors.add(author3, author4) # Dodanie wielu autorów

Dodatkowe możliwości:

  • through: Można zdefiniować własny model pośredni, używając parametru through, jeśli konieczne jest dodanie dodatkowych pól do relacji (np. data dodania autora do książki).

    class Membership(models.Model):
        book = models.ForeignKey(Book, on_delete=models.CASCADE)
        author = models.ForeignKey(Author, on_delete=models.CASCADE)
        date_added = models.DateField()
    
    class Book(models.Model):
        title = models.CharField(max_length=200)
        authors = models.ManyToManyField(Author, through='Membership')
    
        def __str__(self):
            return self.title
    
  • related_name: Pozwala zmienić nazwę atrybutu używanego do relacji odwrotnej.

    class Author(models.Model):
        name = models.CharField(max_length=100)
        books = models.ManyToManyField('Book', related_name='published_by') # Zmiana nazwy relacji odwrotnej
    
        def __str__(self):
            return self.name
    
    # Teraz, aby uzyskać książki autora, używa się:
    # author = Author.objects.get(name="Lew Tołstoj")
    # books_by_author = author.books.all()
    # Aby uzyskać autorów książki:
    # book = Book.objects.get(title="Wojna i pokój")
    # authors_of_book = book.published_by.all()
    

W ten sposób ManyToManyField upraszcza zarządzanie relacjami "wiele do wielu" w Django, automatycznie obsługując tworzenie i zarządzanie odpowiednią tabelą pośrednią.