2015-01-07 9 views
18

Normalmente, utilizzo un metodo dispatch di una vista basata su classi per impostare alcune variabili iniziali o aggiungere una logica basata sulle autorizzazioni dell'utente.Django: una visualizzazione basata su classi con mixin e metodo di invio

Per esempio,

from django.views.generic import FormView 
from braces.views import LoginRequiredMixin 

class GenerateReportView(LoginRequiredMixin, FormView): 
    template_name = 'reporting/reporting_form.html' 
    form_class = ReportForm 

    def get_form(self, form_class): 
     form = form_class(**self.get_form_kwargs()) 
     if not self.request.user.is_superuser: 
      form.fields['report_type'].choices = [ 
       choice for choice in form.fields['report_type'].choices 
       if choice[0] != INVOICE_REPORT 
      ] 
     return form 

Esso funziona come previsto: quando un utente anonimo visita un pagine, il metodo di LoginRequiredMixindispatch si chiama, e poi reindirizza l'utente alla pagina di login.

Ma se voglio aggiungere alcuni permessi per questa vista o impostare alcune variabili iniziali, per esempio,

class GenerateReportView(LoginRequiredMixin, FormView): 

    def dispatch(self, *args, **kwargs): 
     if not (
      self.request.user.is_superuser or 
      self.request.user.is_manager 
     ): 
      raise Http404 
     return super(GenerateReportView, self).dispatch(*args, **kwargs) 

in alcuni casi non funziona, perché dispatch metodi delle mixins, che la vista eredita, non è stato ancora chiamato. Così, per esempio, di essere in grado di chiedere i permessi degli utenti, devo ripetere la convalida da LoginRequiredMixin:

class GenerateReportView(LoginRequiredMixin, FormView): 

    def dispatch(self, *args, **kwargs): 
     if self.request.user.is_authenticated() and not (
      self.request.user.is_superuser or 
      self.request.user.is_manager 
     ): 
      raise Http404 
     return super(GenerateReportView, self).dispatch(*args, **kwargs) 

Questo esempio è semplice, ma a volte ci sono una logica più complessa in un mescolamento: si verifica la presenza di permessi, fa alcuni calcoli e li memorizza in un attributo di classe, ecc.

Per ora lo risolvo copiando del codice dal mixin (come nell'esempio sopra) o copiando il codice dal metodo dispatch della vista ad un altro mixin e ad ereditarlo dopo il primo per eseguirli in ordine (il che non è carino, perché questo nuovo mixin è usato solo da una vista).

Esiste un modo corretto per risolvere questo tipo di problemi?

+0

prima chiamata '' super (GenerateReportView, self) .dispatch (* args, ** kwargs) ''. poi fai il resto del lavoro all'interno della spedizione che stai sovrascrivendo –

+2

@MihaiZamfir Non funzionerà perché, ad esempio, '' LoginRequiredMixin'' restituisce un oggetto '' HttpResponseRedirect'', quindi se lo memorizziamo in una variabile, non eseguirà un reindirizzamento alla vista di accesso finché non restituiremo questa variabile alla fine del metodo '' dispatch''. – vero4ka

+0

ma è possibile verificare se la risposta è un reindirizzamento, quindi continuare con la spedizione –

risposta

3

vorrei scrivere classe personalizzata, che controlla tutte le autorizzazioni

from django.views.generic import FormView 
from braces.views import AccessMixin 

class SuperOrManagerPermissionsMixin(AccessMixin): 
    def dispatch(self, request, *args, **kwargs): 
     if not request.user.is_authenticated(): 
      return self.handle_no_permission(request) 
     if self.user_has_permissions(request): 
      return super(SuperOrManagerPermissionsMixin, self).dispatch(
       request, *args, **kwargs) 
     raise Http404 #or return self.handle_no_permission 

    def user_has_permissions(self, request): 
     return self.request.user.is_superuser or self.request.user.is_manager 

# a bit simplyfied, but with the same redirect for anonymous and logged users 
# without permissions 


class SuperOrManagerPermissionsMixin(AccessMixin): 
    def dispatch(self, request, *args, **kwargs): 
     if self.user_has_permissions(request): 
      return super(SuperOrManagerPermissionsMixin, self).dispatch(
       request, *args, **kwargs) 
     else: 
      return self.handle_no_permission(request) 

    def user_has_permissions(self, request): 
     return request.user.is_authenticated() and (self.request.user.is_superuser 
                or self.request.user.is_manager) 


class GenerateReportView(SuperOrManagerPermissionsMixin, FormView): 
#Remove next two lines, don't need it 
    def dispatch(self, *args, **kwargs): 
     #or put some logic here 
     return super(GenerateReportView, self).dispatch(*args, **kwargs) 

e l'implementazione di classe GenerateReportView (SuperOrManagerPermissionsMixin, FormView) non richiede la sovrascrittura del metodo di spedizione

Se si utilizza il multip l'ereditarietà e una delle classi genitore ha bisogno di qualche miglioramento, è bene migliorarla prima. Mantiene il codice più pulito.

1

Per l'esempio fornito, vorrei utilizzare UserPassesTestMixin da django-braces.

class GenerateReportView(UserPassesTestMixin, FormView): 
    def test_func(self, user): 
     return user.is_superuser or user.is_manager 

Se questo non è adatto per la vostra logica più complicato, quindi la creazione di un mixin separata suona come un approccio OK, in quanto racchiude in sé la logica complicata bene.

EDIT
Come di Django 1.9, l'UserPassesTestMixin è ora incluso in django: https://docs.djangoproject.com/en/1.11/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin

2

questo è un vecchio post ma altre persone potrebbero imbattersi quindi ecco la mia soluzione proposta.

Quando si dice

"[...] Voglio aggiungere alcune autorizzazioni per questa vista o impostare alcune variabili iniziali, ad esempio [...]"

Invece di impostare quelle variabili iniziali nel metodo invio della vostra vista, si potrebbe scrivere un metodo separato per l'impostazione di tali variabili e quindi chiamare tale metodo nel metodo get (e post se necessario) .Sono chiamati dopo la spedizione, quindi l'impostazione delle variabili iniziali non si scontrerà con l'invio nei propri mix. metodo

def set_initial_variables(): 
    self.hey = something 
    return 

def get(blablabla): 
    self.set_initial_variables() 
    return super(blabla, self).get(blabla) 

Questo probabilmente è più pulito di copyi ng e incolla il codice del tuo mixin nella spedizione della tua vista.

Problemi correlati