Skip to content

Our views are slow because of `LDPPermissions`

LDPPermissions are certainly the biggest reason why our views are slower than DRF

What do we have?

  • on the container, filter_user_perms is called on the parent and child model, to filter the queryset (resolving model permissions for each)
  • when each object in the queryset is serialized, the full permissions are serialized (including object and backend permissions), which is more expensive & involves database hits

The MR open for the issue (!175 (merged) ) replaces filter_user_perms with prefilter_query_set, which essentially does the same thing but earlier in the get_queryset, and at the cost that developers need to override prefilter_query_set in their own permissions classes (or those they install). The cache speeds up permissions hits on repeat requests, avoiding database hits by spending memory

Ignoring the ugliness/bugginess of LDPPermissions in general (in this issue), I should note that DRF avoids analysing object permissions in the queryset at all, explicitly for performance reasons, and requires that developers override filter_queryset or provide custom FilterBackends to achieve this functionality

What do we want?

To achieve good performance we need:

  • remove the behaviour of automatically filtering values in LDPSerializer.to_representation
  • remove the auto-generation of the Web-ACLs for retrieved resources (unless requested explicitly?), meaning these are only serialized for the container

To achieve good usability I think we want:

  • to filter values in LDPViewSet in a way that's efficient and easily extensible
  • to render WebACLs dynamically so that these can be returned
  • to override/extend filters easily on viewsets for custom models
  • a simpler system for overriding LDPPermissions (another issue)

with nested fields, we need:

  • values to be filtered when they are a nested property in another (parent) model's viewset
  • the filters from my custom viewset on this model, universally(?) also need to be applied in the nested field of the parent viewset (e.g. circles/x/members/ is the CircleViewSet)

What are we going to do?

What can be automatically filtered (in filter_queryset or in a FilterBackend)?

  • we can easily and efficiently check model permissions. This is "yes" or "no" information, it tells us to start with the whole queryset or with none of them
  • we can use Django-Guardian's get_objects_for_user to apply object and group-level permissions

rendering WebACLs dynamically (['permissions']: ... on the serialized resource)..

  • is this required by LDP? When do we use it? Could it be skipped in the list view? @matthieu @balessan

override/extend filters easily on viewsets or custom models

  • easy as adding a FilterBackend for the direct viewset.. but the nested viewset is a question mark!

@balessan context for this morning

Edited by Calum Mackervoy