Как подвергать цензуре указанные поля c на основе условий, используя django API QuerySet - PullRequest
1 голос
/ 29 января 2020

Используя Django, мы имеем ситуацию, когда у нас есть модель Case, которая может быть установлена ​​как медицинский случай или нет (через BooleanField).

Теперь у нас также есть система проверить, уполномочен ли определенный сотрудник (подкласс пользователя) на просмотр конфиденциальных данных, когда случай помечен как медицинский (содержащий конфиденциальные данные).

Я могу annotate новое поле для каждого экземпляра , BooleanField сообщая нам, уполномочен ли запрашивающий сотрудник просматривать медицинские данные на конкретном c экземпляре дела или нет.

В идеале, я бы хотел, чтобы датчик базы данных не указывал c поля (например, поле customer), когда запрашивающий сотрудник не имеет права просматривать медицинские данные для этого случая. Я полагаю, что это можно сделать с помощью метода annotate и комбинации from django.db.models.Case и from django.db.models.When.

Но нам также хотелось бы, чтобы результирующий QuerySet сохранил те же имена полей на разные модели экземпляров. Мы не хотим менять имя поля customer на другое имя.

На самом деле мы нашли решение, используя сначала .values, а затем .annotate для каждого поля, которое мы хотим потенциально подвергать цензуре (см. код ниже). Это не идеально, хотя, по нескольким причинам. Во-первых, мы не возвращаем модельные экземпляры, а словари. Кроме того, но это другой вопрос, одно из полей, которое нужно подвергнуть цензуре, - это ManyToManyField, и использование .values теперь возвращает уникальную строку для каждого экземпляра, на который ссылается ManyToManyField (какое-либо решение для этого?)

Кроме того, в идеале этот набор запросов должен быть базовым набором запросов для всех ситуаций, в которых сотрудник пытается запросить Случаи в нашем приложении. Мы хотим, чтобы все наши коллеги использовали этот базовый набор запросов, чтобы нам не приходилось внедрять одно и то же решение в нескольких местах и ​​предотвращать утечку конфиденциальных данных.

Поэтому, мне интересно, может кто-нибудь порекомендовать решение для этой ситуации?

Заранее спасибо!

PS. Мы хотели бы, чтобы это выполнялось базой данных, поскольку количество извлекаемых дел потенциально очень велико, и выполнение этого в Python, вероятно, потребовало бы большой мощности ЦП и, таким образом, снизило бы производительность.

from django.db.models import Case, When, BooleanField, IntegerField, F, Value, Q


OurModel.objects.annotate(
            employee_medical_authorized=Case(
                When(..., then=Value(True)),
                default=Value(False),
                output_field=BooleanField()
            )).values(...).annotate(
            customer=Case(
                When(Q(employee_medical_authorized=Value(False)) & Q(medical=Value(True)),
                     then=Value(None)),
                default=F('customer'),
                output_field=IntegerField()
            )
        )
...