Django-guardian: Comment puis-je optimiser ma requête lorsque j'utilise `assign_perm` ?

Créé le 20 août 2020  ·  2Commentaires  ·  Source: django-guardian/django-guardian

Je travaille actuellement sur un projet où une pièce a ses propres autorisations de groupe.

Lorsque quelqu'un crée une nouvelle salle, le système effectuera les opérations suivantes :

  1. Création d'une chambre
  2. Créez des groupes de propriétaires et d'employés avec des noms uniques, tels que Room Owner#room#{pk}
  3. Obtenez la liste des autorisations du propriétaire et du personnel de la classe Room
  4. Faire une affectation à chaque groupe
  5. Attribuer des autorisations de groupe de propriétaires à l'utilisateur

Voici mon modèle de chambre :

class Room(models.Model):
    # ...fields

    PERMISSION_GROUPS = [
        'owner': [
            ('view_room', _('...')),
            ('change_room', _('...')),
            ('delete_room', _('...')),

            ('open_room', _('...')),
            ('close_room', _('...'))
        ],
        'staff': [
            ('view_room', _('...')),
            ('open_room', _('...')),
            ('close_room', _('...'))    
        ]
    ]

Voici mon code pour créer une salle et générer des autorisations de groupe :

from guardian.shortcuts import assign_perm

class CreateRoomView(generics.CreateAPIView):
    def _get_permission_string(self, perm):
        """
        Get string permission, the return is like 'room.add_room'
        """
        return f'room.{perm.codename}'

    def post(self):
        # Create a room
        body = {}
        room = Room.objects.create(**body)

        # Get content type
        ctype = ContentType.objects.get_for_model(Room)

        # Define name of owner and staff group for this room permission
        owner_group_name = _('Room Owner#room#{pk}')
        staff_group_name = _('Room Staff#room#{pk}')

        # Create group
        owner_group = Group.objects.create(
            name=owner_group_name.format(pk=room.pk))
        staff_group = Group.objects.create(
            name=staff_group_name.format(pk=room.pk))

        # Get permissions by group permissions
        owner_perms = Permission.objects.filter(
            codename__in=Room.PERMISSION_GROUPS.get('owner'), content_type=ctype)
        staff_perms = Permission.objects.filter(
            codename__in=Room.PERMISSION_GROUPS.get('staff'), content_type=ctype)

        # Assign owner permissions to the group
        for owner_perm in owner_perms:
            perm = self._get_permission_string(owner_perm)
            assign_perm(perm, owner_group, obj=room)

        # Assign staff permissions to the group
        for staff_perm in staff_perms:
            perm = self._get_permission_string(staff_perm)
            assign_perm(perm, staff_group, obj=room)

        # Assign owner group permission to the user
        request.user.groups.add(owner_group)

Lorsque je regarde les journaux de requêtes, de nombreuses requêtes sont effectuées dans ce processus.

En fait, il y a encore quelques groupes et le processus d'affectation comme ci-dessus, mais je n'ai inclus que quelques exemples, donc il n'y en a pas trop. Si calculé, il peut y avoir plus de 50 exécutions de requêtes qui s'exécutent dans ce processus.

Alors, comment puis-je optimiser la requête pour ce problème ? Quelqu'un peut-il partager comment le faire mieux.

Merci,

Commentaire le plus utile

  1. Utilisez des clés étrangères directes, voir https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Vous pouvez passer des instances de Permission à assign_perm . perm = self._get_permission_string(owner_perm) conduit à une requête supplémentaire par autorisation.

  3. Si cela ne suffit pas, vous pouvez attribuer les autorisations en bloc, voir le code ci-dessous. Mais sachez que je n'ai pas testé ce code. Cela peut nécessiter des ajustements, cela peut ne pas fonctionner du tout.


Avant:

# Assign owner permissions to the group
for owner_perm in owner_perms:
    perm = self._get_permission_string(owner_perm)
    assign_perm(perm, owner_group, obj=room)

# Assign staff permissions to the group
for staff_perm in staff_perms:
    perm = self._get_permission_string(staff_perm)
    assign_perm(perm, staff_group, obj=room)

Après:

# RoomGroupObjectPermission is the model from suggestion 1, use direct foreign keys
room_group_object_permissions = [
    RoomGroupObjectPermission(
        permission=owner_perm, group=owner_group, content_object=room,
    )
    for owner_perm in owner_perms
] + [
    RoomGroupObjectPermission(
        permission=staff_perm, group=staff_group, content_object=room,
    )
    for staff_perm in staff_perms
]

RoomGroupObjectPermission.objects.bulk_create(room_group_object_permissions)

Tous les 2 commentaires

  1. Utilisez des clés étrangères directes, voir https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Vous pouvez passer des instances de Permission à assign_perm . perm = self._get_permission_string(owner_perm) conduit à une requête supplémentaire par autorisation.

  3. Si cela ne suffit pas, vous pouvez attribuer les autorisations en bloc, voir le code ci-dessous. Mais sachez que je n'ai pas testé ce code. Cela peut nécessiter des ajustements, cela peut ne pas fonctionner du tout.


Avant:

# Assign owner permissions to the group
for owner_perm in owner_perms:
    perm = self._get_permission_string(owner_perm)
    assign_perm(perm, owner_group, obj=room)

# Assign staff permissions to the group
for staff_perm in staff_perms:
    perm = self._get_permission_string(staff_perm)
    assign_perm(perm, staff_group, obj=room)

Après:

# RoomGroupObjectPermission is the model from suggestion 1, use direct foreign keys
room_group_object_permissions = [
    RoomGroupObjectPermission(
        permission=owner_perm, group=owner_group, content_object=room,
    )
    for owner_perm in owner_perms
] + [
    RoomGroupObjectPermission(
        permission=staff_perm, group=staff_group, content_object=room,
    )
    for staff_perm in staff_perms
]

RoomGroupObjectPermission.objects.bulk_create(room_group_object_permissions)

OMG. J'ai raté celui-ci. J'ai décidé d'utiliser le premier. Merci,

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

Allan-Nava picture Allan-Nava  ·  4Commentaires

Dzejkob picture Dzejkob  ·  28Commentaires

ad-m picture ad-m  ·  13Commentaires

lukaszb picture lukaszb  ·  14Commentaires

BenDevelopment picture BenDevelopment  ·  5Commentaires