Django QuerySet: форматировать результат запроса как пользовательский словарь - PullRequest
0 голосов
/ 30 января 2020

Я работаю в системе RBA C для моего приложения Django -React. У меня есть определенная объектная структура, которую я хочу сгенерировать, но я не уверен, как это сделать напрямую из QuerySet API Django.

В настоящее время у меня есть этот запрос

permissions |= PermissionAssignment.objects.filter(role=role['role__id']).values(
 'permission__object__id',
 'permission__object__name',
 'permission__operation__id',
 'permission__operation__name'
)

который возвращает этот объект на моем веб-интерфейсе:

permissions: [
        {
          permission__object__id: 1,
          permission__object__name: 'Post',
          permission__operation__id: 1,
          permission__operation__name: 'Read'
        },
        {
          permission__object__id: 1,
          permission__object__name: 'Post',
          permission__operation__id: 2,
          permission__operation__name: 'Write'
        },
        {
          permission__object__id: 2,
          permission__object__name: 'Event',
          permission__operation__id: 2,
          permission__operation__name: 'Read'
        },
]

Мне не требуется, чтобы объект разрешения имел эту сложную структуру. Мне нужно только завладеть именем объекта и операциями, разрешенными для этого объекта для текущего пользователя. В общем, мне просто нужно, чтобы это было структурировано следующим образом:

permissions:[
 "Post": {
   operations: ['Read', 'Write']
 },
 "Event": {
   operations: ['Read']
 }
]

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

Ответы [ 2 ]

1 голос
/ 30 января 2020

Возможно, вы сможете использовать списки для достижения желаемого результата.

# NOTE: we use prefetch_related to avoid extra queries every time we access the object 
permissions_qs = PermissionAssignment.objects.filter(role=role['role__id']).prefetch_related('object', 'operation')

d = {}
[d.update({p.object.name: {'operations': [p.operation.name]}}) if p.object.name not in d else d[p.object.name]['operations'].append(p.operations.name) for p in permissions_qs]
0 голосов
/ 30 января 2020

Я нашел решение для того, что хотел ... Структура ответа JSON отличается от того, что я определил в моем вопросе выше, но я думаю, что он намного лучше.

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

Код:

roles = RoleAssignment.objects.none()
modules = RoleModule.objects.none()
module_objects = ModuleObject.objects.none()
objects = Object.objects.none()
permissions = PermissionAssignment.objects.none()

roles = RoleAssignment.objects.filter(user=user).values('role__id', 'role__name')
for role in roles:
    modules |= RoleModule.objects.filter(role=role['role__id']).values(
        'role__id',
        'module__id',
        'module__name',
        'module__slug',
        'module__fontawesome_icon'
    )
    permissions |= PermissionAssignment.objects.filter(role=role['role__id']).values(
        'permission__object__id',
        'permission__object__name',
        'permission__operation__id',
        'permission__operation__name'
    )
for module in modules:
    module_objects |= ModuleObject.objects.filter(module=module['module__id']).values(
        'module__id',
        'module__name',
        'object__id',
        'object__name',
        'object__slug'
    )

# format modules to include respective objects and permissions
# this logic is primarily designed so that sidebar links can be...
# ...generated seamlessly thru frontend 
formatted_modules = [
    {
        "name": x['module__name'],
        "slug": x['module__slug'],
        "icon": x['module__fontawesome_icon'],
        "objects": [
            {
                "name": y['object__name'],
                "slug": y['object__slug'],
                "operations": [z['permission__operation__name'] for z in permissions if z['permission__object__id']==y['object__id']]
            }
            for y in module_objects if x['module__id']==y['module__id']
        ]
    }
    for x in modules
]

Затем отправьте его как ответ:

return Response({
    "modules": formatted_modules
})

Эквивалент JSON:

{
  modules: [
    {
      name: 'Web Content',
      slug: 'web-content',
      icon: 'fas fa-newspaper',
      objects: [
        {
          name: 'Post',
          slug: 'post',
          operations: [
            'Read',
            'Write',
            'Modify',
            'Delete'
          ]
        }
      ]
    },
    {
      name: 'Bids and Awards',
      slug: 'bids-and-awards',
      icon: 'fas fa-project-diagram',
      objects: [
        {
          name: 'SRBP Goods & Services',
          slug: 'srbp-goods-services',
          operations: [
            'Read',
            'Write',
            'Modify',
            'Delete'
          ]
        },
        {
          name: 'SRBP Infrastructure',
          slug: 'srbp-infrastructure',
          operations: [
            'Read',
            'Write',
            'Modify',
            'Delete'
          ]
        }
      ]
    }
  ]
}

В моем пользовательском интерфейсе: enter image description here

...