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