Django投票系统:防止重复投票

时间:2015-12-14 03:57:18

标签: python html django

我正在创建一个使用Django的论坛。我有很多工作要做,包括投票。我无法弄清楚的一件事就是防止重复投票。我怎么能让这个工作?有没有办法可以使用JS在HTML中创建一个只能发送一次的表单?或者我是否必须在视图中执行一些特殊操作?这是我在模板中的代码:

{% for comment in comments %}
<div class="ui container segment">
    <img class="ui avatar image" src="/{{ comment.by.userprofile.img.url }}"><b>{{ comment.by }}</b>
    <p style="font-size: 20px">{{ comment.body }}</p>
    <form action="" method="post">
        {% csrf_token %}
        <input type="submit" value="Thumbs up" class="ui small blue button">
        <i class="thumbs up outline icon"></i>
        <input type="hidden" value="{{ comment.id }}" name="comment">
    </form>
    <span>{{ comment.points }}</span>
</div>
{% endfor %}

我在视图中的代码:

elif request.method == 'POST':
    print request.POST
    if 'body' in request.POST.keys():
        reply = ForumReply.objects.create(by=request.user, reply_to=post, body=request.POST['body'])
        reply.save()
        notification = Notification.objects.create(to=post.by, message='Your post "' + post.title + '" received a new reply')
        notification.save()
    if 'comment' in request.POST.keys():
        comment = post.forumreply_set.filter(pk=request.POST['comment'])[0]
        comment.points += 1
        comment.save()

我的模特(按照乐高风暴的要求)

class ForumReply(models.Model):
    by = models.ForeignKey(User)
    reply_to = models.ForeignKey(ForumPost)
    body = models.TextField()
    created = models.DateField(default=timezone.now())
    points = models.IntegerField(default=0)

2 个答案:

答案 0 :(得分:2)

你肯定想防止在服务器上进行双重投票,而不是在javascript中。否则,有人可能会写一个恶意脚本来搞乱您的投票系统数据库。有一些解决方案,让我们开始最简单的方法:

1)在服务器上,您需要检查用户之前是否已投票。添加如下内容:

voted_before = len(ForumReply.objects.filter(by=request.user, reply_to=post)[:1]) > 1

然后,您可以在添加新投票之前检查voted_before是否为True

2)然而,第一个解决方案受竞争条件影响。如果一个用户同时投了两次相同的投票,那么服务器可能无法检测到它之前投票。

为了避免竞争条件,您只使用一台服务器,并且只运行一个django进程,您可以使用threading.Lock来阻止多次检查。

3)如果您使用多个服务器和分布式数据库,则需要使用称为事务的东西。这些通常是特定于数据库的。

答案 1 :(得分:0)

好的,我找到了解决问题的方法,但我确信它不是最优雅的。但是,它可以正常运行。

所以,我所做的是在UserProfile上创建一个ManyToManyField。所有用户都与UserProfile具有OneToOne关系。

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    bio = models.TextField(default='This user hasn\'t said anything about themselves yet')
    img = models.ImageField(upload_to=gen_name, default="static/imgs/default/default_user.jpg")
    points = models.IntegerField(default=0)
    liked_replies = models.ManyToManyField(ForumReply)

每当用户喜欢回复时,都会将其保存到ManyToManyField。然后在视图中,它会检查该评论是否在当前用户的已回复列表中,如果是,则不会添加投票。

if 'comment' in request.POST.keys():
    comment = post.forumreply_set.filter(pk=request.POST['comment'])[0]
    if not comment in request.user.userprofile.liked_replies.all():
        print 'liked'
        comment.points += 1
        comment.save()
        request.user.userprofile.liked_replies.add(comment)
        request.user.userprofile.save()