Currently, I am in the process of integrating a star rating system into my Django website.
After some research, I came across a star design that I really like on this page: https://www.w3schools.com/howto/howto_css_star_rating.asp
My knowledge of JavaScript, AJAX, and Django is limited at the moment. I'm looking for guidance on how to incorporate the star ratings from the provided example using AJAX and Django to allow database updates without requiring a page refresh when users select a rating.
Additionally, it's crucial that each user can only vote once, meaning they should not be able to rate a page multiple times. To achieve this, an IP check must be implemented. I find the code confusing and need assistance with it.
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>'
}
})
})
}))
}
And regarding the error message:
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
I suspect the issue lies in the URL configuration. Any suggestions on how to resolve this problem?