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:
Then I created a new Book and assigned Leo Tolstoy as theAuthor:
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:
I would like to access the Author's Books as well as for the Books
to show in the Author's Admin view.
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
)
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()
Related
I am trying to add OneToMany field in django rest models. But Django is not giving an options for it. Can anyone suggest something similar to java #OneToMany in Django framework
You can use related_name in ForeignKey field to achieve this.
For example, you have the following models:
class Author(models.Model):
name = models.CharField(max_length=128)
class Book(models.Model):
name = models.CharField(max_length=128)
author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE)
Now, to access all books of an author the query will be Author.books.all(). Here, notice that Author model don't have books attribute. But in author ForeignKey field (which refers the Author model) of Book model has the related_name argument and its value is books. It means that books of an auhtor can be accessed from Author model. Django handles it nicely.
Also, you can use select_related for optimization (in this case you don't need to use related_name argument): Book.objects.all().select_related('author')
Please I need help with getting the result of querying my ManyToMany fields.
Basically I have the following models:
class Book(models.Model):
title = models.CharField(max_length=50)
authors = models.ManyToManyField(Author)
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
How should I query my book model to show all the authors of each book, based on the book_id and without the book_id, and how to query all the books that were written by one author?
I have tried to follow the Docs where Pizza and Topping but I'm not getting it, so thanks in advance friends and have a good day.
To get all the authors given a book you just do:
my_book.authors.all()
The second query is much more complicated: you need to use annotations to get the count of authors for each book, and filter on those whose count is one:
from django.db.models import Count
Book.objects.annotate(author_count=Count('authors')).filter(author_count=1)
For getting all the authors of a book using ManyToManyField you should use related_name attribute of your Book. authors field. ex: authors = models.ManyToManyField(Author, related_name="Books").
And then the query is my_author.books.all() which is syntactic sugar of my_author.book_set.all()
If having different books stored in django database, each book has a date in which it was added to the database. Is their a way of filtering books written by a certain author that was within a date range only using django views?
Not sure what you mean by only django views, I assume you want to use querysets. Your question is poorly written - read this.
class Book(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField()
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=200)
And Queryset would be something like this.
books = Book.objects.filter(author__name=authors_name,
date__range=["2011-01-01", "2011-01-31"])
Given the following models:
class Author(models.Model):
name = models.CharField()
class Book(models.Model):
title = models.CharField()
published_year = models.PositiveIntegerField()
authors = models.ManyToManyField(Author)
Let's say I want to get all of the authors who have authored a book published in the year 2008. I can do the following:
Book.objects.filter(published_year=2008).values_list('authors__name').distinct()
That'll get me a list of authors - almost exactly what I want, except that instead of just the names, I want the Author objects. I can achieve that somewhat by doing this:
authors = []
for b in Book.objects.filter(published_year=2008):
for a in b.authors.all():
if a not in authors:
authors.append(a)
But that seems totally unnecessary. Is it possible to get the QuerySet to do that work for me? Thanks!
Just use backward relationship
Author.objects.filter(book__published_year=2008).all()
From Django docs
Reverse m2m queries are supported (i.e., starting at the table that
doesn’t have a ManyToManyField):
Well, this is the problem, I have a username column and I defined it in the models.py.
And a user may take some courses( the course may changes in the future), the relation between user and courses is 1 vs multi, which means a user can take multi courses and a courses could be taken by several users.
I am new to django and DB design, how to represent this in Django with ORM?
def user(models.Model):
name = models.CharField(max_length=30)
class courses(models.Model):
course = models.CharField(max_length=100)
Following #djsutho thought, define a many-to-many relationship:
class user(models.Model):
name = models.CharField(max_length=30)
courses = models.ManyToManyField(courses)
class courses(models.Model):
course = models.CharField(max_length=100)
Then, for example, querying courses per user would be as easy as:
courses.objects.filter(user__name='Bob')
Also note that, by Django model naming convention, model class names should start with a upper case letter: user should be User, courses - Courses.
Also note that the model name should not be in a plural form - better name courses as Course. Also better rename course field to name.
So, finally, here's the picture:
class User(models.Model):
name = models.CharField(max_length=30)
courses = models.ManyToManyField(Course)
class Course(models.Model):
name = models.CharField(max_length=100)
Hope that helps.