Когда я отправляю свою форму Мой комментарий не сохраняется в базе данных
Я создаю 5-звездочную систему рейтинга, используя django с javascript, и хочу, чтобы пользователь комментировал следующим образом:
я хочу нажать на звезды и вернуть значение, которое является целым числом
вот мои модели:
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})
Несколько заметок:
- Хорошей практикой являются функции в
snake_case
и классы вCamelCase
. - Вам не нужны два поля для получения объекта. Либо используйте
id
илиslug
. Поскольку вы не поделились всеми моделями, я не уверен, чтоslug
также является уникальным, поэтому я просто использовалid
, как обычно. - Убедитесь в наличии
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
.