Django-guardian: ¿Cómo puedo optimizar mi consulta cuando utilizo `assign_perm`?

Creado en 20 ago. 2020  ·  2Comentarios  ·  Fuente: django-guardian/django-guardian

Actualmente estoy trabajando en un proyecto en el que una habitación tiene sus propios permisos de grupo.

Cuando alguien crea una nueva habitación, el sistema hará lo siguiente:

  1. Creando una habitación
  2. Cree grupos de propietarios y empleados con nombres únicos, como Room Owner#room#{pk}
  3. Obtenga una lista de permisos de propietario y personal de la clase de sala
  4. Haga una tarea para cada grupo
  5. Asignar permisos de grupo de propietarios al usuario

Aquí está mi modelo de habitación:

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', _('...'))    
        ]
    ]

Este es mi código para crear sala y generar permisos de grupo:

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)

Cuando miro los registros de consultas, se están realizando muchas consultas en este proceso.

En realidad, todavía hay algunos grupos y el proceso de asignación como el anterior, pero solo incluí algunos ejemplos, por lo que no hay demasiados.Si se calcula, puede haber más de 50 ejecuciones de consultas que se ejecutan en este proceso.

Entonces, ¿cómo puedo optimizar la consulta para este problema? ¿Alguien puede compartir cómo hacerlo mejor?

Gracias,

Comentario más útil

  1. Use claves externas directas, consulte https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Puede pasar instancias de Permission a assign_perm . perm = self._get_permission_string(owner_perm) conduce a una consulta adicional por permiso.

  3. Si esto no es suficiente, puede asignar los permisos de forma masiva, consulte el código a continuación. Pero tenga en cuenta que no probé este código. Puede que necesite ajustes, puede que no funcione en absoluto.


Antes:

# 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)

Despué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)

Todos 2 comentarios

  1. Use claves externas directas, consulte https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Puede pasar instancias de Permission a assign_perm . perm = self._get_permission_string(owner_perm) conduce a una consulta adicional por permiso.

  3. Si esto no es suficiente, puede asignar los permisos de forma masiva, consulte el código a continuación. Pero tenga en cuenta que no probé este código. Puede que necesite ajustes, puede que no funcione en absoluto.


Antes:

# 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)

Despué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)

Dios mío. Echaba de menos este. Decidí usar el primero. Gracias,

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

ad-m picture ad-m  ·  13Comentarios

johnthagen picture johnthagen  ·  9Comentarios

BenDevelopment picture BenDevelopment  ·  5Comentarios

g-as picture g-as  ·  10Comentarios

Dzejkob picture Dzejkob  ·  28Comentarios