2015-12-14 192 views
0

我正在創建一個使用Django的論壇。我有很多工作,包括投票。我無法弄清楚的一件事是防止重複投票。我怎麼能得到這個工作?有沒有一種方法可以使用JS在HTML中只能發送一次的表單?或者我需要在視圖中執行一些特殊操作?這是我的模板代碼:Django投票系統:防止重複投票

{% 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() 

我的模型(每樂高Stormtroopr的要求)

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

向我們展示您用來存儲投票的模型? –

回答

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() 
+0

這正是我要做的。你爲什麼覺得它不雅? –

+0

不確定。在網絡開發方面我沒有太多經驗,所以如果我找到問題的解決方案,我不一定會認爲這是一個好的解決方案。 –

2

你一定要防止服務器上的雙重投票,而不是在JavaScript中。否則有人會寫一個惡意腳本來搞亂你的投票系統數據庫。有幾個解決方案,讓我們開始智慧最簡單:

1)在服務器上,你需要檢查用戶之前是否投票過。添加類似以下內容:

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

然後你就可以檢查是否voted_beforeTrue添加新的表決之前。

2)然而,第一個解決方案是受競賽條件。如果同時使用一個用戶投了兩次相同的投票,那麼服務器可能無法檢測到它投票過。

爲了避免競爭條件,您只使用一臺服務器,並且只有一個django進程正在運行,您可以使用threading.Lock來防止多次發生檢查。

3)如果你使用多個服務器和分佈式數據庫,你需要使用一些稱爲事務的東西。這些通常是數據庫特定的。

+0

您提供的代碼不起作用。 –