Создание пользовательских исключений, на которые реагирует Django - PullRequest
15 голосов
/ 19 февраля 2010

Для своего сайта я создал абстрактную модель, которая реализует разрешения на чтение на уровне модели.Эта часть системы завершена и работает правильно.Один из методов, которые предоставляет разрешенная модель, - это is_safe(user), который может вручную проверить, разрешено ли пользователю просматривать эту модель или нет.

Я хотел бы добавить метод с эффектом * 1004.* который может быть вызван на любом экземпляре модели, и вместо возврата логического значения, такого как 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's 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)

Ответы [ 4 ]

10 голосов
/ 19 февраля 2010

Для запрещенной ошибки (403) вы можете вызвать исключение PermissionDenied (из django.core.exceptions).

Для поведения перенаправления не существует встроенного способа справиться с ним так, как выопишите в своем вопросе.Вы можете написать собственное промежуточное ПО, которое будет перехватывать ваше исключение и перенаправлять в process_exception.

5 голосов
/ 18 апреля 2012

Я сделал небольшое промежуточное ПО, которое возвращает то, что возвращает метод render вашего класса 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.

2 голосов
/ 19 апреля 2014

Django раздражает, есть решение для этого:

from annoying.exceptions import Redirect

...
    raise Redirect('/')  # or a url name, etc
1 голос
/ 19 февраля 2010

Вы хотите использовать декораторы для этого.Посмотрите login_required для примера.По сути, декоратор позволит вам проверить проверку безопасности, а затем вернуть HttpResponseRedirect(), если это небезопасно.

Ваш код будет выглядеть примерно так:

@safety_check:
def some_view(request):
    #Do Stuff
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...