Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TemplateView in Django with custom status code

I have internal account privacy permissions in my project(e.g. only friends can see profile page of user) and I want to have custom permission denied page for this case. Is there any way to return response from TemplateView with status code equals 403?

Something like this:

class PrivacyDeniedView(TempateView):
    template_name = '...'
    status_code = 403

I can do this by override dispatch() but maybe Django has out of the box solution

Answer: it looks like there no generic solution. The best way is proposed by @alecxe, but encapsulated in Mixin as @FoxMaSk proposed

like image 809
kharandziuk Avatar asked Sep 11 '13 12:09

kharandziuk


4 Answers

One option is to override get() method of your TemplateView class:

def get(self, request, *args, **kwargs):
    context = self.get_context_data(**kwargs)
    return self.render_to_response(context, status=403)
like image 160
alecxe Avatar answered Nov 01 '22 05:11

alecxe


You can subclass TemplateResponse and set response_class in the view. For example:

from django.template.response import TemplateResponse

class TemplateResponseForbidden(TemplateResponse):
    status_code = 403

class PrivacyDeniedView(TemplateView):
    response_class = TemplateResponseForbidden
    ...

This approach is more DRY than the other suggestions because you don't need to copy and paste any code from TemplateView (e.g. the call to render_to_string()).

I tested this in Django 1.6.

like image 32
cjerdonek Avatar answered Nov 01 '22 06:11

cjerdonek


While alecxe's answer works, I strongly suggest you to avoid overriding get; it's easy to forget that CBV's can have other methods like post, and if you're overriding one you should do the same for the others.

In fact, there is no need to create a separate view just to display a 403 error; Django already has django.http.HttpResponseForbidden. So instead of redirecting to your view, just do something along the lines of:

if not user.has_permission(): # or however you check the permission
    return HttpResponseForbidden()

Or, if you want to render a particular template:

if not user.has_permission(): # or however you check the permission
    return HttpResponseForbidden(loader.render_to_string("403.html"))
like image 3
Berislav Lopac Avatar answered Nov 01 '22 07:11

Berislav Lopac


I just encountered this problem as well. My goal was to be able to specify the status code in urls.py, e.g.:

url(r'^login/error/?$', TemplateView.as_view(template_name='auth/login_error.html', status=503), name='login_error'),

So using the previous answers in this thread as idea starters, I came up with the following solution:

class TemplateView(django.views.generic.TemplateView):

    status = 200

    def render_to_response(self, context, **response_kwargs):

        response_kwargs['status'] = self.status

        return super(TemplateView, self).render_to_response(context, **response_kwargs)
like image 2
jacob Avatar answered Nov 01 '22 05:11

jacob