2012-06-10 11 views
7

Attualmente la mia app Django ha URL protetti dalle funzioni 'permission_required()'.Trova le autorizzazioni necessarie per gli URL di Django senza chiamarli?

Questa funzione viene chiamata in tre modi diversi.

  1. Come decoratore in views.py, con parametri hardcoded.
  2. Come una semplice funzione, con parametro generato automaticamente, in viste generiche basate su classi personalizzate.
  3. Come una funzione che richiama viste in urls.py, con parametri hardcoded.

Ora sto aggiungendo un sistema di menu all'app e ho bisogno di fare in modo che le voci del menu riflettano se l'utente ha il permesso di richiedere l'URL di ogni voce di menu. (O estinguendo o nascondendo le voci.)

Esiste un modo per interrogare le autorizzazioni richieste a un URL senza che richiede l'URL?

L'unica soluzione che ho pensato finora è di sostituire il decoratore con un decoratore "menu_permssion_required()" senza parametri e un hardcoded di tutte le autorizzazioni in una struttura Python. Questo mi sembra un passo indietro, poiché le mie viste generiche basate su classi personalizzate già generano le autorizzazioni necessarie.

Qualche suggerimento su come creare un sistema di menu che rifletta le autorizzazioni dell'URL per l'utente corrente?

+0

I menu con hardcode sempre nei modelli, è semplice e consente menu contestuali con {% estende%}. – jpic

+0

scuse @jplc, non riesco a capire come il tuo commento si riferisce alla domanda. Questo riguarda specificamente le autorizzazioni. Le autorizzazioni sono trasversali, non collegate al prefisso URL o simili. – fadedbee

+0

Puoi controllare i permessi nel modello: https://gist.github.com/25c03f286337c66cc860 Questo è abbastanza standard nei progetti di Django da quello che ho visto, ecco i documenti sul modulo per le django in questione: https: // docs.djangoproject.com/en/1.0/topics/auth/#id6 Tuttavia, il mio punto è che il tempo impiegato per creare un "sistema" per un menu HTML potrebbe essere meglio speso per altre cose. – jpic

risposta

2

Ecco un esempio di come risolvere il problema:

primo luogo, creare un wrapper decoratore da usare al posto di permission_required:

from django.contrib.auth.decorators import login_required, permission_required, user_passes_test 
from django.core.exceptions import PermissionDenied 
from functools import wraps 
from django.utils.decorators import available_attrs 

def require_perms(*perms): 
    def decorator(view_func): 
     view_func.permissions = perms 
     @wraps(view_func, assigned=available_attrs(view_func)) 
     def _wrapped_view(request, *args, **kwargs): 
      for perm in perms: 
       return view_func(request, *args, **kwargs) 
      raise PermissionDenied() 
     return _wrapped_view 
    return decorator 

Quindi, utilizzare per decorare le vostre opinioni:

@require_perms('my_perm',) 
def home(request): 
..... 

Poi, aggiungere un tag da utilizzare per voci di menu:

from django.core.urlresolvers import resolve 

def check_menu_permissions(menu_path, user): 
    view = resolve(menu_path) 
    if hasattr(view.func, "permissions"): 
     permissions = view.func.permissions 
     for perm in permissions: 
      if user.has_perm(perm): 
       return True # Yep, the user can access this url 
      else: 
       return False # Nope, the user cannot access this url 
    return True # or False - depending on what is the default behavior 

E, infine, nei modelli, quando si costruisce la struttura del menu:

<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} /> 

N.B. Non ho testato l'ultima parte con il tag, ma spero che tu abbia avuto l'idea. La cosa magica qui è quella di aggiungere le autorizzazioni a view_func nel decoratore, e quindi è possibile accedervi usando resolment (percorso). Non sono sicuro di come si comporterà in termini di prestazioni, ma dopotutto è solo un'idea.

EDIT: Basta corretto un bug nell'esempio ..

+0

Grazie, mi piace l'idea generale. Ti farò sapere come funziona in pratica prima della fine del mese (scadenza del progetto). – fadedbee

2

Esiste un modo per interrogare le autorizzazioni richieste a un URL senza richiedere l'URL?

User.has_perm() e User.has_module_perms()

Qualche suggerimento su come fare un sistema di menu che riflette le autorizzazioni di URL per l'utente corrente?

Mi piace molto questa domanda, perché riguarda chiunque faccia un sito Web con Django, quindi lo trovo davvero rilevante. L'ho passato anche io e anche il coded a menu "system" nel mio primo progetto di django nel 2008. Ma da allora ho provato Pinax, e una delle (tante) cose che ho imparato dai loro progetti di esempio è che è completamente inutile.

Quindi, non ho alcun suggerimento che vorrei supportare su come creare un "sistema" di menu che rispetti le autorizzazioni dell'utente della richiesta.

Ho un suggerimento su come creare un semplice menu che rispetti le autorizzazioni dell'utente della richiesta, in modo che non sia del tutto estraneo.

  1. Basta fare il vostro menu in semplice HTML, non è come sta andando a cambiare così spesso che deve essere generato. Ciò manterrà anche il codice Python più semplice.

  2. Aggiungi al settings.TEMPLATE_CONTEXT_PROCESSORS: 'django.core.context_processors.PermWrapper'

  3. Utilizzare il {{ perms }} proxy a User.has_perms.

Esempio:

{% if perms.auth %} 
    <li class="divider"></li> 

    {% if perms.auth.change_user %} 
    <li> 
     <a href="{% url admin:auth_user_changelist %}">{% trans 'Users' %}</a> 
    </li> 
    {% endif %} 

    {% if perms.auth.change_group %} 
    <li> 
     <a href="{% url admin:auth_group_changelist %}">{% trans 'User groups' %}</a> 
    </li> 
    {% endif %} 

{% endif %} 
{# etc, etC#} 

Ecco come io continuo navigazione semplice, stupido e fuori del modo. Ma includo sempre lo an autocomplete non lontano dai menu per consentire all'utente di navigare facilmente in qualsiasi pagina di dettaglio. Quindi, questo è tutto ciò che so sulla navigazione nei progetti di Django, sono ansioso di leggere altre risposte!

1

ho avuto un problema simile, ma è andato un po 'più profonda. Invece di solo autorizzazioni, volevo anche altri test basati sull'utente con il coperchio (ad esempio, is_staff o user.units.count() > 1). Duplicandoli nella vista e il modello sembra soggetto a errori.

È possibile eseguire l'introspezione di un oggetto vista e vedere tutti i decoratori che lo avvolgono e calcolare se sono controlli (nel mio caso: il primo argomento sarebbe u o user). Se passano tutti, quindi consentire il rendering del collegamento.

Get all decorators wrapping a function descrive la tecnica in modo un po 'più dettagliato. Puoi trovare l'app che lo trasforma in un pratico sostituto per {% url %} allo Django-menus.

+0

Grazie, darò un'occhiata ai menu di Django e vedrò se fa quello che mi serve. Se finisco per dover codificare me stesso (mentre uso il mio decoratore personalizzato per le persecuzioni), andrò con la risposta di Tisho, poiché è significativamente meno "magica". – fadedbee

Problemi correlati