custom_user: improve performance of User.attributes (fixes #17599)

This commit is contained in:
Benjamin Dauvergne 2017-06-25 13:49:59 +02:00
parent 60f9657a32
commit 4b900a031a
3 changed files with 31 additions and 10 deletions

View File

@ -476,7 +476,6 @@ class LDAPBackend(object):
if getattr(user, legacy_attribute) != value:
setattr(user, legacy_attribute, value)
user._changed = True
user.attributes = attributes
def populate_admin_flags_by_group(self, user, block, group_dns):
'''Attribute admin flags based on groups.

View File

@ -26,19 +26,38 @@ class Attributes(object):
def __init__(self, owner, verified=None):
super(Attributes, self).__setattr__('owner', owner)
super(Attributes, self).__setattr__('verified', verified)
attributes = Attribute.objects.all()
at_map = {attribute.name: attribute for attribute in attributes}
for attribute in attributes:
at_map[attribute.id] = attribute
super(Attributes, self).__setattr__('attributes', at_map)
values = {}
super(Attributes, self).__setattr__('values', values)
for atv in self.owner.attribute_values.select_related().all():
try:
attribute = at_map[atv.attribute_id]
except KeyError:
continue
value = atv.to_python()
if attribute.multiple:
values.setdefault(attribute.name, []).append(value)
else:
values[attribute.name] = value
def __setattr__(self, name, value):
try:
at = Attribute.objects.get(name=name)
at.set_value(self.owner, value, verified=bool(self.verified))
except Attribute.DoesNotExist:
attribute = self.attributes[name]
except KeyError:
raise AttributeError(name)
attribute.set_value(self.owner, value, verified=bool(self.verified))
self.values[name] = value
def __getattr__(self, name):
try:
return Attribute.objects.get(name=name).get_value(self.owner, verified=self.verified)
except Attribute.DoesNotExist:
attribute = self.attributes[name]
except KeyError:
raise AttributeError(name)
return self.values.get(name, [] if attribute.multiple else None)
class AttributesDescriptor(object):
@ -46,7 +65,10 @@ class AttributesDescriptor(object):
self.verified = verified
def __get__(self, obj, objtype):
return Attributes(obj, verified=self.verified)
cache_name = '_attributes_verified_cache' if self.verified else '_attributes_cache'
if not hasattr(obj, cache_name):
setattr(obj, cache_name, Attributes(obj, verified=self.verified))
return getattr(obj, cache_name)
class User(AbstractBaseUser, PermissionMixin):

View File

@ -66,7 +66,7 @@ def test_sync_first_name(db, settings):
user.save()
user.first_name = 'John'
user.save()
assert Attribute.objects.get(name='first_name').get_value(user) == 'John'
assert user.attributes.first_name == 'John'
Attribute.objects.get(name='first_name').set_value(user, 'John Paul')
assert User.objects.get(id=user.id).first_name == 'John Paul'
user.attributes.first_name = 'John Paul'
assert user.attributes.first_name == 'John Paul'