Для моего сайта я создал абстрактную модель, которая реализует разрешения на чтение на уровне модели. Эта часть системы завершена и работает правильно. Одним из методов, предоставляемых разрешенной моделью, является 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)