/ / Czy PermissionRequiredMixin i LoginRequiredMixin można połączyć? - django, django-1.9

Czy PermissionRequiredMixin i LoginRequiredMix mogą być połączone? - django, django-1.9

Mam kilku użytkowników, którzy mogą zobaczyć określony widok.

Aby umożliwić użytkownikom logowanie się i składanie skarg przy użyciu pliku 403 Forbidden dla tych użytkowników, którzy nie widzą tego loginu, mogę użyć następujących (jak wyjaśniono tutaj):

@permission_required("polls.can_vote", raise_exception=True)
@login_required
def my_view(request):
...

To rzeczywiście działa zgodnie z oczekiwaniami. Ale wszystkie moje poglądy są poglądami klasowymi. Od Django 1.9 (wreszcie!) Istnieje kilka ładnych miksów do robienia rzeczy, które były możliwe tylko przez dekoratorów. Jednak...

class MyClassView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
raise_exception = <???>
permission_required = "polls.can_vote"
template_name = "poll_vote.html"

to nie działa. Ponieważ raise_exception flaga jest używana przez oba LoginRequiredMixin i PermissionRequiredMixin, Nie mogę go ustawić na nic.

  • gdyby raise_exception jest True, niezalogowany użytkownik otrzymuje plik 403 Forbidden (czego nie chcę).
  • gdyby raise_exception jest Falseczyli użytkownik nie będzie mógł zobaczyć widok, zostanie przekierowany na stronę logowania, która, ponieważ użytkownik jest zalogowany, przekieruje ponownie na tę stronę. Tworzenie niecodziennej pętli przekierowań.

Oczywiście mógłbym zaimplementować własny mixin, który zachowuje się tak, jak się spodziewałem, ale czy jest na to sposób Django w samym widoku? (nie w urls.py)

Odpowiedzi:

6 dla odpowiedzi № 1

W wielu przypadkach oczekiwanym zachowaniem jest podniesienie 403 dla nieuwierzytelnionych użytkowników. Więc tak, potrzebujesz niestandardowego miksu:

class LoggedInPermissionsMixin(PermissionRequiredMixin):
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_authenticated():
return redirect_to_login(self.request.get_full_path(),
self.get_login_url(), self.get_redirect_field_name())
if not self.has_permission():
# We could also use "return self.handle_no_permission()" here
raise PermissionDenied(self.get_permission_denied_message())
return super(LoggedInPermissionsMixin, self).dispatch(request, *args, **kwargs)

2 dla odpowiedzi nr 2

Chciałem dodać komentarz, ale moja reputacja na to nie pozwala. A co z następującymi? Czuję, że poniższe informacje są bardziej czytelne?

Zaktualizowany po komentarzach

Moje rozumowanie jest takie: w zasadzie piszesz zmodyfikowany dispatch od LoginRequiredMixin i po prostu ustaw raise_exception = True. PermissionRequiredMixin będzie raise PermissionDenied gdy nie są spełnione odpowiednie uprawnienia

class LoggedInPermissionsMixin(PermissionRequiredMixin):
raise_exception = True

def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_authenticated():
return redirect_to_login(self.request.get_full_path(),
self.get_login_url(),
self.get_redirect_field_name())
return super(LoggedInPermissionsMixin, self).dispatch(request, *args, **kwargs)

0 dla odpowiedzi № 3

Najprostszym rozwiązaniem wydaje się być niestandardowy zestaw widoków. Coś w tym stylu:

class PermissionsMixin(PermissionRequiredMixin):
def handle_no_permission(self):
self.raise_exception = self.request.user.is_authenticated()
return super(PermissionsMixin, self).handle_no_permission()

Lub po prostu użyj PermissionRequiredMixin jak zwykle i umieść to handle_no_premission do każdego CBV.