Search code examples
djangodetailview

Django block access to a detailview based on field


I have a detailView/template that has a confidential field (Boolean) and I want the detail page to be only accessible by staff users (or higher). I have currently made it work by adding the following to my template:

  {% if enzymes.confidential == True %}
    {% if user.is_staff %}
      # confidential data is listed here
    {% else %}
      <p>You do not have access to this page</p>
    {% endif %}
  {% else %}
    # non confidential data is listed here
  {% endif %}

However, I want to know if I can't just apply a filter to my view? The view that I use is listed below (including a bit of leftover from what I tried).

class DetailView(generic.DetailView):
    template_name = 'gts/detail.html'
    model = Enzymes

    # The active get_context_data
    def get_context_data(self, **kwargs):
        context = super(DetailView, self).get_context_data(**kwargs)
        enzyme = context['object']
        activities = Activitydiagram.objects.filter(enzymes=enzyme)
        spectras = Spectraimage.objects.filter(enzymes=enzyme)
        enzymeactivities = Enzymeactivity.objects.filter(enzymes=enzyme)
        context['activities'] = activities
        context['spectras'] = spectras
        context['enzymeactivities'] = enzymeactivities
        return context

    # This was my WIP attempt
    """def get_context_data(self, **kwargs):
        context = super(DetailView, self).get_context_data(**kwargs)
        if self.request.user.is_staff:
            enzyme = context['object']
            activities = Activitydiagram.objects.filter(enzymes=enzyme)
            spectras = Spectraimage.objects.filter(enzymes=enzyme)
            enzymeactivities = Enzymeactivity.objects.filter(enzymes=enzyme)
            context['activities'] = activities
            context['spectras'] = spectras
            context['enzymeactivities'] = enzymeactivities
        else:
            # TODO: Load only confidential=False enzymes here
            enzyme = context['object']
            activities = Activitydiagram.objects.filter(enzymes=enzyme)
            spectras = Spectraimage.objects.filter(enzymes=enzyme)
            enzymeactivities = Enzymeactivity.objects.filter(enzymes=enzyme)
            context['activities'] = activities
            context['spectras'] = spectras
            context['enzymeactivities'] = enzymeactivities
        return context"""

Solution

  • A typical approach is to override the get_queryset method, and filter the queryset if the user isn't a staff member. If a non-staff member tries to access a confidential item, they'll get a 404 page.

    class DetailView(generic.DetailView):
        template_name = 'gts/detail.html'
        model = Enzymes
    
        def get_queryset(self):
            queryset = super(DetailView, self).get_queryset()
            if not request.user.is_staff:
                queryset = queryset.filter(confidential=False) 
            return queryset