Pat Res
Pat Res

Reputation: 97

Django ManyToMany model: unable to access one relation from the other

My models.py:

class Author(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(
        "Book", related_name="books", blank=True
    )

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ManyToManyField(Author)

In Django admin I first created an instance of Author, without assigning him any Book:

enter image description here

Then I created a new Book and assigned Leo Tolstoy as theAuthor:

enter image description here

In Django shell, I am able to access the Book's Author:

>>> Book.objects.filter(title="War and Peace").first().author.first()
<Author: Leo Tolstoy>

But I'm unable to access the Author's Books:

>>> Author.objects.filter(name="Leo Tolstoy").first().books.all()
<QuerySet []>

The book isn't assigned in the Admin view either:

enter image description here

I would like to access the Author's Books as well as for the Books to show in the Author's Admin view.

Upvotes: 0

Views: 300

Answers (2)

Omayer Hasan Marif
Omayer Hasan Marif

Reputation: 364

I suggest you do this:

class Author(models.Model):
    name = models.CharField(max_length=100)
                
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ManyToManyField(Author, related_name="books",blank=True)

You need one ManyToManyField, then django will create two associative tables between the book and author tables. Changes to one table will not affect the other. You can see in the django documentation about many to many relationships. I have removed your books field in my answer because you have created an instance of your Author but you did not assign his 'book' and you have created a Book instance with giving title and author in your Book model. So so that any of your data won't be deleted. I also added related_name to your author field in your Book model because when you try to get the books related to the author (for example "Loe Tolstoy") you can get by this:

Author.objects.get(name="Leo Tolstoy").books.all() 

Upvotes: 1

Simon Crowe
Simon Crowe

Reputation: 468

You only need one ManyToManyField. You should also pass "books" as the related_name on Book.authors as this is the name Django will use for the many-to-many manager attribute it automatically adds to Author instances.

See the example in the Django docs for more info.

When a ManyToManyField is created on both sides of a relation, Django is creating two associative tables between the book and author tables under the hood. Changes to one table don't affect the other.

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

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(
        Author, related_name="books", blank=True
    )

Upvotes: 2

Related Questions