我正在创建一个使用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)
答案 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()