Создание пользовательских исключений, которые Django реагирует на
Для моего сайта я создал абстрактную модель, которая реализует разрешения на чтение на уровне модели. Эта часть системы завершена и работает правильно. Одним из методов, предоставляемых разрешенной моделью, является is_safe(user)
, который может вручную протестировать, если пользователю разрешено просматривать эту модель или нет.
Мне бы хотелось добавить метод, влияющий на continue_if_safe
, который может быть вызван для любого экземпляра модели, и вместо того, чтобы возвращать логическое значение, например is_safe
, сначала будет проверяться, можно ли просмотреть модель или нет, то в случае False он перенаправляет пользователя либо на страницу входа в систему, если они еще не вошли в систему, либо возвращают ошибку 403, если они вошли в систему.
Идеальное использование:
model = get_object_or_404(Model, slug=slug)
model.continue_if_safe(request.user)
# ... remainder of code to be run if it safe down here ...
Я заглянул в то, как работает get_object_or_404, и он выдает ошибку Http404
, которая, кажется, имеет смысл. Однако проблема заключается в том, что, похоже, не существует эквивалентного перенаправления или 403 ошибки. Какой лучший способ сделать это?
(нерабочий) метод continue_if_safe:
def continue_if_safe(self, user):
if not self.is_safe(user):
if user.is_authenticated():
raise HttpResponseForbidden()
else:
raise HttpResponseRedirect('/account/')
return
Изменить - Решение
Код для окончательного решения, если другие "штабелеры" нуждаются в помощи с этим:
В абстрактной модели:
def continue_if_safe(self, user):
if not self.is_safe(user):
raise PermissionDenied()
return
Представления пойманы промежуточным программным обеспечением:
class PermissionDeniedToLoginMiddleware(object):
def process_exception(self, request, exception):
if type(exception) == PermissionDenied:
if not request.user.is_authenticated():
return HttpResponseRedirect('/account/?next=' + request.path)
return None
Использование в представлении (очень короткое и сладкое):
model = get_object_or_404(Model, slug=slug)
model.continue_if_safe(request.user)
Ответы
Ответ 1
Для запрещенной (403) ошибки вы можете создать исключение PermissionDenied
(от django.core.exceptions
).
Для поведения перенаправления нет встроенного способа справиться с этим так, как вы описываете в своем вопросе. Вы можете написать собственное промежуточное программное обеспечение, которое поймает ваше исключение и перенаправит его в process_exception
.
Ответ 2
Я создал небольшое промежуточное программное обеспечение, которое возвращает все возвращаемые методы рендеринга класса Exception. Теперь вы можете использовать произвольное исключение (с методами визуализации) в любом из ваших представлений.
class ProductNotFound(Exception):
def render(self, request):
return HttpResponse("You could ofcourse use render_to_response or any response object")
pip install -e git+http://github.com/jonasgeiregat/django-excepted.git#egg=django_excepted
И добавьте django_excepted.middleware.ExceptionHandlingMiddleware
к вашему MIDDLEWARE_CLASSES
.
Ответ 3
Django раздражает решение для этого:
from annoying.exceptions import Redirect
...
raise Redirect('/') # or a url name, etc
Ответ 4
Вы хотите использовать декораторы для этого. Посмотрите login_required
для примера. В основном декоратор позволит вам проверить безопасность, а затем вернуться HttpResponseRedirect()
, если это не безопасно.
Ваш код будет выглядеть примерно так:
@safety_check:
def some_view(request):
#Do Stuff