Когда я отправляю свою форму Мой комментарий не сохраняется в базе данных

Я создаю 5-звездочную систему рейтинга, используя django с javascript, и хочу, чтобы пользователь комментировал следующим образом:template

я хочу нажать на звезды и вернуть значение, которое является целым числом

вот мои модели:

class Review(models.Model):

course = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews')

first_name = models.CharField(max_length=50)

last_name = models.CharField(max_length=50)

rating = models.IntegerField(null=True, validators=[MinValueValidator(1), MaxValueValidator(5)])

comment = models.TextField()

created = models.DateField(auto_now_add=True)

active = models.BooleanField(default=False)

def __str__(self):

    return f'{self.first_name} {self.last_name}

мои взгляды:

@csrf_exempt
def productDetailView(request, id, slug):
    product = get_object_or_404(Product, id=id, slug=slug, available=True)
    new_comment = None
    
    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid():
            new_comment = form.save(commit=False)
            new_comment.course = product
            new_comment.rating = request.POST['rating']
            new_comment.save()
    else:
        form = ReviewForm()
    
    return render(request, 'shop/product_detail.html', {'product': product, 'form': form})

js функция:

$(document).ready(function(){
        $('.rate .rate-item').on('click', function(){
            var value = $(this).data('value');
            $.ajax({
                url: '{{ product.get_absolute_url }}',
                type: 'POST',
                data: {'rating': value},
                success: function(response){
                    alert('Rating saved successfully!');
                }
            });
        });
    });

и мой шаблон:

<form method="post">
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Fast name" }}
</div>
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Last Name"}}
</div>
<div class="rate-label">Your Rating:</div>
<div class="rate">
<div data-value="1" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="2" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="3" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="4" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
<div data-value="5" class="rate-item"><i class="fa fa-star" aria-hidden="true"></i></div>
</form>
<div class="form-singel">
{{ form.first_name|attr:" placeholder:Comment" }}                                                                                               
</div>
<div class="form-singel">
<button type="submit" class="main-btn">Post Comment</button>
</div>

Как мне это исправить?

Вам не нужен AJAX для отдельной отправки значения рейтинга. Вместо этого вы можете использовать JavaScript для обновления значения поля формы rating (при работе с функцией звездных элементов), и отправить его, как только оно будет готово:

forms.py

class ReviewForm(forms.ModelForm):
    class Meta:
        model = Review
        fields = ['first_name', 'last_name', 'comment', 'rating', 'course']
        labels = {
            'rating': '',
            'course': '',
        }
        widgets = {
            'rating': forms.HiddenInput(),
            'course': forms.HiddenInput(),
            'first_name': forms.TextInput(attrs={'placeholder': 'First Name'}),
            'last_name': forms.TextInput(attrs={'placeholder': 'Last Name'}),
            'comment': forms.Textarea(attrs={'placeholder': 'Comment'}),
        }

views.py

def product_detail(request, id, slug=None):
    product = get_object_or_404(Product, id=id, available=True)
    
    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Comment saved successfully")
            # Probably want to redirect somewhere else
            return redirect(reverse('core:product_detail', kwargs={'id': product.id}))

    else:
        form = ReviewForm(initial={'course': product})
    
    return render(request, 'shop/product_detail.html', {'product': product, 'form': form})

Несколько заметок:

  1. Хорошей практикой являются функции в snake_case и классы в CamelCase.
  2. Вам не нужны два поля для получения объекта. Либо используйте id или slug. Поскольку вы не поделились всеми моделями, я не уверен, что slug также является уникальным, поэтому я просто использовал id, как обычно.
  3. Убедитесь в наличии csrftoken в ваших запросах, особенно при модификации базы данных, это вопрос безопасности. Конечно, это также можно использовать его с AJAX.

shop/product_detail.html:

<form method="POST" action="">
    {% csrf_token %}
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            <label for="{{ field_name.label_tag }}">{{ field.label_tag }}</label><br>
            {{ field }}
        </div>
    {% endfor %}
    <div class="rate-label">Your Rating:</div>
    <div id="rate" style="display: flex; flex-flow: row nowrap;">
        <div data-value="1" class="rate-item"><i class="far fa-star" aria-hidden="true"></i></div>
        <div data-value="2" class="rate-item"><i class="far fa-star" aria-hidden="true"></i></div>
        <div data-value="3" class="rate-item"><i class="far fa-star" aria-hidden="true"></i></div>
        <div data-value="4" class="rate-item"><i class="far fa-star" aria-hidden="true"></i></div>
        <div data-value="5" class="rate-item"><i class="far fa-star" aria-hidden="true"></i></div>
    </div>
    <br>
    <input type="submit" value="Post Comment">
</form>

<script>
    const filledStarClass = 'fas fa-star';
    const emptyStarClass = 'far fa-star';

    $('.rate-item').on('click', function(){
        var value = $(this).data('value');
        updateStars(value);
        $('#id_rating').val(value)
    });

    function updateStars(value) {
        var childDivs = $('#rate').children();
        for( i=0; i< value; i++ ) {
            var star = childDivs[i].children[0];
            star.className = filledStarClass;
        }

        if (value < 5) {
            for( i=value; i< childDivs.length; i++ ) {
                var star = childDivs[i].children[0];
                star.className = emptyStarClass;
            }
        }
    }
</script>

В шаблоне основная точка находится в $('#id_rating').val(value), где мы обновляем значение формы на основе элемента звезды data-value.

Вернуться на верх