#32782: Optimize _get_user_permissions by using set comprehensions
-------------------------------------+-------------------------------------
     Reporter:  Abhyudai             |                    Owner:  nobody
         Type:                       |                   Status:  closed
  Cleanup/optimization               |
    Component:  Uncategorized        |                  Version:  3.2
     Severity:  Normal               |               Resolution:  needsinfo
     Keywords:  permissions, auth    |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  1                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Nick Pope):

 I thought an alternative implementation could be the following to avoid
 needing `hasattr()` and `getattr()`:

 {{{#!python
 def _user_get_permissions(user, obj, name):
     name = f'get_{name}_permissions'
     return {
         permission
         for backend in auth.get_backends()
         if (method := getattr(backend, name, None))
         for permission in method(user, obj)
     }
 }}}

 I think this is more readable (personally), but there is no speed up:

 {{{
 Before: Mean +- std dev: 252 us +- 16 us
 After:  Mean +- std dev: 253 us +- 10 us
 }}}

 Maybe I got something wrong in my script. Here it is if anyone was
 interested in how to do this:

 {{{#!python
 import time

 import django
 import pyperf
 from django.apps import apps
 from django.conf import settings
 from django.core.management import call_command

 settings.configure(
     # Duplicate default backend 10 times to add more looping:
     AUTHENTICATION_BACKENDS=['django.contrib.auth.backends.ModelBackend']
 * 10,
     DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME':
 ':memory:'}},
     INSTALLED_APPS=['django.contrib.auth', 'django.contrib.contenttypes',
 '__main__'],
 )
 django.setup()

 # Run the migrations to create the require models:
 call_command('migrate', verbosity=0)

 # Look up the required models:
 User = apps.get_model('auth.User')
 Group = apps.get_model('auth.Group')
 Permission = apps.get_model('auth.Permission')

 # Create a user with a group and permissions assigned to both the user and
 group:
 user = User.objects.create_user('test')
 group = Group.objects.create(name='test')
 permissions = Permission.objects.all()
 user.groups.add(group)
 user.user_permissions.add(*permissions)
 group.permissions.add(*permissions)

 # Call permission methods to pre-cache results to reduce overhead from
 database queries:
 user.get_all_permissions()
 user.get_user_permissions()
 user.get_group_permissions()

 def test(loops, user):
     range_it = range(loops)

     t0 = time.perf_counter()

     for loop in range_it:
         user.get_all_permissions()
         user.get_user_permissions()
         user.get_group_permissions()

     return time.perf_counter() - t0

 runner = pyperf.Runner()
 runner.bench_time_func('Fetch Permissions', test, user)
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32782#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/068.986c5dd332ad399111c31f68a1c8db2e%40djangoproject.com.

Reply via email to