Django-guardian: Wie kann ich meine Abfrage optimieren, wenn ich `assign_perm` verwende?

Erstellt am 20. Aug. 2020  ·  2Kommentare  ·  Quelle: django-guardian/django-guardian

Ich arbeite gerade an einem Projekt, bei dem ein Raum seine eigenen Gruppenberechtigungen hat.

Wenn jemand einen neuen Raum erstellt, geht das System wie folgt vor:

  1. Einen Raum erstellen
  2. Erstellen Sie Eigentümer- und Mitarbeitergruppen mit eindeutigen Namen, z. B. Room Owner#room#{pk}
  3. Rufen Sie eine Liste der Eigentümer- und Mitarbeiterberechtigungen aus der Raumklasse ab
  4. Machen Sie jeder Gruppe eine Aufgabe
  5. Weisen Sie dem Benutzer Eigentümergruppenberechtigungen zu

Hier ist mein Room-Modell:

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

Dies ist mein Code zum Erstellen von Räumen und Generieren von Gruppenberechtigungen:

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)

Wenn ich mir die Abfrageprotokolle ansehe, werden in diesem Prozess viele Abfragen ausgeführt.

Tatsächlich gibt es noch ein paar Gruppen und den Zuweisungsprozess wie oben, aber ich habe nur einige Beispiele aufgenommen, damit es nicht zu viele sind. Wenn berechnet, können in diesem Prozess mehr als 50 Abfrageausführungen ausgeführt werden.

Wie kann ich die Abfrage für dieses Problem optimieren? Kann jemand sagen, wie man es besser macht.

Dankeschön,

Hilfreichster Kommentar

  1. Direkte Fremdschlüssel verwenden, siehe https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Sie können Instanzen von Permission an assign_perm . perm = self._get_permission_string(owner_perm) führt zu einer zusätzlichen Abfrage pro Berechtigung.

  3. Wenn dies nicht ausreicht, können Sie die Berechtigungen massenweise zuweisen, siehe Code unten. Aber seien Sie sich bewusst, dass ich diesen Code nicht getestet habe. Möglicherweise müssen Anpassungen vorgenommen werden, es funktioniert möglicherweise überhaupt nicht.


Vor:

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

Nach:

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

Alle 2 Kommentare

  1. Direkte Fremdschlüssel verwenden, siehe https://django-guardian.readthedocs.io/en/stable/userguide/performance.html#direct -foreign-keys

  2. Sie können Instanzen von Permission an assign_perm . perm = self._get_permission_string(owner_perm) führt zu einer zusätzlichen Abfrage pro Berechtigung.

  3. Wenn dies nicht ausreicht, können Sie die Berechtigungen massenweise zuweisen, siehe Code unten. Aber seien Sie sich bewusst, dass ich diesen Code nicht getestet habe. Möglicherweise müssen Anpassungen vorgenommen werden, es funktioniert möglicherweise überhaupt nicht.


Vor:

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

Nach:

# 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. Ich habe diesen verpasst. Ich habe mich für den ersten entschieden. Dankeschön,

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

johnthagen picture johnthagen  ·  9Kommentare

g-as picture g-as  ·  10Kommentare

ad-m picture ad-m  ·  13Kommentare

brianmay picture brianmay  ·  16Kommentare

xuhcc picture xuhcc  ·  10Kommentare