Reputation: 107
I have made a comment system under my books where only the authenticated user can comment. When I use the form to add a comment, it doesn't work! why ?
here is my models
class Books(models.Model):
author = models.ManyToManyField(Authors)
title = models.CharField(max_length=250)
number_of_pages = models.PositiveIntegerField(validators=[MaxValueValidator(99999999999)])
date_added = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
publication_date = models.PositiveIntegerField(default=current_year(), validators=[MinValueValidator(300),
max_value_current_year])
cover = models.ImageField(upload_to='pics/covers/', default='pics/default-cover.jpg')
pdf_file = models.FileField(upload_to='pdfs/books/', default='pdfs/default-pdf.pdf')
category = models.ForeignKey(Categories, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Comments(models.Model):
book = models.ForeignKey(Books, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{} - {}'.format(self.livre.title, self.user)
here is my forms
class BookForm(ModelForm):
class Meta:
model = Books
fields = '__all__'
class CommentForm(ModelForm):
class Meta:
model = Comments
fields = ['body']
here is my views
@login_required(login_url='login')
def book_detail_view(request, book_id):
books = get_object_or_404(Books, pk=book_id)
context = {'books': books,}
return render(request, 'book_detail.html', context)
@login_required(login_url='login')
def add_comment(request, comment_id):
form = CommentForm()
books = get_object_or_404(Books, pk=comment_id)
user = request.user
if request.method == "POST":
form = CommentForm(request.POST, instance=books)
if form.is_valid():
comment = form.save(commit=False)
comment.user = user
comment.books = books
comment.save()
return redirect('book_detail', books.id)
context = {'form': form}
return render(request, 'comment_form.html', context)
here is my book detail page
{% extends 'base.html' %}
{% block title %} {{ books.title }} {% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-4">
<p><img src="{{ books.cover.url }}"></p>
</div>
<div class="col-lg-8">
<h2>{{ books.title }}</h2>
<b>Author : </b>
{% for author in books.author.all %}
<a href="{% url 'detail_author' author.id %}">{{ author.name }}</a>
{% if not forloop.last %},{% endif %}
{% endfor %}<br/>
<b>Catégory : </b>{{ books.category }}<br/>
<b>Pages : </b>{{ books.number_of_pages }}<br/>
<b>Publication : </b>{{ books.publication_date }}<br/>
<b>Date added : </b>{{ books.date_added }}<br/>
<b>Updated : </b>{{ books.updated }}<br/>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<p><a href="{{ books.pdf_file.url }}"><button class="btn btn-outline-dark btn-sm"><i class="far fa-eye"></i> Read</button></a></p>
</div>
</div>
<hr/>
<div class="container-fluid">
<h2>Comments</h2>
</div>
<div class="container-fluid">
{% if not books.comments.all %}
<p>No comments yet ! <a class="text-primary" href="{% url 'add_comment' books.id %}">Add comment...</a></p>
{% else %}
<a class="text-primary" href="{% url 'add_comment' books.id %}">Add comment !</a><br/><br/>
{% for comment in books.comments.all%}
<b>{{ comment.user }}</b> - <span class="text-muted" style="font-size: 13px;">{{ comment.date }}</span>
<p>{{ comment.body }}</p>
{% endfor %}
{% endif %}
</div>
{% endblock %}
here is my form for comment model
{% extends 'base.html' %}
{% block title %} Add a comment {% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Add this comment</button>
</form>
{% endblock %}
here is my urls
urlpatterns = [
# BOOKS
path('book/<int:book_id>/', views.book_detail_view, name='book_detail'),
# COMMENTS
path('book/<int:comment_id>/comment/', views.add_comment, name='add_comment'),
]
Upvotes: 1
Views: 338
Reputation: 476574
Your form is currently set to edit the book, not the comment, you should remove the instance=books
:
if request.method == "POST":
# no instance=books ↓
form = CommentForm(request.POST)
If you use instance=books
, the form will set attributes to the Books
object, and then the comment = form.save(commit=False)
will result in the fact that comment
is a Books
object that is already saved and thus updated in the database.
You also made a typo when setting the book
of a Comments
object: it is book
, not :books
if form.is_valid():
comment = form.save(commit=False)
comment.user = user
comment.book = books # ← .book, not .books
comment.save()
Note: normally a Django model is given a singular name, so
Book
instead of.Books
Upvotes: 3