101 votes

Comment puis-je utiliser les permissions de Django sans définir un type de contenu ou un modèle ?

J'aimerais utiliser un système de permissions pour restreindre certaines actions dans mon application Django. Ces actions n'ont pas besoin d'être liées à un modèle particulier (par exemple, l'accès aux sections de l'application, la recherche...), donc je ne peux pas utiliser l'option cadre des autorisations de stock directement, car le Permission requiert une référence à un type de contenu installé.

Je pourrais écrire mon propre modèle de permission, mais je devrais alors réécrire tous les éléments inclus dans les permissions de Django, tels que.. :

J'ai vérifié des applications comme django-autorité y django-guardian mais ils semblent fournir des autorisations encore plus liées au système de modèles, en permettant des autorisations par objet.

Existe-t-il un moyen de réutiliser ce cadre sans avoir défini aucun modèle (en dehors de User y Group ) pour le projet ?

202voto

Dmitry Points 1888

Pour ceux d'entre vous qui cherchent encore :

Vous pouvez créer un modèle auxiliaire sans table de base de données. Ce modèle peut apporter à votre projet toutes les autorisations dont vous avez besoin. Il n'est pas nécessaire de traiter le ContentType ou de créer explicitement des objets Permission.

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. 

        default_permissions = () # disable "add", "change", "delete"
                                 # and "view" default permissions

        permissions = ( 
            ('customer_rights', 'Global customer rights'),  
            ('vendor_rights', 'Global vendor rights'), 
            ('any_rights', 'Global any rights'), 
        )

Juste après manage.py makemigrations y manage.py migrate vous pouvez utiliser ces permissions comme n'importe quelle autre.

# 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_rights %}
    <p>You can do any customer stuff</p>
{% endif %}

61voto

Gonzalo Delgado Points 1813

Le programme de Django Permission modèle nécessite un ContentType instance .

Je pense qu'une façon de contourner le problème est de créer un faux ContentType qui n'est pas lié à un modèle (le app_label y model peuvent être définis comme n'importe quelle valeur de chaîne).

Si vous voulez que tout soit propre et agréable, vous pouvez créer un fichier Permission modèle de substitution qui gère tous les détails moches du mannequin. ContentType et crée des instances de permission "sans modèle". Vous pouvez également ajouter un gestionnaire personnalisé qui filtre toutes les autorisations de type Permission des instances liées à des modèles réels.

54voto

Chewie Points 2948

Suivant Le conseil de Gonzalo J'ai utilisé un modèle de substitution et un gestionnaire personnalisé pour gérer mes permissions "sans modèle" avec un type de contenu fictif.

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)

10voto

rgammans Points 31

Correction pour la réponse de Chewie dans Django 1.8, qui a été demandée dans quelques commentaires.

Il est dit dans les notes de mise à jour :

Le champ name de django.contrib.contenttypes.models.ContentType a été supprimé par une migration et remplacé par une propriété. Cela signifie qu'il n'est plus possible d'interroger ou de filtrer un ContentType par ce champ.

C'est donc le "nom" en référence dans ContentType qui est utilisé et non dans GlobalPermissions.

Lorsque je le répare, j'obtiens ce qui suit :

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 classe GlobalPermissionManager est inchangée mais incluse par souci d'exhaustivité.

5voto

guettli Points 3284

C'est une solution alternative. Demandez-vous d'abord : Pourquoi ne pas créer un modèle factice qui existe réellement dans la base de données mais qui n'est jamais utilisé, sauf pour conserver les autorisations ? Ce n'est pas très joli, mais je pense que c'est une solution valable et directe.

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 solution ci-dessus a l'avantage de vous permettre d'utiliser la variable Permissions.can_search_blue_flower dans votre code source au lieu d'utiliser la chaîne littérale "mon_app.can_search_blue_flower". Cela signifie moins de fautes de frappe et plus d'autocomplétion dans l'IDE.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X