2012-06-10 13 views
7

Mi aplicación Django actualmente tiene URL que están protegidas por las funciones 'permission_required()'.¿Encuentra los permisos necesarios de las URL de Django sin llamarlas?

Esta función se llama de tres maneras diferentes.

  1. Como decorador en views.py, con parámetros codificados.
  2. Como una función simple, con parámetro autogenerado, en vistas genéricas basadas en clases personalizadas.
  3. Como una función que invoca vistas en urls.py, con parámetros codificados.

Ahora estoy agregando un sistema de menú a la aplicación, y tengo que hacer que las entradas del menú reflejen si el usuario tiene permiso para solicitar la URL de cada entrada del menú. (Ya sea atenuándolo u ocultando dichas entradas.)

¿Hay alguna forma de consultar los permisos necesarios para una URL sin solicitando la URL?

La única solución que he pensado hasta ahora es reemplazar el decorador con un decorador sin parámetros 'menu_permssion_required()' y codificar todos los permisos en una estructura de Python. Esto parece un paso atrás, ya que mis vistas genéricas basadas en clases personalizadas ya generan automáticamente los permisos necesarios.

¿Alguna sugerencia sobre cómo hacer un sistema de menú que refleje los permisos de URL para el usuario actual?

+0

Siempre código de menús en plantillas, es simple y permite menús contextuales con {% extends%}. – jpic

+0

disculpas @jplc, no puedo entender cómo se relaciona su comentario con la pregunta. Esto es específicamente sobre permisos. Los permisos son transversales, no están vinculados al prefijo URL o similar. – fadedbee

+0

Puede verificar los permisos en la plantilla: https://gist.github.com/25c03f286337c66cc860 Esto es bastante estándar en los proyectos django de lo que he visto, aquí están los documentos sobre el módulo django perms en cuestión: https: // docs.djangoproject.com/en/1.0/topics/auth/#id6 Aún así, mi punto es que el tiempo dedicado a hacer un "sistema" para un menú HTML podría ser mejor gastado en otras cosas. – jpic

Respuesta

2

Aquí es un ejemplo de cómo resolver su problema:

En primer lugar, crear un contenedor decorador de usar en lugar de 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 

Entonces, lo utilizan para decorar sus puntos de vista:

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

a continuación, añadir una etiqueta a utilizar para sus elementos de menú:

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 

Y, por último, en sus plantillas, al construir el árbol de menús:

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

N. B. No he probado la última parte con la etiqueta, pero espero que entiendas la idea. Lo mágico aquí es agregar los permisos a view_func en el decorador, y luego puedes acceder a esto usando resolve (ruta). No estoy seguro de cómo se comportará en términos de rendimiento, pero después de todo, es solo una idea.

EDITAR: Sólo arreglado un error en el ejemplo ..

+0

Gracias, me encanta la idea general. Le dejaré saber cómo funciona en la práctica antes de fin de mes (fecha límite del proyecto). – fadedbee

2

¿Hay alguna forma de consultar los permisos necesarios para una URL sin solicitar la URL?

User.has_perm() y User.has_module_perms()

Cualquier sugerencia sobre cómo hacer que un sistema de menús que refleja permisos de URL para el usuario actual?

Me gusta mucho esta pregunta, porque se refiere a cualquier persona que hace un sitio web con django, por lo que me parece realmente relevante. He pasado por eso yo mismo e incluso coded a menu "system" en mi primer proyecto django en 2008. Pero desde entonces probé Pinax, y una de las (tantas) cosas que aprendí de sus proyectos de ejemplo es que es completamente innecesario.

Por lo tanto, no tengo ninguna sugerencia que apoyaría sobre cómo hacer un menú "sistema" que respete los permisos de usuario de la solicitud.

Tengo una sugerencia sobre cómo hacer un menú simple que respete los permisos de usuario de la solicitud, por lo que podría no estar completamente relacionado.

  1. Simplemente haga su menú en HTML plano, que no es como se va a cambiar tan a menudo que tiene que ser generado. Eso también mantendrá su código de Python más simple.

  2. Añadir a settings.TEMPLATE_CONTEXT_PROCESSORS: 'django.core.context_processors.PermWrapper'

  3. Uso del {{ perms }} proxy a User.has_perms.

Ejemplo:

{% 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#} 

Así es como me mantengo navegación sencilla , estúpida, y fuera del camino. Pero también siempre incluyo an autocomplete no muy lejos de los menús para que el usuario pueda navegar a cualquier página de detalles fácilmente. Entonces, eso es todo lo que sé sobre la navegación en los proyectos de django, ¡estoy ansioso por leer otras respuestas!

1

tuve un problema similar, pero fue un poco más profundo. En lugar de solo permisos, también quería otras pruebas basadas en el usuario con tapa (es decir, is_staff o user.units.count() > 1). Duplicar estos en la vista y la plantilla parece propensa a errores.

Puede introspectar un objeto de vista, y ver todos los decoradores envolviéndolo, y averiguar si son cheques (en mi caso: el primer argumento sería u o user). Si todos pasan, entonces permite renderizar el enlace.

Get all decorators wrapping a function describe la técnica con un poco más de detalle. Puede encontrar la aplicación que lo convierte en un reemplazo útil para {% url %} en Django-menus.

+0

Gracias, echaré un vistazo a los menús de Django y veré si hace lo que necesito. Si termino teniendo que codificar esto yo mismo (como uso mi propio decorador personalizado de persmissions), voy a ir con la respuesta de Tisho, ya que es significativamente menos 'mágico'. – fadedbee

Cuestiones relacionadas