Django Dynami c разрешение модели с использованием метода запроса - PullRequest
0 голосов
/ 28 мая 2020

Я работаю в компании, которая использует машины и формы для производства промышленных деталей. Во время производственного процесса машины могут работать со сбоями, поэтому мы создали интерфейс и серверную часть, чтобы работники регистрировали эти записи об ошибках. Недавно к этой системе присоединились инженеры и менеджеры из других отделов, поэтому мне нужно было убедиться, кто что может делать, другими словами, управлять разрешениями .

Соответствующая модель:

class FaultRecord(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    fault = models.ForeignKey(Fault, on_delete=models.PROTECT)
    machine = models.ForeignKey(Machine, on_delete=models.PROTECT)
    mold = models.ForeignKey(Mold, on_delete=models.PROTECT)
    part = models.ForeignKey(Part, on_delete=models.PROTECT)
    material = models.ForeignKey(Material, on_delete=models.PROTECT)
    responsible_departments = models.ManyToManyField(Department)
    status = models.ForeignKey(FaultRecordStatus, on_delete=models.SET_NULL, null=True)
    reason = models.TextField()
    temporary_action = models.TextField()
    permanent_action = models.TextField(null=True)
    duration = models.PositiveSmallIntegerField()
    occured_at = models.DateTimeField()
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField(null=True)

Соответствующий вид:

class FaultRecordViewSet(ModelViewSet):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated, ModelPermission]
    serializer_class = FaultRecordSerializer
    queryset = FaultRecord.objects.prefetch_related(
        'user',
        'fault',
        'machine',
        'mold',
        'part',
        'material',
        'responsible_departments',
        'status'
    ).all().order_by('occured_at')
    model = FaultRecord

Как мы знаем, Django создает 4 разрешения по умолчанию для моделей, которые позволяют просматривать, добавлять, изменять и удалять. Исходя из этого, я хотел проверить разрешения пользователей по методу запроса, поэтому мне не нужно писать класс разрешений для каждой модели. Также я не хочу использовать has_object_permission, потому что я тоже проверяю разрешение на публикацию.

Решение, которое я нашел:

class ModelPermission(BasePermission):
    method_mapper = {
        'GET': 'view',
        'POST': 'add',
        'PUT': 'change',
        'PATCH': 'change',
        'DELETE': 'delete'
    }

    def get_model_permission(self, method, model):
        app_label = model._meta.app_label
        model_name = model._meta.model_name
        permission_name = self.method_mapper.get(method)
        return f'{app_label}.{permission_name}_{model_name}'

    def has_permission(self, request, view):
        if request.method in SAFE_METHODS:
            return True
        permission = self.get_model_permission(request.method, view.model)
        return request.user.has_perm(permission)

Я добавил атрибут модели для класса просмотра, поэтому get_model_permission возвращает требуемую строку, чтобы иметь возможность использовать has_perm для меня. С его помощью я могу создавать группы с разрешениями и устанавливать группы пользователей. Я много искал, но ничего полезного не нашел. Что вы думаете? Мне нужны мнения других.

1 Ответ

1 голос
/ 28 мая 2020

Вы идете в правильном направлении, но я бы предложил использовать DjangoModelPermissions вместо BasePermission. DjangoModelPermissions реализует функции get_required_permissions и has_permission, поэтому вам не нужно писать эти функции самостоятельно. Если вы не хотите проверять права доступа к объектам, назначьте DjangoModelPermissions в своем наборе представлений.

Вы правы насчет управления разрешениями с помощью групп. Создайте группы и назначьте разрешения этим группам, а затем назначьте группы пользователям. Вы также можете назначить некоторые права пользователю напрямую, если того требует ситуация. has_permission of DjangoModelPermissions по умолчанию проверяет разрешение, назначенное пользователю, а также группам пользователей.

...