2016-01-08 12 views
6

Alcuni utenti hanno la possibilità di vedere una determinata vista.È possibile combinare PermissionRequiredMixin e LoginRequiredMixin?

Per consentire agli utenti di accedere e si lamentano con un 403 Forbidden per quegli utenti che non possono vedere che login, posso utilizzare il seguente (come spiegato here):

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

Questo funziona davvero come previsto. Ma tutte le mie opinioni sono viste basate su classi. Dal momento che Django 1.9 (finalmente!) Ci sono un bel po 'di mixin per fare cose che erano possibili solo attraverso i decoratori. Tuttavia ...

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

questo non funziona. Poiché il flag raise_exception viene utilizzato da entrambi LoginRequiredMixin e PermissionRequiredMixin, non riesco a impostare nulla.

  • se raise_exception è True, un utente che non è connesso in riceve un 403 Forbidden (che io non voglio).
  • se raise_exception è False, un utente che è non permesso di vedere la vista, verrà reindirizzato alla pagina di login, che, perché l'utente è collegato, sarà reindirizzare di nuovo alla pagina. Creare un ciclo di reindirizzamento di fantasia non proprio allettante.

Ovviamente potrei implementare il mio mixin che si comporta come previsto, ma c'è qualche modo Django di farlo nella vista stessa? (non nel urls.py)

risposta

5

Per molti casi il sollevamento di 403 per utenti non autenticati è il comportamento previsto. Quindi sì, hai bisogno di un mixin personalizzato:

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) 
+0

Ok, capisco. Grazie, solo una domanda: il 'LoginRequiredMixin' non è richiesto, non è vero? C'è qualche ragione per cui l'hai messo lì? – MariusSiuram

+0

@MariusSiuram, hai assolutamente ragione. Oltre a ciò, il codice aveva un difetto logico, che è (si spera) risolto ora. –

+0

Vedo, non mi sono reso conto di situazioni in cui un utente non registrato aveva qualche permesso (era quello il difetto logico?), Ma io (penso che io) comprendo appieno il Mixin. Grazie. – MariusSiuram

2

Volevo aggiungere un commento, ma la mia reputazione non lo consente. Che ne dici di quanto segue? Sento che il sotto è più leggibile?

aggiornato dopo commenti

Il mio ragionamento è: Che, fondamentalmente, scrivere modificato dispatch da LoginRequiredMixin e appena impostato raise_exception = True. PermissionRequiredMixin sarà raise PermissionDenied quando autorizzazioni corrette non sono soddisfatte

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

Mi piace questa svolta. Usando il metodo 'handle_no_permission', ci si sente più pitoni e naturali. In retrospettiva, sembra una scelta ovvia del metodo. – MariusSiuram

+1

Attesa ... non è equivalente a mettere 'raise_exception = True'? – MariusSiuram

+0

:) Buon punto. Refactoring della community in corso qui, mi piace! –

0

soluzione più semplice sembra essere un mixin visualizzazione personalizzata. Qualcosa del genere:

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

Oppure, basta usare PermissionRequiredMixin come al solito e mettere questo handle_no_premission ad ogni CBV.

Problemi correlati