Here is my code first:
forms code from product.html:
...
{% comment %} Review Form Start`` {% endcomment %}
<div class="container">
<section class="review-section col-12 mt-4">
{% comment %} Display All Reviews {% endcomment %}
<h3 class="hide-review-heading">Reviews</h3>
{% for review in reviews %}
<div class="review">
<p><strong>{{ review.user.username }}</strong> - {{ review.rating }} stars</p>
<p>{{ review.review | safe }}</p>
</div>
<hr>
{% empty %}
<p>No reviews yet. Be the first to write a review!</p>
{% endfor %}
<h3 class="hide-review-heading">Write a Review</h3>
<strong class="" id="review-response"></strong>
<form action="{% url 'home:ajax_add_review' p.pid %}" method="POST" class="hide-review-form" id="commentForm">
{% csrf_token %}
<div class="form-group mt-3">
{{ review_form.review }}
</div>
<div class="form-group mt-3">
{{ review_form.rating.label_tag }}<br>
{{ review_form.rating }}
</div>
<br>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</section>
</div>
{% comment %} Review Form End {% endcomment %}
{% endblock body %}
review.js:
console.log("review.js loaded");
$("#commentForm").submit(function(e) {
e.preventDefault();
$.ajax({
data: $(this).serialize(),
method: $(this).attr("method"),
url: $(this).attr("action"),
dataType: "json",
success: function(response) {
console.log("Comment saved to DB")
if (response.bool) {
$("#review-response").html("Review saved successfully");
// Assign a class and remove text-danger class if there
$("#review-response").addClass("text-success");
$("#review-response").removeClass("text-danger");
$(".hide-review-form").hide();
$(".hide-review-heading").hide();
}
else {
$("#review-response").html("Error saving review");
$("#review-response").addClass("text-danger");
$("#review-response").removeClass("text-success");
}
}
});
});
urls.py:
from django.urls import path
from . import views
app_name = "home"
urlpatterns = [
path('', views.index, name='index'),
path('collections/<slug:collection_handle>', views.collections, name="collections"),
path('product/<slug:product_handle>', views.product, name="product"),
path('minimal_product/<slug:product_handle>', views.minimal_product, name="minimal_product"),
# path('products/', views.products, name="products"),
path('search/', views.search, name="search"),
path('products/', views.product_list, name="product-list"),
path('product-quick-view/<int:product_id>/', views.product_quick_view, name='product_quick_view'),
path("ajax-add-review/<pid>", views.ajax_add_review, name="ajax_add_review"),
]
Product and ajax_add_review function from views:
def product(request, product_handle):
product = Product.objects.filter(handle=product_handle, product_status="in_review").first()
review_form = ProductReviewForm()
reviews = ProductReview.objects.filter(product=product)
if not product:
raise Http404
context = {
"p": product,
"review_form": review_form,
"reviews": reviews,
}
return render(request, 'home/product.html', context=context)
def ajax_add_review(request, pid):
product = Product.objects.get(pid=pid)
user = request.user
# for key, value in request.POST.items():
# print(f'{key}: {value}')
review_text = request.POST.get('review')
rating = request.POST.get('rating')
print(f"Review is: {review_text}")
if not review_text or not rating:
print("Review text or rating is missing")
return JsonResponse({'bool': False, 'error': 'Review text or rating is missing'})
review = ProductReview.objects.create(
user=user,
product=product,
review=review_text,
rating=rating,
)
context = {
'user': user.username,
'review': review.review,
'rating': review.rating,
}
average_reviews = ProductReview.objects.filter(product=product).aggregate(Avg('rating'))
return JsonResponse(
{
'bool': True,
'context': context,
'average_reviews': average_reviews,
}
)
ProductReviewForm from forms.py:
class ProductReviewForm(forms.ModelForm):
# review = forms.CharField(widget=CKEditor5Widget(config_name='review', attrs={'placeholder': 'Write your review here...'}), required=False)
class Meta:
model = ProductReview
fields = ['review', 'rating']
widgets = {
"review": CKEditor5Widget(
attrs={"class": "django_ckeditor_5", 'placeholder': 'Write your review here...'}, config_name="review"
)
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["review"].required = False
Now, when I click submit, the value of rating is retrieved but the value of review, I checked in inspect and instead of {{ review_form.review }}, there was a with the name=”review” and display as none and for ckeditor where you the review is shown. And I believe that the review is retreieved from the .
It was happening from one of the two options which isn’t exactly what I want:
- If I click the Submit button, it shows “Error saving review” because of the line in ajax_add_review which says if not review_text or not rating and during that, the text in the review field is automatically added to the , so if I click Submit again, it works.
- If I remove e.preventDefault();, and then add the review and click Submit, it redirects me to the page where the JSON successfully generated from ajax_add_review is shown and the data is added successfully to the database with the review.
What I want is: for the page to not reload, the review and rating to be added to the database correctly without having to click the Submit button twice.
Help would be really really apprecaited