I have a book model and a genre model that have a many to many relationship. How would I go about getting all the books for a specific genre in a list view. I'm assuming its faster to get a Genre object and get all the books from it using a query such as "genre.objects.book_set.all" rather than going through all books and seeing if they have the specified genre. However I'm not sure how I would do that in a ListView? I wanna take the genre name from the url and then use that to get the genre object.
Here is what I have:
urls.py:
path('genre/<string:name>', GenreListView.as_view(), name='book-genre'),
Models.py:
class Genre(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.TextField()
user_count = models.IntegerField()
pages = models.IntegerField()
genres = models.ManyToManyField(Genre)
image = models.ImageField(default='book_imgs/default.jpg', upload_to='book_imgs')
def __str__(self):
return self.name
Views.py
class GenreListView(ListView):
model = Genre
def get_queryset(self):
Not sure what to put here....
return
CodePudding user response:
You can do something like this:
class SciFiListView(View):
scifi_books = Book.objects.filter(genres__name__icontains="scifi")
return render(request, "books/list.html", {"scifi_books": scifi_books})
list.html
{% for book in scifi_books %}
<p>{{ book.name }} | {{ book.description }}</p>
{% endfor %}
CodePudding user response:
You should pass id
of Genre, then apply filter in get_queryset
method to get all the books for specific genres in the following way:
urls.py
path('genre/<int:id>/', GenreListView.as_view(), name='book_genre'),
views.py
class GenreListView(ListView):
model = Book
template_name = 'any_folder_name/any_file_name.html'
context_object_name = 'specific_books'
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(genres=self.kwargs['id'])
Then, you can show books related to specific genre in the template.
any_file_name.html
<body>
{% for book in specific_books %}
<div>
<p>{{book.name}}</p>
<p>{{book.description}}</p>
<p>{{book.pages}}</p>
</div>
<br>
{% endfor %}
</body>
Or, you can simply do it with function based views too.
urls.py
path('genre/<int:id>/', views.specific_books, name='specific_books'),
views.py
def specific_books(request, id):
specific_books = Book.objects.filter(genres=id)
return render(request, 'any_folder_name/any_file_name.html', {'specific_books': specific_books})