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

时间:2018-06-18 15:10:41

标签: django django-models django-views django-permissions

我的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')
            }) 

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

2 个答案:

答案 0 :(得分:2)

您应该使用EligibleVoter作为直通字段,将Poll中的多对多字段添加到用户:

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

现在你可以做到:

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

答案 1 :(得分:2)

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
            eligiblevoters__user=self.request.user,
            pub_date__lte=timezone.now()
        )

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

这是如何工作的

查询的工作原理如下。通过从ForeignKey定义EligibleVotersUser(名为user),然后Django反向创建隐式关系:您可以查询使用User.eligblevoters_set获取相关的EligableVoters查询集。我们也可以使用elgiblevoters进行过滤。

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

因此,如果没有此类Post,则我们无法获得Poll所请求的id

在未找到对象的情况下渲染

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

from django.http import Http404

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)
        except Http404:
            return render(request, 'app/template_not_found.html', {})

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