В конечном счете, моя цель состоит в том, чтобы расширить ModelAdmin в Django для предоставления разрешений на уровне полей, то есть, учитывая свойства объекта запроса и значения полей редактируемого объекта, я хотел бы контролировать, будут ли поля /строки видны пользователю.В конечном итоге я достиг этого, добавив метод can_view_field()
в ModelAdmin и изменив встроенные методы get_form()
и get_fieldset()
, чтобы удалить / исключить поля + inline, которые пользователь не имеет разрешений (как определено can_view_field()
)видеть.Если вы хотите увидеть код, я поместил его в папку , так как он длинный и только в некоторой степени актуален.
Он отлично работает ... почти.Кажется, я столкнулся с какой-то проблемой безопасности потоков или кэширования, когда состояние объекта ModelAdmin воспроизводится из одного запроса в другой воспроизводимым образом.
Я проиллюстрирую проблему с помощьюпростой примерПредположим, у меня есть модель, модель которой я добавил в код доступа на уровне поля.Эта модель имеет два поля: - public_field
, которое может просматривать / редактировать любой сотрудник; - secret_field
, которое может просматривать / редактировать только суперпользователи
В этом случае метод can_view_field()
будет выглядеть следующим образом:
def can_view_field(self, request, obj, field_name):
"""
Returns boolean indicating whether the user has necessary permissions to
view the passed field.
"""
if obj is None:
return request.user.has_perm('%s.%s_%s' % (
self.opts.app_label,
action,
obj.__class__.__name__.lower()
))
else:
if field_name == "public_field":
return True
if field_name == "secret_field" and request.is_superuser:
return True
return False
Контрольный пример 1: при новом перезапуске сервера, если вы сначала просматриваете форму списка изменений как суперпользователь, вы видите форму, как и в случае public_field
и secret_field
видимый.Если вы выходите из системы и просматриваете ее как сотрудник (но не как суперпользователь), вы увидите только public_field
.
Тестовый пример 2: с новым перезапуском сервера, если вы вошли в систему сначала как сотрудник,вы все еще видите только public_field
.Однако, если вы выйдете из системы и увидите, что вы суперпользователь, вы не см. secret_field
.Воспроизводится на 100%.
Я провел некоторые базовые диагностики безопасности потоков:
- В конце
get_form()
я распечатал адрес памятиОбъект ModelForm.Как и должно быть, он уникален для каждого запроса.Поэтому объект ModelForm не является проблемой. - Непосредственно перед регистрацией администратора я попытался распечатать адрес памяти объекта ModelAdmin.В тестовом примере 1 он уникален для обоих запросов.Однако в тестовом примере 2 он вообще не печатается при втором запросе.
На данный момент я не в курсе.Следующим моим исследованием будет система регистрации администраторов (о которой я, по общему признанию, ничего не знаю).Состояние сбрасывается при перезапуске сервера, поэтому кажется, что ModelAdmin должен быть кэширован?Или это проблема безопасности потоков?Если я превращу его в фабрику и верну deepcopy()
из ModelAdmin, будет ли он обслуживать новый ModelAdmin с каждым запросом?Я невежественен и буду признателен за любые мысли.Спасибо!