根据现有模型限制用户查看

Restrict User from view based on existing model

我的 views.py 中有一些非常简单的观点。

class IndexView(generic.ListView):
    template_name = 'voting/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """
        Return the last five published questions (not including those set to be
        published in the future).
        """    
        return Poll.objects.filter(
            pub_date__lte=timezone.now()
        ).order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Poll
    template_name = 'voting/detail.html'
    context_object_name = 'question'

    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Poll.objects.filter(pub_date__lte=timezone.now())


class ResultsView(generic.DetailView):
    model = Poll
    template_name = 'voting/results.html'
    context_object_name = 'question'

我还创建了一个 model 存储哪些用户被邀请参加哪些投票以及其他一些数据。

class EligibleVoters(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    poll = models.ForeignKey(Poll, on_delete=models.CASCADE, null=True)
    encrypted_keypart = models.BinaryField(max_length=200, blank=True)
    decrypted_keypart = models.BinaryField(max_length=200, blank=True)
    class Meta:
        unique_together = ["user", "poll"]

我想限制未受邀参加投票的用户查看任何这些投票。

我认为我想为每个视图做的是这样的事情,但我不确定这是否是正确的方法。

class DetailView(generic.DetailView):
    model = Poll
    template_name = 'voting/detail.html'
    context_object_name = 'question'

    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        if EligibleVoters.objects.filter(poll=Poll.objects.id, user=self.request.user.id).exists():
            return Poll.objects.filter(pub_date__lte=timezone.now())
        else:
            return render('voting/somethingsomething.html')
            }) 

我应该以这种方式限制对特定民意调查的访问吗?此外,上面的代码并没有真正起作用并给出了一些错误,但我不确定我是否应该继续并尝试以这种方式修复它。

您应该从 Poll 到 User 添加一个多对多字段,使用 EligibleVoter 作为直通字段:

eligible_users = models.ManyToManyField('User', through='EligibleVoter')

现在您可以:

return Poll.objects.filter(eligible_users=self.request.user, pub_date__lte=timezone.now())

过滤 eligblevoters

上的查询集

get_queryset渲染输出,它只产生一个查询集。

不过,我们可以通过添加额外的过滤来使用它来限制访问:

class DetailView(generic.DetailView):
    model = Poll
    template_name = 'voting/detail.html'
    context_object_name = 'question'

    def get_queryset(self):
        return super(DetailView, self).get_queryset().filter
            <b>eligiblevoters__user=self.request.user</b>,
            pub_date__lte=timezone.now()
        )

在其他视图中应使用类似的方法。

这是如何工作的

查询工作如下。通过定义从 EligibleVotersUserForeignKey(命名为 user),然后 Django 反向创建一个 implicit 关系:你可以例如使用 User.eligblevoters_set 查询以获得相关的 EligableVoters 查询集。我们还可以使用 elgiblevoters.

对其进行过滤

因此我们添加了两个额外的过滤条件:pub_date__lte=timezone.now() 用于过滤之前发布的帖子(现在包括在内),以及 eligiblevoters__user=self.request.user。这意味着我们添加了一个约束,即 至少 相关 eligablevoters 之一应该具有 user self.request.user(此特定会话的用户).

所以如果没有这样的Post,那么我们就无法得到Poll和请求的id

渲染以防找不到对象

我们还可以在找不到对象的情况下呈现页面,例如通过使用 try-exceptHttp404 修补 .get(..) 函数,然后呈现特定页面,例如:

<b>from django.http import Http404</b>

class DetailView(generic.DetailView):
    model = Poll
    template_name = 'voting/detail.html'
    context_object_name = 'question'

    def get_queryset(self):
        return super(DetailView, self).get_queryset().filter
            eligiblevoters__user=self.request.user,
            pub_date__lte=timezone.now()
        )

    def get(request, *args, **kwargs):
        try:
            return super(DetailView, self).get(request, *args, **kwargs)
        <b>except Http404:
            return render(request, 'app/template_not_found.html', {})</b>

所以这里我们渲染一个(可能是不同的模板),这里有一个空的上下文,当然你可以让它更高级。