Рано или поздно, разработчик на Django встречается с проблемой: как сделать так, чтобы пользователи не могли изменять или удалять, а то и вовсе не видели разные объекты одного и того же типа. Допустим, ваш проект касается хранения информации о проектах. Разные пользователи входят в разные проекты и не должны видеть информацию о другом проекте. Один и тот же пользователь может входить в несколько проектов и иметь разный статус в разных проектах — где-то он может только просматривать информацию, а в других — править данные. В каком-то проекте пользователь зарегистрирован как персонал проекта, а в другом — только как потребитель его услуг. Уровень доступа соответственно, должен быть совершенно разным. Этими вопросами занимаются несколько пакетов, мы рассмотрим один из них — Django-Access. Все, кому это интересно, приглашаются под кат. Рассмотрим пример, кратко описанный в преамбуле. Будем считать, что у нас имеется некая простая система управления данными проектов определенного направления, например транспортных. С точки зрения доступа к различным данным, пользователи системы разделены на несколько категорий: Для простоты, мы полностью проигнорируем встроенную систему управления правами Django, но оставим нетронутой систему данных пакета django.contrib.auth. Соответственно, мы не будем обращать внимания на объекты моделей Permission и Group и развернем собственную, альтернативную подсистему управления правами, основанную на отношении пользователей к проекту и отдельным категориям данных внутри него. Создадим каталог для проекта и в нем — новый проект Django командой django-admin startproject sample. Мне не нравится система именования каталогов в стандартном шаблоне Django, поэтому я переименую подкаталог sample внутри каталога проекта sample в каталог options и поменяю соответственным образом все сгенерированные внутри файлов проекта ссылки на это имя. Создадим заготовку джанго-приложения trans командой python manage.py startapp trans и все модели нашего приложения будем создавать в нем. Информация обо всех проектах в системе будет содержаться в объектах модели Project. Пользователь системы может иметь разный статус по отношению к разным проектам. Мы отразим это в модели ProjectMember, которая будет устанавливать связь между пользователем и проектом и хранить детали порядка доступа этого пользователя к этому проекту. Внимательный читатель уже заметил, что в данных о членстве в проектах отсутствует информация о том, является ли пользователь потребителем услуг этого проекта. Будем считать, что все пользователи системы являются потенциальными потребителями услуг всех проектов, определяя факт использования услуг по наличию ссылок на этого пользователя внутри данных самого проекта. Таким образом, наличие информации о членстве определяет, имеет ли пользователь какое-либо отношение к проекту, помимо факта получения услуг от этого проекта. Примером данных проекта — тех, которыми управляет персонал проекта — будут следующие модели: Для всех из них определено явное участие в одном из проектов, кроме того, водитель является пользователем, а заказ определяет время пользования клиентом назначенной парой водитель-автомобиль. Включим приложения access и trans в состав инсталлированных приложений проекта в модуле settings.py, создадим миграции командой python makemigrations trans и выполним миграцию командой python migrate. Теперь, для всех моделей нашего приложения, сделаем админки в модуле admin.py приложения trans. В админках мы сразу же используем модифицированные классы админки из пакета Django-Access. Да. Во-первых, пакет Django-Access по умолчанию, использует систему распределения прав, аналогичную той, которая используется пакетом Django, и только для тех моделей, права к которым переопределены, использует переопределенные права. Во-вторых, вы скорее всего, будете поначалу отлаживать админки под правами суперпользователя, которому Django-Access, по умолчанию, так же как и Django, отдает все права. Мы должны переопределить админку пользователей, чтобы исключить оттуда неиспользуемые поля и исключить возгонку прав. Мы также отменим регистрацию админки для групп, поскольку вовсе не собираемся использовать группы в этом проекте. Разместим следующий код над кодом админки для проекта, поскольку админка пользователей должна быть зарегистрирована к тому моменту, когда список пользователей используется в полях autocomplete: Вы можете сейчас запустить админку, чтобы убедиться, что раздел аутентификации и авторизации содержит только админку пользователей, а также зарегистрировать нового пользователя (с установленным флагом is_staff и сброшенным флагом is_superuser), открыть приложение от его имени и увидеть, что он вообще никаких прав не имеет и ничего не может поменять, кроме своего пароля. Теперь, нам понадобится вспомогательное приложение authorize. В этом приложении, мы создадим схему управления правами, в которой укажем все взаимоотношения между объектами для определения прав доступа к ним. Отдельное приложение нужно для того, чтобы иметь хорошо определенную последовательность инсталлированных приложений. Мы разместим приложение authorize в конце списка INSTALLED_APPS в файле settings.py, чтобы к моменту регистрации прав все модели точно были известны системе. Выполним команду python manage.py startapp authorize и перейдем к редактированию файла models.py. Вместо определения моделей, мы разместим в нем все определения схемы доступа. Мы пользуемся тем фактом, что все модули models.py, содержащиеся в зарегистрированных приложениях, импортируются по очереди в процессе запуска файла проекта, в том порядке, в котором они перечислены в списке INSTALLED_APPS. Таким образом, права доступа будут регистрироваться после того, как все остальные приложения уже сообщили список своих моделей системе. Прежде всего, сообщим системе, что любой пользователь (кроме суперпользователя) не имеет никакого доступа к личной информации другого пользователя, кроме доступа на чтение. Дадим полный доступ к своей информации пользователю, имея в виду, что мы ограничили ему доступ к админке так, что он не сможет выполнить возгонку прав до суперпользователя. Также, разрешим пользователям с правами управления доступом к проекту, добавлять в систему других пользователей и видеть список всех пользователей, но не менять информацию о них после создания. Остальные пользователи, кроме суперпользователя, смогут увидеть в системе список только тех пользователей, которые относятся к тому же проекту, что и данный пользователь. Пользователь, не состоящий ни в одном проекте, увидит в этом списке только себя. Да мне тоже, на самом деле. В реальном проекте, была использована система регистрации через социальные сети, поэтому пользователи сами могли регистрировать себе аккаунт в системе, а менеджеры проектов — только добавлять пользователей в свой проект по необходимости. В этом же примере, система регистрации через соцсети удалена для упрощения. Вы можете добавить ее сюда сами и изменить права доступа в соответствие с новыми правилами. Теперь определим порядок доступа к информации о проектах и членстве в них. Во-первых, определим, что никакой пользователь, кроме суперпользователя, не может ни добавить проект в систему, ни удалить его. Также установим, что пользователи, которые являются членами проекта, могут видеть список и данные проектов, в которых они состоят. Во-вторых, пользователи, которые имеют права управления проектом, могут менять этот проект и членство других пользователей в проекте. Остальные пользователи видят проекты и членство в проектах, в которых состоят, но не могут изменять эти данные. Теперь, мы можем определить правила доступа пользователей к остальным объектам, через записи о членстве в проектах и распределенных в этих проектах правах. Все эти объекты мы будем считать доступными пользователю для изменения и удаления, если эти объекты принадлежат к одному из проектов, в которых пользователь имеет членство с установленным флагом allow_change. Кроме того, мы должны обработать особые случаи — когда пользователь, не принадлежа к проекту, является исполнителем (водителем) или клиентом проекта. Объектов, ссылающихся на пользователя, у нас несколько: Учтем это в правилах доступа. Мы не будем ограничивать право создания новых объектов, так как модель запрещает создание объектов с незаполненным полем ссылки на проект. В настоящий момент, пакет Django-Access не может запретить добавление объектов в проект, который мы хотим сделать доступным только для чтения, поскольку не проверяет состав полей объекта перед его созданием. Необходимо как-то ограничить список проектов, для которых пользователь может создать объект. Мы сделали это через метод админки, ограничивающий список выбора проектов. Поскольку у нас ссылка на проект везде называется project, мы написали практически одинаковый метод для всех админок, в которых есть ссылка на проект. Для объектов ProjectMember: Для остальных объектов: (на место многоточия… мы подставим класс админки). Осталась последняя деталь. По умолчанию, для совместимости со штатной системой прав Django, пакет Django-Access определяет порядок доступа ко всем моделям, для которых такой порядок явно не определен, как совместимый с Django. Этим занимается плагин access.plugins.DjangoAccessPlugin, установленный, как плагин по умолчанию. Переопределим плагин по умолчанию с помощью файла настроек settings.py. Для этого объявим свой простой плагин, запрещающийдоступ к объекту для всех, кроме суперадмина, и зададим его, как плагин по умолчанию в файле настроек. settings.py Мы рассмотрели почти реальную систему, содержащую информацию, доступ к которой должен регулироваться сложными правилами, основанными на отношении объектов к другим объектам системы. С помощью пакета Django-Access, мы сформулировали почти все необходимые правила, а оставшиеся детали ограничения доступа смогли реализовать путем небольших изменений в админке. Все правила ограничения доступа мы сформулировали в форме запросов к СУБД. Вы можете посмотреть полные исходники работающего приложения на репозитории GitHub