Обработка кэша разрешений в пользовательской модели 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, эти ключи кэша могут измениться в будущем, поэтому я бы предложил просто получить пользователя снова. Но это полностью зависит от вас.

Вернуться на верх