Django 星级评分系统 AJAX 和 JavaScript

Posted

技术标签:

【中文标题】Django 星级评分系统 AJAX 和 JavaScript【英文标题】:Django star rating system AJAX and JavaScript 【发布时间】:2022-01-06 05:59:12 【问题描述】:

我正在尝试在 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

对我来说,问题出在网址的某个地方。如何解决这个问题?

screenshot

【问题讨论】:

【参考方案1】:

您的问题不在于网址,而在于查询obj = Rating.objects.get(id=element_id)。没有 id=element_id 的评级对象。

要调试,请检查 Rating id 是否从 RatingView -> Template -> JS -> RateView 正确传递。

例如,在 RatingView 中,obj 可能是空的。

【讨论】:

即使在这里obj = Rating.objects.filter(score = 0).order_by("?").First() 也不正确。你能告诉我如何将评分与博客文章相关联吗?我需要将帖子上的信息发送到RatingView

以上是关于Django 星级评分系统 AJAX 和 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

星级评分系统 - 悬停+点击问题

星级评分系统,给予独一无二的评分

ASP 更新面板打破了 jQuery 星级评分系统

如何在 Spring Boot 中使用 JavaScript、jQuery 的 Ajax 成功时将数字转化为星级?

改进模板标签的功能 - Django

编辑评论时如何让星级评分保留价值?