Система звездного рейтинга Django AJAX и JavaScript
Я пытаюсь реализовать систему звездного рейтинга на сайте Django.
Я нашел следующее, и мне нравится стиль звезд здесь: https://www.w3schools.com/howto/howto_css_star_rating.asp
В настоящее время имею ограниченное представление о JavaScript, AJAX и Django. Кто-нибудь знает, как использовать звезды в приведенном выше примере в сочетании с AJAX и Django, чтобы можно было обновлять базу данных (модели) без обновления страницы, когда пользователь выбирает оценку?
Также важно, чтобы пользователи могли голосовать только один раз, т.е. им не разрешается оценивать страницу дважды. Для этого должна быть предусмотрена проверка IP. Я запутался в коде и мне нужна помощь.
models.py
:
class Rating(models.Model):
ip = models.CharField(max_length=15)
post = models.ForeignKey(Post, related_name='ratings', on_delete=models.CASCADE)
score = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0),
]
)
def __str__(self):
return str(self.pk)
views.py
:
def RatingView(request):
obj = Rating.objects.filter(score=0).order_by("?").first()
context ={
'object': obj
}
return render(request, 'blog/post_detail.html', context)
# def get_client_ip(self, request):
# x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
# if x_forwarded_for:
# ip = x_forwarded_for.split(',')[0]
# else:
# ip = request.META.get('REMOTE_ADDR')
# return ip
def RateView(request):
if request.method == 'POST':
element_id = int(request.POST.get('element_id'))
val = request.POST.get('val')
print(val)
obj = Rating.objects.get(id=element_id)
obj.score = val
obj.save()
return JsonResponse({'success':'true', 'score': val}, safe=False)
return JsonResponse({'success':'false'})
urls.py
:
urlpatterns = [
path('rate/', views.RateView, name='rate'),
path('<slug:slug>/<slug:post_slug>/', views.PostDetailView.as_view(), name='detail'),
path('<slug:slug>/', views.CategoryView.as_view(), name='category'),
path('', views.HomeView.as_view(), name='home'),
]
html
:
<div class="col text-center">
<form class="rate-form" action="" method="POST" id="{{ object.id }}">
{% csrf_token %}
<button type="submit" class="fa fa-star my-btn" id="first"></button>
<button type="submit" class="fa fa-star my-btn" id="second"></button>
<button type="submit" class="fa fa-star my-btn" id="third"></button>
<button type="submit" class="fa fa-star my-btn" id="fourth"></button>
<button type="submit" class="fa fa-star my-btn" id="fifth"></button>
</form>
<br>
<div id="confirm-box"></div>
</div>
JavaScript
:
// Stars
const one = document.getElementById('first')
const two = document.getElementById('second')
const three = document.getElementById('third')
const four = document.getElementById('fourth')
const five = document.getElementById('fifth')
const form = document.querySelector('.rate-form')
const confirmBox = document.getElementById('confirm-box')
const csrf = document.getElementsByName('csrfmiddlewaretoken')
const handleStarSelect = (size) => {
const children = form.children
console.log(children[0])
for (let i=0; i < children.length; i++) {
if(i <= size) {
children[i].classList.add('checked')
} else {
children[i].classList.remove('checked')
}
}
}
const handleSelect = (selection) => {
switch(selection){
case 'first':{
handleStarSelect(1)
return
}
case 'second':{
handleStarSelect(2)
return
}
case 'third':{
handleStarSelect(3)
return
}
case 'fourth':{
handleStarSelect(4)
return
}
case 'fifth':{
handleStarSelect(5)
return
}
}
}
const getNumericValue = (stringValue) =>{
let numericValue;
if (stringValue === 'first') {
numericValue = 1
}
else if (stringValue === 'second') {
numericValue = 2
}
else if (stringValue === 'third') {
numericValue = 3
}
else if (stringValue === 'fourth') {
numericValue = 4
}
else if (stringValue === 'fifth') {
numericValue = 5
}
else {
numericValue = 0
}
return numericValue
}
if (one) {
const arr = [one, two, three, four, five]
arr.forEach(item=> item.addEventListener('mouseover', event=>{
handleSelect(event.target.id)
}))
arr.forEach(item=> item.addEventListener('click', (event)=>{
const val = event.target.id
console.log(val)
form.addEventListener('submit', e=>{
e.preventDefault()
const id = e.target.id
console.log(id)
const val_num = getNumericValue(val)
$.ajax({
type: 'POST',
url: '/rate/',
data: {
'csrfmiddlewaretoken': csrf[0].value,
'element_id': id,
'val': val_num,
},
success: function(response){
console.log(response)
confirmBox.innerHTML = `<p>Successfully rated with ${response.score}</p>`
},
error: function(error){
console.log(error)
confirmBox.innerHTML = '<p>Oops... Something went wrong...</p>'
}
})
})
}))
}
А вот и сама ошибка:
4
Internal Server Error: /rate/
Traceback (most recent call last):
File "/home/kali/Django/personal_blog/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/kali/Django/personal_blog/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/kali/Django/personal_blog/src/blog/views.py", line 91, in RateView
obj = Rating.objects.get(id=element_id)
File "/home/kali/Django/personal_blog/venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/kali/Django/personal_blog/venv/lib/python3.9/site-packages/django/db/models/query.py", line 435, in get
raise self.model.DoesNotExist(
blog.models.Rating.DoesNotExist: Rating matching query does not exist.
[29/Nov/2021 00:18:19] "POST /rate/ HTTP/1.1" 500 86956
Как по мне, проблема кроется где-то в url. Как решить эту проблему?
Ваша проблема не в url, а в запросе obj = Rating.objects.get(id=element_id)
. Не существует объекта рейтинга с id=element_id.
Для отладки проверьте, правильно ли передается идентификатор рейтинга из RatingView -> Template -> JS -> RateView.
Например, obj может быть пустым в RatingView, для начала.