Обработка кэша разрешений в пользовательской модели django
Я столкнулся со странным поведением: Я добавляю разрешение к объекту пользователя, но проверка разрешения не проходит.
permission = Permission.objects.get_by_natural_key(app_label='myapp', codename='my_codename', model='mymodel')
user.user_permissions.add(permission)
user.has_permission('myapp.my_codename') # this is False!
Я нашел несколько сообщений о кэшировании пользовательских разрешений здесь и здесь и решение, похоже, заключается в полной перезагрузке объекта из базы данных.
# Request new instance of User
user = get_object_or_404(pk=user_id)
# Now note how the permissions have been updated
user.has_perms('myapp.my_codename') # now it's True
Это кажется мне излишеством и очень не похоже на Django. Неужели нет способа либо очистить кэш разрешений, либо перезагрузить внешние ключи, как это можно сделать для объекта с помощью refresh_from_db()
?
Заранее спасибо!
Ронни
Кэширование является проблемой для вас только из-за метода has_perms
. Если вы проследуете за ним по всему стеку, то в конце концов окажетесь здесь. Вы увидите, что этот метод явно проверяет кэш перед продолжением работы.
Если вам действительно нужно знать разрешения этого пользователя в данный момент времени и действительно не хотите обновлять данные из БД, то вы можете проверить больше вручную/прямо без вспомогательного метода has_perm
, поскольку это разрешение .add()
является стандартной операцией m2m и поле модели было обновлено.
На практике вы вряд ли будете проверять разрешение сразу после его добавления, пока объект находится в области видимости, и пока разрешения кэшируются, так как это немного избыточно. Я уверен, что разработчики Django учли это и решили, что преимущества кэширования по умолчанию будут правильным решением.
Вы можете принудительно пересчитать, удалив _perm_cache
и _user_perm_cache
пользовательского объекта.
permission = Permission.objects.get_by_natural_key(app_label='myapp', codename='my_codename', model='mymodel')
user.user_permissions.add(permission)
user.has_permission('myapp.my_codename') # returns False
del user._perm_cache
del user._user_perm_cache
user.has_permission('myapp.my_codename') # should be True
Но это приведет к повторному обращению к базе данных для получения обновленных разрешений. Поскольку это основано на внутренней работе django и не является частью публичного API, эти ключи кэша могут измениться в будущем, поэтому я бы предложил просто получить пользователя снова. Но это полностью зависит от вас.