【问题标题】:Django - User should only able to vote onceDjango - 用户只能投票一次
【发布时间】:2019-06-07 09:03:52
【问题描述】:

我希望用户只能为类别请求投票一次,但不知何故我收到以下错误,我不知道如何“正确”调用该实例:

不能分配“1”:“CategoryRequests_Voter.voted”必须是 “CategoryRequests”实例。

models.py

# Category Requests Model
class CategoryRequests(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    ....

# Vote(s) of Category Requests Model
class CategoryRequests_Voter(models.Model):
    voter = models.ForeignKey(User, on_delete=models.CASCADE)
    voted = models.ForeignKey(CategoryRequests, on_delete=models.CASCADE)
    published_date = models.DateField(auto_now_add=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

views.py

def category_request_up_vote (request, pk):
    category_request = get_object_or_404(CategoryRequests, pk=pk)
    if request.method == 'GET':
        if CategoryRequests_Voter.objects.filter(voter=request.user, voted=category_request.pk).exists():
            messages.error(request, 'You already voted for this request.')
        else:
            category_request.up_vote = F('up_vote') + 1
            category_request.save()
            CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request.pk)
            messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
            return redirect('category_request_detail', pk=category_request.pk)
    else:
        messages.error(request, 'Uuups, something went wrong, please try again.')
        return redirect('category_request_detail', pk=category_request.pk)

提前致谢

【问题讨论】:

  • voter=request.user, voted=category_request.pk 更改为voter=request.user, voted=category_request(这样做不仅对.create(..) 有意义,对.exists(..) 也是如此。
  • 谢谢!工作正常

标签: python django vote


【解决方案1】:

您需要将voted 参数仅修复为category_request,而不是其主键,例如:

CategoryRequests_Voter.objects.create(voter=request.user, voted=<b>category_request</b>)

但是,您可以改进模型和视图以提高一致性和优雅性。为了防止User 投票两次或更多次,您可以通过使用unique_together 约束来防止为相同 votervoted 创建两次CategoryRequest_Voter 对象:

class CategoryRequests_Voter(models.Model):
    voter = models.ForeignKey(User, on_delete=models.CASCADE)
    voted = models.ForeignKey(CategoryRequests, on_delete=models.CASCADE)
    published_date = models.DateField(auto_now_add=True, null=True)

    class Meta:
        unique_together = ('voter', 'voted')

    def publish(self):
        self.published_date = timezone.now()
        self.save()

此外,我们可以使用get_or_create,从而只从数据库中提取一次。通常,更改数据的视图应该使用 POST 请求而不是 GET 来执行此操作。 GET 请求不应该有副作用。

def category_request_up_vote (request, pk):
    category_request = get_object_or_404(CategoryRequests, pk=pk)
    if request.method == 'POST':
        __, created = CategoryRequests_Voter.objects.get_or_create(
            voter=request.user,
            voted=category_request
        )
        if created:
            category_request.up_vote = F('up_vote') + 1
            category_request.save()
            messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
        else:
            messages.error(request, 'You already voted for this request.')
    else:
        messages.error(request, 'Uuups, something went wrong, please try again.')
    return redirect('category_request_detail', pk=category_request.pk)

可能值得计算CategoryRequest_Voters 的数量,而不是增加投票数,因为有可能,例如由于删除Users 或投票,最终投票数是不再与该 CategoryRequests 对象的 CategoryRequests_Voters 数量一致。

也许计算对象的数量并不是那么有效的per票,但是您可以创建一个不时运行的任务,从而计算:

CategoryRequests_Voter.objects.filter(voted=category_request)<b>.count()</b>

计算给定category_requestCategoryRequests_Voter 的数量。

【讨论】:

  • 我尝试实现您的优化,但似乎我总是以最后一个 else 语句结束
【解决方案2】:
def category_request_up_vote (request, pk):
    category_request = get_object_or_404(CategoryRequests, pk=pk)
    try:
        if request.method == 'GET':
            if CategoryRequests_Voter.objects.filter(voter=request.user, voted=category_request).exists():
                messages.error(request, 'You already voted for this request.')
                return redirect('category_request_detail', pk=category_request.pk)
            else:
                category_request.up_vote = F('up_vote') + 1
                category_request.save()
                CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request)
                messages.success(request, 'You have successfully Provided an Up-Vote for this Request')
                return redirect('category_request_detail', pk=category_request.pk)
        else:
            messages.error(request, 'Uuups, something went wrong, please try again.')
            return redirect('category_request_detail', pk=category_request.pk)
    except:
        messages.error(request, 'Uuups, something went wrong, please try again.')
        return redirect('category_request_detail', pk=category_request.pk)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多