简体   繁体   English

Django - 用户只能投票一次

[英]Django - User should only able to vote once

i want that a user is only able to vote once for a category-request but somehow i get the following error and i dont know how to "properly" call the instance at that point:我希望用户只能为类别请求投票一次,但不知何故我收到以下错误,我不知道此时如何“正确”调用实例:

Cannot assign "1": "CategoryRequests_Voter.voted" must be a "CategoryRequests" instance.无法分配“1”:“CategoryRequests_Voter.voted”必须是“CategoryRequests”实例。

models.py模型.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视图.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)

Thanks in advance提前致谢

You need to fix the voted argument to just category_request , not its primary key, like:您需要将voted参数修复为仅category_request ,而不是其主键,例如:

CategoryRequests_Voter.objects.create(voter=request.user, voted=category_request)

You can however improve your model and view to improve consistency, and elegance.但是,您可以改进模型和视图以提高一致性和优雅度。 In order to prevent a User from voting twice or more, you can prevent creating creating a CategoryRequest_Voter object twice for the same voter and voted , by using a unique_together constraint:为了防止User投票两次或更多次,您可以通过使用unique_together约束来防止为同一个voter创建两次CategoryRequest_Voter对象并voted

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

Furthermore we can use a get_or_create and thus make only a single fetch from the database.此外,我们可以使用get_or_create从而只从数据库中进行一次提取。 Typically a view that changes data should do this with a POST request, not with a GET.通常,更改数据的视图应该使用 POST 请求而不是 GET 来执行此操作。 GET requests are not supposed to have side effects. 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)

It might be worth to count the number of CategoryRequest_Voter s, instead of incrementing the vote count, since it is possible that, for example due to deletion of User s, or votes, eventually the number of votes is no longer in harmony with the number of CategoryRequests_Voter s for that CategoryRequests object.可能值得计算CategoryRequest_Voter的数量,而不是增加投票计数,因为有可能,例如由于删除User或投票,最终投票数量不再与数量一致的CategoryRequests_Voter ■对于CategoryRequests对象。

Perhaps counting the number of objects is not that efficient per vote, but you could make a task that runs every now and then, and thus calculate:也许每次投票计算对象的数量并不是那么有效,但是您可以创建一个不时运行的任务,从而计算:

CategoryRequests_Voter.objects.filter(voted=category_request).count()

to count the number of CategoryRequests_Voter for the given category_request .计算给定category_requestCategoryRequests_Voter的数量。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM