I am building website for library and I want to add comment for each book. I built a form for it, but I don’t know how to pass the title for each book. Furthermore, I did it for user, but I don’t know how to do it for title.
models.py
import uuid
from django.db import models
from django.db.models.enums import TextChoices
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User
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()
isbn = models.CharField(max_length=10, unique=True, blank=True, null=True)
genre = models.ManyToManyField("Genre", related_name="book_genre")
publisher = models.ManyToManyField("Publisher")
languages = models.ManyToManyField("Language")
publication_date = models.DateTimeField(default=timezone.now)
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 Publisher(models.Model):
name = models.CharField(max_length=250)
def __str__(self):
return self.name
class Language(models.Model):
class LanguageBook(models.TextChoices):
English = "Eng", _('English')
Spanish = "Es", _('Spanish')
Russian = "Rus", _('Russian')
German = "German", _('German')
Chinese = "Chinese", _('Chinese')
language_book = models.CharField(
max_length=10, choices=LanguageBook.choices, default=LanguageBook.English)
def __str__(self):
return self.language_book
# Author
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):
"""String for representing the Model object."""
return f"{self.first_name} {self.last_name}"
class Review(models.Model):
book = models.ForeignKey(
Book, on_delete=models.CASCADE, related_name="reviews")
title = models.CharField(max_length=255)
body = models.TextField()
author = models.OneToOneField(User, on_delete=models.CASCADE)
created = models.DateTimeField(default=timezone.now)
def __str__(self):
"""String for representing the Model object."""
return self.body
forms.py
from django import forms
from .models import Author, Book, Review
class NewReviewForm(forms.ModelForm):
class Meta:
model = Review
fields = ("title", "body")
views.py
from django.db.models import Q
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.urls import reverse
from django.views.generic.edit import FormMixin
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
TemplateView, UpdateView)
from .filters import BookFilter
from .forms import AuthorForm, BookForm, NewReviewForm
from .models import Author, Book, Genre, Review
class BookDetailView(FormMixin, DetailView):
model = Book
template_name = "book-detail.html"
context_object_name = "book"
form_class = NewReviewForm
def get_success_url(self):
return reverse('book_detail', kwargs={'pk': self.object.id})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["author"] = Author.objects.all()
context['form'] = NewReviewForm(initial={'id': self.object})
return context
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.instance.author = self.request.user
form.save()
return super(BookDetailView, self).form_valid(form)
book-detail.html
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row justify-content-md-center">
{% comment %} Image and update, delete {% endcomment %}
<div class="col-2 mt-5 ms-5 d-flex flex-column align-items-center">
{% if book.image %}
<img src="{{ book.image.url }}" alt="{{book.title}}" style="width:200px; height:200px">
{% else %}
<p>No Image</p>
{% endif %}
<a href="{% url 'book_update' book.id %}" class="d-flex align-items-center gap-1 mt-2"><svg
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-square"
viewBox="0 0 16 16">
<path
d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z" />
<path fill-rule="evenodd"
d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z" />
</svg>Update information</a>
<a href="{% url 'book_delete' object.id %}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path
d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" />
<path fill-rule="evenodd"
d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z" />
</svg>
Delete Book</a>
</div>
{% comment %} End Image {% endcomment %}
{% comment %} Content {% endcomment %}
<div class="col-6 mt-5 ms-5">
<h1>{{book.title}}</h1>
<a href="{% url 'author_detail' book.author.id %}" class="color-primary">{{book.author}}</a>
{% comment %} start Google Translate {% endcomment %}
<div id="google_translate_element" class="text-end"></div>
{% comment %} End Google Translate {% endcomment %}
<p class="mt-5"><strong>Summary:</strong></p>
<p class="bold">{{book.summary}}</p>
<br>
<ul class="list-group mt-4">
<li class="list-group-item ">Book author: {{book.author}}</li>
<li class="list-group-item">Genre: {{ genre.book_genre.all }}</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>
<div>
{% comment %} Start review {% endcomment %}
<h1>Review</h1>
{% for review in book.reviews.all %}
<p>{{review.author}}</p>
<div class="notification">
<p>{{ review.created|date:"d-m-Y" }}</p>
</div>
<p>{{review.title}}</p>
<p>{{ review.body|linebreaks }}</p>
{% empty %}
<div class="notification">
No review yet ...
</div>
{% endfor %}
</div>
<div>
{% if request.user.is_authenticated %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Add comment">
</form>
{% else %}
<p>Please sign in to add review</p>
{% endif %}
</div>
{% comment %} End review {% endcomment %}
</div>
{% comment %} End comment {% endcomment %}
{% comment %} Loan {% endcomment %}
<div class="col-4 mt-5" style="width: 300px; height:100px">
<div class="card rounded-3 shadow-sm">
<div class="card-header py-3">
<h4 class="my-0 fw-normal tex-center">Loan</h4>
</div>
<div class="card-body">
<ul class="list-unstyled mt-3 mb-4">
<li>...</li>
</ul>
<button type="button" class="w-100 btn btn-lg btn-outline-primary">Take</button>
</div>
</div>
{% comment %} End Loan {% endcomment %}
</div>
</div>
{% endblock content %}