with vincent guardian custom abstractuser django django-permissions

vincent - login url django



¿Cómo puedo usar los permisos de Django sin definir un tipo de contenido o modelo? (6)

Me gustaría usar un sistema basado en permisos para restringir ciertas acciones dentro de mi aplicación Django. Estas acciones no tienen que estar relacionadas con un modelo en particular (por ejemplo, acceso a secciones en la aplicación, búsqueda ...), por lo que no puedo usar el marco de permisos de existencias directamente, porque el modelo de Permission requiere una referencia a un tipo de contenido instalado.

Podría escribir mi propio modelo de permiso, pero luego tendría que volver a escribir todas las bondades incluidas con los permisos de Django, como:

He comprobado algunas aplicaciones como django-authority y django-guardian , pero parecen proporcionar permisos aún más acoplados al sistema modelo, al permitir permisos por objeto.

¿Hay una manera de reutilizar este marco sin haber definido ningún modelo (además de User y Group ) para el proyecto?


El modelo de Permission de Django requiere una instancia de ContentType .

Creo que una forma de app_label es crear un ContentType ficticio que no esté relacionado con ningún modelo (los campos app_label y model se pueden establecer en cualquier valor de cadena).

Si desea que todo esté limpio y agradable, puede crear un modelo de proxy de Permission que maneje todos los detalles feos del ContentType ficticio y cree instancias de permiso "sin formato". También puede agregar un administrador personalizado que filtre todas las instancias de Permission relacionadas con modelos reales.


En lugar de escribir y ejecutar este código que inserta registros en la base de datos, simplemente puede insertar los registros en su base de datos (obviamente, editar las claves primarias y externas según sea necesario)

insert into django_content_type(id,name,app_label,model) values (22,''app_permission'',''myapp'',''app_permission''); insert into auth_permission(id,name,content_type_id,codename) values (64,''Is Staff Member'',22,''staff_member'');

Y luego, en el administrador de su aplicación, tendrá la capacidad de asignar ''Es miembro del personal'' a sus usuarios o grupos. Para verificar este permiso en tu clase deberías escribir

from django.contrib.auth.decorators import permission_required from django.utils.decorators import method_decorator from django.views.generic import TemplateView class MyClass(TemplateView): template_name = myapp/index.html'' @method_decorator(permission_required([''myapp.staff_member''],raise_exception=True)) def dispatch(self, *args, **kwargs): return super(MyClass, self).dispatch(*args, **kwargs)


Esta es una solución alternativa. Primero pregúntese: ¿Por qué no crear un modelo ficticio que realmente existe en la base de datos pero que nunca se usa, a excepción de los permisos de posesión? Eso no es bueno, pero creo que es una solución válida y directa.

from django.db import models class Permissions(models.Model): can_search_blue_flower = ''my_app.can_search_blue_flower'' class Meta: permissions = [ (''can_search_blue_flower'', ''Allowed to search for the blue flower''), ]

La solución anterior tiene la ventaja de que puede usar la variable Permissions.can_search_blue_flower en su código fuente en lugar de usar la cadena literal "my_app.can_search_blue_flower". Esto significa menos errores tipográficos y más autocompletar en IDE.


Para aquellos de ustedes que todavía están buscando:

Puede crear un modelo auxiliar sin tabla de base de datos. Ese modelo puede traer a tu proyecto cualquier permiso que necesites. No es necesario tratar con ContentType o crear objetos de Permiso explícitos.

from django.db import models class RightsSupport(models.Model): class Meta: managed = False # No database table creation or deletion operations / # will be performed for this model. permissions = ( (''customer_rigths'', ''Global customer rights''), (''vendor_rights'', ''Global vendor rights''), (''any_rights'', ''Global any rights''), )

Inmediatamente después de la manage.py migrate , puede utilizar estos permisos como cualquier otro.

# Decorator @permission_required(''app.customer_rights'') def my_search_view(request): … # Inside a view def my_search_view(request): request.user.has_perm(''app.customer_rights'') # In a template # The currently logged-in user’s permissions are stored in the template variable {{ perms }} {% if perms.app.customer_rigths %} <p>You can do any customer stuff</p> {% endif %}


Siguiendo el consejo de Gonzalo , utilicé un modelo de proxy y un administrador personalizado para manejar mis permisos "modernos" con un tipo de contenido ficticio.

from django.db import models from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType class GlobalPermissionManager(models.Manager): def get_query_set(self): return super(GlobalPermissionManager, self)./ get_query_set().filter(content_type__name=''global_permission'') class GlobalPermission(Permission): """A global permission, not attached to a model""" objects = GlobalPermissionManager() class Meta: proxy = True def save(self, *args, **kwargs): ct, created = ContentType.objects.get_or_create( name="global_permission", app_label=self._meta.app_label ) self.content_type = ct super(GlobalPermission, self).save(*args, **kwargs)


Solución para la respuesta de Chewie en Django 1.8, que tal como se solicitó en algunos comentarios.

Dice en las notas de publicación:

El campo de nombre de django.contrib.contenttypes.models.ContentType ha sido eliminado por una migración y reemplazado por una propiedad. Eso significa que ya no es posible consultar o filtrar un ContentType en este campo.

Entonces, es el ''nombre'' en referencia en ContentType que no se usa en GlobalPermissions.

Cuando lo arreglo me sale lo siguiente:

from django.db import models from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType class GlobalPermissionManager(models.Manager): def get_queryset(self): return super(GlobalPermissionManager, self)./ get_queryset().filter(content_type__model=''global_permission'') class GlobalPermission(Permission): """A global permission, not attached to a model""" objects = GlobalPermissionManager() class Meta: proxy = True verbose_name = "global_permission" def save(self, *args, **kwargs): ct, created = ContentType.objects.get_or_create( model=self._meta.verbose_name, app_label=self._meta.app_label, ) self.content_type = ct super(GlobalPermission, self).save(*args)

La clase GlobalPermissionManager no se modifica, pero se incluye para completar.