14

I am using django's PermissionDenied to render 403.html whenever the user is not allowed to access any page.

There are whole lot of pages, of different type, for example, Product page, User Page, User Contact information, Owner Information.

I would like to add the custom message with PermissionDenied, that would tell the user exactly why he can not view this page. I would like to add the following dynamic message to the 403.html.

You have are trying to `View a Product (id:3094384)` while having a `Trail` account. You are not authorized to view this product. 

And

 You have are trying to `View a Customer (id:48)` which is Private. You are not authorized to view this User. 

and so on.

here is my code

elif role.id == Project.ROLE_SALES and not project.sales_person_id == user_id:
            raise PermissionDenied

html

<body class="error-page">

<!--  content -->
<section>
    <div class="error403">
        <h1>403</h1>
    </div>
    <p class="description">Oops! Request forbidden...</p>

    <p>Sorry, it appears the page you were looking for is forbidden and not accessible. If the problem persists, please
        contact web Administrator.</p>


# HERE I WANT TO SHOW DYNAMIC MESSAGE. 



    <a href="{{ request.META.HTTP_REFERER }}" class="btn btn-danger403 btn-primary btn-large" >
        Go Back </a>
{{ except }}
</section>



<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.js' %}"></script>
</body>

Possibility

raise PermissionDenied("Custom message")

Or

Pass a context to PermissionDenied?

Suggestions.

A.J.
  • 8,557
  • 11
  • 61
  • 89

5 Answers5

27

This answer is probably arriving very late for you. But here it is. You can use this in your Django code:

raise PermissionDenied("Custom message")

And then display the custom message using below snippet in the 403.html template:

{% if exception %}
  <p>{{ exception }}</p>
{% else %}
  <p>Static generic message</p>
{% endif %}

The message string passed to 'PermissionDenied' is available in template context as explained in Django documentation - https://docs.djangoproject.com/en/1.10/ref/views/#http-forbidden-view

kvrao127
  • 385
  • 3
  • 8
  • I am facing a similar dilemma. Could you check my question [here](https://stackoverflow.com/questions/63167348/how-to-display-permission-denied-message-in-custom-403-html-page-in-django)? – shaan Jul 30 '20 at 16:32
2

I came across the same issue and resolved it using the Django messages framework to pass a custom message to the template.

https://docs.djangoproject.com/en/1.8/ref/contrib/messages/

My specific example:

from django.contrib import messages
...
messages.error(request, 'The submission deadline has passed.')
raise PermissionDenied

The messages can then be output in the template as described in the documentation.

Grant Anderson
  • 322
  • 1
  • 8
1

You can try like this:

class SomeException(Exception):
    message = 'An error occurred.'

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return repr(self.message)

#usage
 raise SomeException("Hello, you have an exception here")

Another way of sending a message to template is like:

if not request.user.is_staff: #or your condition
   context['flash_message']= "permission error occurred"
   retrun render_to_response('template.html', context)

# template
<!-- I am using bootstrap here -->
<div class="alert alert-{{ flash_message_type }} flash_message hide">
    {{ flash_message | safe }}
</div>

<script>
...
if($.trim($(".flash_message").html()) != ''){
        $(".flash_message").slideDown();
        setTimeout(function(){
            $(".flash_message").slideUp();
        }, 5000);
    };
</script>
ruddra
  • 50,746
  • 7
  • 78
  • 101
  • This is not what i am looking for. I want to redirect user to the new page that only shows error. PremissionDenied always shows one page 403.html but i want to show custom message. – A.J. Jan 06 '15 at 11:48
1

If you are using class based views (CBV), or anything that extends the AccessMixin, either set the permission_denied_message attribute, or override the get_permission_denied_message method.

Example:

from django.conf import settings

class MyView(ListView):
    permission_denied_message = 'Hooo!'

    def get_permission_denied_message(self):
        perms = self.get_permission_required()
        if settings.DEBUG:
            for perm in perms:
                if not self.request.user.has_perm(perm):
                    return 'Permission denied: ' + str(perm)
        return ''

and then, in your template:

{% if exception and debug %}
    <h3 class="font-bold">{{ exception }}</h3>
{% endif %}
mehmet
  • 7,720
  • 5
  • 42
  • 48
0

Same issue here.

In django 1.9 we have this built in. In earliest django version we can use sys.exc_info(), so the next step is just reuse whole default permission_denied handler to add our exception.

# urls.py
...
handler403 = 'project.views.errors.permission_denied'
...

# views/errors.py
import sys

from django import http
from django.template import Context, TemplateDoesNotExist, loader
from django.views.decorators.csrf import requires_csrf_token


@requires_csrf_token
def permission_denied(request, template_name='403.html'):
    _, value, _ = sys.exc_info()

    try:
        template = loader.get_template(template_name)
    except TemplateDoesNotExist:
        return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html')
    return http.HttpResponseForbidden(
        template.render(request=request, context={'exception': force_text(value)})
    )

# templates/403.html
...
{{ exception }}
...
proxy
  • 469
  • 5
  • 12