PermissionDenied

Исключение PermissionDenied относится к модулю django.core.exceptions и используется для сигнализации о том, что текущий пользователь не имеет необходимых прав доступа для выполнения операции. Это исключение автоматически обрабатывается Django и приводит к возврату клиенту HTTP-ответа со статусом 403 (Forbidden). В отличие от исключения Http404, которое говорит о том, что ресурс не найден, PermissionDenied указывает на то, что ресурс существует, но недоступен для данного пользователя.

Исключение принимает один необязательный аргумент - строку с сообщением об ошибке, которая будет передана в ответ. В большинстве случаев это сообщение игнорируется, но может быть полезно для отладки или при кастомной обработке исключений. Исключение можно выбрасывать в любом месте кода, где выполняется проверка прав доступа: в представлениях, в методах моделей, в миксинах для проверки разрешений или в кастомных декораторах. Django также предоставляет встроенные механизмы для автоматического выброса этого исключения, например, декоратор permission_required и миксины для классовых представлений.

При использовании в представлениях, особенно в сочетании с декораторами, исключение PermissionDenied позволяет удобно разделять логику проверки прав и логику обработки данных. Это делает код более чистым и поддерживаемым. Также важно отметить, что исключение можно перехватывать и обрабатывать кастомным образом, например, для перенаправления на страницу входа или для логирования попыток несанкционированного доступа.

Синтаксис

pythonfrom django.core.exceptions import PermissionDenied

raise PermissionDenied("Custom error message")

Пример . Использование в представлении

Проверим, имеет ли пользователь право редактировать статью, и если нет - выбросим исключение:

pythonfrom django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from myapp.models import Article

def edit_article(request, article_id):
  article = get_object_or_404(Article, id=article_id)

  if request.user != article.author:
    raise PermissionDenied("You are not the author of this article")

  # Logic for editing the article
  return render(request, "edit_article.html", {"article": article})

Пример . С декоратором permission_required

Используем встроенный декоратор для проверки наличия конкретного разрешения:

pythonfrom django.contrib.auth.decorators import permission_required
from django.shortcuts import render

@permission_required("myapp.change_article", raise_exception=True)
def publish_article(request, article_id):
  # Logic for publishing the article
  return render(request, "publish_article.html")

Если у пользователя нет разрешения 'myapp.change_article', декоратор автоматически выбросит исключение PermissionDenied.

Пример . В классовых представлениях

Переопределим метод dispatch или используем миксин PermissionRequiredMixin:

pythonfrom django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import UpdateView
from django.core.exceptions import PermissionDenied
from myapp.models import Article

class ArticleUpdateView(PermissionRequiredMixin, UpdateView):
  model = Article
  fields = ["title", "content"]
  permission_required = "myapp.change_article"
  raise_exception = True

class CustomArticleDeleteView(UpdateView):
  model = Article
  fields = ["title"]

  def dispatch(self, request, *args, **kwargs):
    article = self.get_object()
    if request.user != article.author:
      raise PermissionDenied("Only the author can delete this article")
    return super().dispatch(request, *args, **kwargs)

Пример . Кастомная обработка исключения

Переопределим обработчик для возврата кастомной страницы ошибки:

pythonfrom django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.template import loader

def custom_permission_denied_view(request, exception=None):
  template = loader.get_template("errors/403.html")
  context = {"error_message": str(exception) if exception else "Access denied"}
  return HttpResponse(template.render(context, request), status=403)

# In urls.py:
# handler403 = custom_permission_denied_view

Пример . В модели

Проверим права доступа в методе модели перед выполнением операции:

pythonfrom django.core.exceptions import PermissionDenied
from django.db import models
from django.contrib.auth.models import User

class Article(models.Model):
  title = models.CharField(max_length=200)
  content = models.TextField()
  author = models.ForeignKey(User, on_delete=models.CASCADE)
  is_published = models.BooleanField(default=False)

  def publish(self, user):
    if user != self.author and not user.has_perm("myapp.can_publish_article"):
      raise PermissionDenied("User cannot publish this article")
    self.is_published = True
    self.save()

Результат вызова метода для пользователя без прав:

pythonfrom myapp.models import Article
from django.contrib.auth.models import User

article = Article.objects.get(id=1)
user = User.objects.get(username="guest")

try:
  article.publish(user)
except PermissionDenied as e:
  print(str(e))

Результат выполнения кода:

python"User cannot publish this article"

Смотрите также

  • исключение PermissionDenied,
    которое выбрасывается при отсутствии прав доступа
  • исключение Http404,
    которое выбрасывается, когда ресурс не найден
  • исключение ObjectDoesNotExist,
    которое выбрасывается при отсутствии объекта в базе данных
  • исключение ValidationError,
    которое выбрасывается при ошибках валидации данных