I want to create a filter on the website based on book data so that after selecting these categories on the same page, it is sorted. For example, how it is implemented on e-commerce websites (you can select a range of date, genre, publisher etc.). After the selection, the number of books is reduced.
Could you tell me how to do this?
**views.py**
from django.db.models import Q
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
TemplateView, UpdateView)
from .forms import AuthorForm, BookForm
from .models import Author, Book, Genre
# Create your views here.
# Home page
class HomeView(ListView):
model = Book
template_name = "home.html"
# Book pages
class BooksView(ListView):
model = Book
template_name = "books.html"
context_object_name = "books_list"
ordering = ["-created_date"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["genre"] = Genre.objects.all()
context["authors"] = Author.objects.all()
return context
class BookDetailView(DetailView):
model = Book
template_name = "book-detail.html"
context_object_name = "book"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["genre"] = Genre.objects.filter(id=1)
context["author"] = Author.objects.all()
return context
# CRUD pages
class BookCreateView(SuccessMessageMixin, CreateView):
model = Book
form_class = BookForm
template_name = "create_book.html"
success_message = "%(title)s was created successfully"
class BookUpdateView(UpdateView):
model = Book
form_class = BookForm
template_name = "update_book.html"
success_message = "%(title)s was updated successfully"
class BookDeleteView(SuccessMessageMixin, DeleteView):
model = Book
form_class = BookForm
template_name = "delete_book.html"
success_url = reverse_lazy("books")
success_message = "%(title)s was deleted successfully"
def delete(self, request, *args, **kwargs):
obj = self.get_object()
data_to_return = super(BookDeleteView, self).delete(
request, *args, **kwargs)
messages.success(self.request, self.success_message % obj.__dict__)
return data_to_return
# Author pages
class AuthorDetailView(DetailView):
model = Author
template_name = "author-detail.html"
context_object_name = "author"
class AuthorCreateView(SuccessMessageMixin, CreateView):
model = Author
form_class = AuthorForm
template_name = "author_create.html"
success_message = "%(last_name)s was created successfully"
class AboutView(TemplateView):
template_name = "about.html"
# Search page
class SearchResultsListView(ListView):
model = Book
context_object_name = "book_list"
template_name = "search_results.html"
def get_queryset(self):
query = self.request.GET.get('q')
return Book.objects.filter(
Q(title__icontains=query) | Q(
author__first_name__icontains=query) | Q(author__last_name__icontains=query)
)
**models.py**
import uuid
from django.db import models
from django.urls import reverse
from django.utils import timezone
class Genre(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(
upload_to="photos", default=None, blank=True, null=True)
author = models.ForeignKey("Author", on_delete=models.SET_NULL, null=True)
summary = models.TextField()
publisher = models.ForeignKey("Publisher", on_delete=models.SET_NULL, null=True)
isbn = models.CharField(max_length=10, unique=True, blank=True, null=True)
genre = models.ManyToManyField("Genre")
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("book_detail", kwargs={"pk": self.pk})
class Meta:
ordering = ["-created_date"]
constraints = [
models.UniqueConstraint(
fields=["title"], name="%(app_label)s_unique_booking"
)
]
class Author(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Meta:
ordering = ["first_name", "last_name"]
constraints = [
models.UniqueConstraint(
fields=["first_name", "last_name"], name="uniquename"
)
]
def get_absolute_url(self):
return reverse("author_detail", kwargs={"pk": self.pk})
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Publisher(model.Model):
name = models.CharField(max_length=200)
**list_books.html**
{% extends 'base.html' %} {% block content %}
<div class="container">
<div class="row">
<div class="col-2">
<ul class="list-unstyled text-primary">
{% for genre_list in genre %}
<li>{{genre_list.name}}</li>
{% endfor %}
</ul>
</div>
<div class="col-10">
<div class="card-group gap-3">
{% for books_list in books_list %}
<div class="d-flex flex-wrap">
<div class="card p-2" style="width: 10rem; height: 15rem">
<div class="card-img-top mb-2 text-center">
{% if books_list.image %}
<img src="{{ books_list.image.url }}" class="card-img-top mb-2" alt="{{books_list.title }}"
style="max-width: 127px; max-height: 127px" />
{% else %}
<p>No Image</p>
{% endif %}
</div>
<div class="class-body text-center">
<h5 class="card-tittle fs-6">
<a href="{% url 'book_detail' books_list.id %}">{{books_list.title}}</a>
</h5>
<p class="card-text fs-6">
<small class="text-muted">
<a href="{% url 'author_detail' books_list.author.id %}">{{books_list.author}}</a>
</small>
</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock content %}