'Django - Form not saving when submitted

Good afternoon all,

One of my form does not seem to save when submitted. I cannot see why, in particular as I have a similar form working just fine using the same code.

For some reason it work just fine using the admin panel.

My assumption is that I am missing something that tells the form it needs to be saved. But cannot find what.

Any ideas?

Models

RATING=(
    (1,'1'),
    (2,'2'),
    (3,'3'),
    (4,'4'),
    (5,'5'),
)
class ProductReview(models.Model):
    user=models.ForeignKey(User, on_delete=models.CASCADE)
    product=models.ForeignKey(Product,related_name="comments", on_delete=models.CASCADE)
    review_text=models.TextField(max_length=250)
    review_rating=models.IntegerField(choices=RATING,max_length=150, default=0)
    date_added = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)

Views

def add_review(request, product_id):
    product = Product.objects.get(pk=product_id)
    form = ReviewAdd(request.POST or None, instance=product) #instance=product (populate field with existing information)
    if form.is_valid():
        form.save()
        return redirect('product')
    return render(request, 'main/add_review.html',{'form':form}) 

URL

from django.urls import path
from . import views

urlpatterns = [
...
path('product/add_review/<product_id>', views.add_review,name="add_review"),
]

Forms

class ReviewAdd(forms.ModelForm):
    class Meta:
        model = ProductReview
        fields = ('review_text', 'review_rating')
        labels ={
            'review_text': '',
            'review_rating': '',
                }

        widgets = {
                    'review_text': forms.TextInput(attrs={'class':'form-control', 'placeholder':'Enter Review'}),
                    }

Admin

from django.contrib import admin
from .models import Venue, User, Product, ProductReview
from django.urls import path


admin.site.register(User)
admin.site.register(ProductReview)


class ProductReview(admin.ModelAdmin):
    list_display=['user','product','review_text','get_review_rating']

HTML Page

{% extends 'main/base.html' %}
{% load crispy_forms_tags %}

{% block title %} 
{% endblock %}

{% block content %}
    <center>
        <h1>Add ReviewTo Database</h1>
        <br/><br/>
        
        {% if submitted %}
            Success!
        {% else %}
                <form action="" method="post">
                {% csrf_token %}
                {{ form|crispy }}
                <input type="Submit" value="Submit" class="btn btn-secondary">
                </form>
        {% endif %}
    </center>
{% endblock %}


Solution 1:[1]

I detect 2 fixes

On your url, the parameter product_id might need the type of data it will going to receive

path('product/add_review/<int:product_id>', views.add_review,name="add_review"),

And in your view, you are sending an instance, and no data for a new rating. In your view:


from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404


@login_required
def add_review(request, product_id):
    product = get_object_or_404(Product, pk=product_id)
    form = ReviewAdd(request.POST or None)
    if form.is_valid():
        new_rating = form.save(commit=False)
        new_rating.product = product
        new_rating.user = request.user
        new_rating.save()
        return redirect('product')
    return render(request, 'main/add_review.html',{'form':form})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alejandro Franco