Alireza
Alireza

Reputation: 4516

Reduce number of database queries, initiated from django templates

I have a custom permission model for my project and I'm not using django's default permissions backend. I have a custom has_permission template tag to check if the user has the specified permission or not.

The problem is that there's lots of queries done for the same checks every time, I'm looking for a way to reduce my Permission queries. What I'm doing inside my templates is like :

    {% if user|has_permission:'jpermission.can_edit_jpermission' or 
          user|has_permission:'jgroup.can_edit_jgroup' or 
          user|has_permission:'role.can_edit_role' %}

and the code for has_permission template tag is as follows :

rep = perm_name.split('.') # rep is for e.g. "jpermission.can_edit_jpermission"
ctn_type = rep[0]
codename = rep[1]

pr = JPermission.objects.filter(model_name=ctn_type, codename=codename)
if pr.exists():
    if user.has_perm(pr[0]):
        return True

Specifically talking, the problem is that every time i check even for the exactly same if statements, lots of queries are made (from what I'm doing, it's obvious there will be).

Is there any other way i can go at it ? like query all permissions once, cache them, and do something like how prefetch_related is handled to prohibit further db queries (python filtering with loops and ... ) ?

P.S: has_perm is also overridden and checks if users role, group or permissions have the specified permission or not)

Upvotes: 3

Views: 638

Answers (1)

Aamir Rind
Aamir Rind

Reputation: 39689

There are multiple solutions for this.

  • Move permissions to user model as methods of model and use cached_property decorator so that consecutive calls to methods does not hit database again.
  • Store the permissions state in session when user logged in, and later use session data to check for permissions.

It looks like you are using django-guardian, and it is already caching the permissions:

Once checked for single object, permissions are stored and we don’t hit database again if another check is called for this object. This is great for templates, views or other request based checks (assuming we don’t have hundreds of permissions on a single object as we fetch all permissions for checked object).

Upvotes: 1

Related Questions