Я не знаю, является ли это повторяющейся темой, посвященной знанию того, когда работать со схемой аутентификации Django, как лучше всего ее использовать и расширять или ее заменяют пользовательской, но всегда с идеей сохранение механизмов и функций аутентификации.
В связи с вышеизложенным, я хочу поделиться своим беспокойством по поводу некоторых возможных альтернатив или подходов к проектированию, которые я обдумывал в следующей ситуации, в надежде, что они помогут мне проанализировать/предложить или выбрать лучший из них:
Я создаю приложение, в котором у меня есть три разных типа пользователей:
- Медицинский
- Пациент
- Физиотерапевт
Все три пользователя должны иметь возможность войти в систему, и должны быть отношения (из контекста бизнес-объекта приложения или требований) между пользователями-медиками с пользователями-пациентами и пользователями-физиотерапевтами с пользователями-пациентами, понимая, что :
- Больного лечит врач
- Больного лечит терапевт
- У пациента могут быть эти три роли в системе (я предполагаю, что это не будет проблемой)
Моя первоначальная идея — использовать стандартную схему аутентификации Django (django.contrib.auth).
Сначала я подумал о следующей схеме сущности, в которой модель/таблица User эквивалентна таблице auth_user, которую Django автоматически генерирует в нашей базе данных, когда мы применяем нашу первую миграцию, и в которой хранятся пользователи Django:
В этой таблице пользователей у меня есть три логических поля, которые я добавил:
is_patient
иis_medical
is_physiotherapist
Предыдущий, я думаю, это подход, который позволил бы мне делать то, что я ищу, только в том, что есть деталь, а именно то, что модель аутентификации Django по умолчанию не может быть изменена, она неизменна, я думаю, что изменить это вам пришлось бы модифицировать ядро Джанго а это что-то более дорогое или нужно было бы сделать это хорошо или знать что делается.
По этой причине поля is_patient
, is_medical
и is_physiotherapist
не могут быть добавлены в таблицу User, как я намеревался.
Классическая рекомендация, которую Django дает нам в своей документации, состоит в том, чтобы расширить модель User с отношением OneToOne на другую модель, содержащую дополнительные данные, которые мы хотим добавить пользователям. Основным примером того, что я говорю, является следующий рисунок:
Вот как я могу заставить пользователей, которые у меня есть в Django (управляемые схемой аутентификации Django по умолчанию django.contrib.auth
), иметь дополнительные атрибуты, такие как фотография, дата рождения и другие, которые нам нужны.
Что касается последнего, схема, которую я представляю ниже, может быть полезна для управления различными ролями пользователей, которые мне нужны?, то есть пациентами, врачами и физиотерапевтами.
У меня должны быть отношения между этими таблицами:
- Медицинские пользователи и пользователи-пациенты
- Пользователи-физиотерапевты и пользователи-пациенты и т. д. между ними и другими таблицами
При таком подходе эти отношения не пострадают?
Три разных типа пользователей, их атрибуты будут храниться между таблицами UserProfile и User.
Сама по себе таблица UserProfile будет содержать все поля пользователей пациентов, врачей и терапевтов.
Является ли это хорошей практикой с точки зрения масштабируемости? Я знаю, что они, конечно, не будут нормализованы.
Потому что другая альтернатива — подумать о моем первоначальном подходе, но без булевых полей is_patient
, is_medical
а is_physiotherapist
затем по транзитивности работать с разными ролями пользователей, то есть вот так:
В дополнение к вышеперечисленному также представлены некоторые альтернативы, такие как:
- Создайте таблицу/модель с именем Роль
Если у меня есть отдельная или независимая ролевая модель/таблица, и это будет связано с моделью пользователя Django, я могу сказать, что у пользователя может быть несколько ролей. Этот подход может быть полезен, если я хочу хранить уникальную информацию о конкретной роли.
Разрешения и авторизация Django На данный момент я не знаю степень детализации (насколько это позволит мне работать с моделями и их экземплярами с точки зрения операций с ними).
Я просмотрел, что система авторизации и разрешений позволит мне работать с операциями создания, редактирования и удаления.
Вы также можете посмотреть на создание групп, например, группы под названием «Врачи», к которой принадлежат медицинские пользователи, и что эта группа (и, следовательно, пользователи, которые ее составляют) могут иметь определенные разрешения на определенные модели и операции. Так и с другими типами пользователей.
Это еще одна хорошая альтернатива?
- AUTH_USER_MODEL Создание пользовательской модели пользователя
Другая альтернатива, представленная для случаев, когда схема управления пользователями по умолчанию Django не удовлетворяет требованиям аутентификации пользователей или управления в проекте, заключается в замене или настройке пользовательской модели, но я не знаю, будет ли это иметь свои недостатки с точки зрения не сохранение механизмов аутентификации и других функций, которые Django предоставляет нам в своей модели User.
Требует ли мое требование иметь пользователя-пациента, пользователя-медика и пользователя-физиотерапевта для создания пользовательской модели пользователей?
Все, что Django показывает нам об управлении пользователями и множестве вещей, которые они позволяют нам делать с этой темой, поначалу не является чем-то сложным само по себе, но из того, что я видел и с моей точки зрения, я осмеливаюсь утверждать, что это это довольно обширная тема, и по этой причине я чувствую себя несколько сбитым с толку, чтобы принять наилучшее решение в соответствии с тем, что мне нужно.
Если кто-то делал что-то подобное или у него есть предложения по руководству (я знаю, что это может быть очень частный случай, чтобы разместить это в бесплатном сообществе), я был бы очень благодарен.
Большое спасибо за ваше время и извинения за длинный пост.
Я взял на себя труд создать проект, чтобы иметь возможность формировать ваш случай, который, кстати, я нахожу довольно интересным, поскольку не исключено, что я наткнусь на что-то подобное через несколько месяцев для проекта.
Я создал проект
hospital
(это первое, что пришло в голову) с помощью Django 1.9. Теперь да, как сказал Джек Потрошитель, давайте по частям .По поводу вашего комментария:
Это, на мой взгляд, немного облегчает вам задачу, вы забываете об утомительных регистрациях, вы создаете своего суперпользователя (с
createsuperuser
), а затем создаете необходимых системных пользователей и, самое главное, вы (я предполагаю, что вы системный администратор) вы будете контролировать, кто что может делать. Я также предполагаю, что вы не хотите, чтобы вас беспокоили каждый раз, когда они хотят создать пользователя, поэтому вы будете давать инструменты другим пользователям с меньшими привилегиями, чтобы они могли создавать новых пациентов и даже врачей и физиотерапевтов, что-то вроде «супер доктор".Помните, что аутентификация (пользователи, пароли) и авторизация (группы, разрешения) — это проблемы, которые мы должны решать отдельно.
Сказав это, мы можем начать с проблемы нескольких пользователей. Я был бы склонен работать с вашей первоначальной идеей, расширить a,
User
чтобы иметь логические значения и обрабатывать три типа профилей для каждого из них, я думаю, что с этим будет проще справиться, когда вы хотите войти в часть авторизации и добавить, например, пользователяdoctor
в группуfisioterapeuta
илиpaciente
.Каждая группа будет иметь свои привилегии, и пользователь может принадлежать к одной или нескольким группам, например, у вас может быть врач, который также является пациентом.
Теперь да, давайте перейдем к некоторому коду. Начну с противоречия вашему утверждению:
Ну, это не неизменно. Вы можете выбрать между использованием AbstractBaseUser или
AbstractUser
, разница в том, что этоAbstractBaseUser
пользователь без полей Django, но он содержит всю логику аутентификации, при этом у негоAbstractUser
есть все поля, которые вам дает Django. Что мы будем делать, так это расширять пользователя , так как мы не хотим создавать нашу собственную модель пользователя, но мы хотим добавить несколько логических полей.Во-первых, мы сообщаем Django, что хотим использовать нашу собственную пользовательскую модель (я создал одно приложение под названием
usuario
):Индивидуальная модель. Чтобы не чувствовать себя слишком плохо, я использую то же имя таблицы, что и Django (
auth_user
):Затем сам Django предлагает, чтобы первое, что вы делаете при расширении пользователя, — это создание миграции, поэтому мы запускаем команду, а также попутно создаем суперпользователя:
С помощью быстрого запроса
shell
мы можем увидеть новые поля:Как вы только что видели, вполне возможно расширить пользователя. Теперь нам нужны профили. Поскольку профили относятся только
OneToOne
к нашему пользователю, мы можем создать все профили, которые захотим (я создам только пару полей для каждого):Nuevamente, creamos la migración y migramos:
Listo, ¡ya replicamos tu idea original!
Autenticación
Veamos si es posible autenticar el usuario. No voy crear todo un login completo, solo haremos uso de
authenticate()
para demostrarlo. Hagámoslo desde elshell
:Perfecto, funciona. Un dolor de cabeza menos, ya sabemos que incluso habiendo creado nuestro propio modelo de usuario heredado del
User
de Django, el proceso de autenticación funciona como debería. La forma en la que haces la autenticación finalmente es tarea tuya (usando el sistema de autenticación Django, OAuth2, Social Auth, etc.).Autorización
Como mencioné anteriormente, bastará por el momento con crear tres grupos:
doctor
,fisioterapeuta
ypaciente
. Antes de continuar, podemos crear algunas funciones en nuestro modeloUser
para obtener los perfiles de acuerdo al tipo de usuario.Esto nos ayudará, ya que cuando usas la relación
OneToOneField
y esta relación no existe, te genera el errorRelatedObjectDoesNotExist
:Pero, si usamos nuestra nuevas funciones, no generará error porque estamos validando previamente que existe el atributo:
Muy bien, entonces estas funciones nos servirán de mucho. Como ejemplo, en alguna de tus vistas podrías usarlas de esta forma para obtener los perfiles de acuerdo al usuario logueado:
Bien, para ver el tema de los grupos, creemos solo un doctor y un paciente: "Dr. House" y "Jorge Enfermizo". No quiero llenar esto de capturas de pantalla ya que esto es fácil de hacer desde el admin, pero hagámoslo desde el
shell
:Listo, ahora creemos los grupos de los usuarios:
Agregamos los usuarios a su grupo correspondiente, digamos que Dr. House también puede ser un paciente:
Ahora, solo bastará con preguntar para saber si un usuario pertenece a cierto grupo, en algunas de tus vistas:
Finalmente, solo quedaría que a los grupos creados, les agregues los permisos que quieres que tenga cada uno y en las vistas uses tus mecanismos para comprobar que el usuario pueda hacer solo lo que su grupo le permite.
Notas finales
Siempre lo digo, no reinventes la rueda a menos que sea por temas didácticos.
Si quieres autenticar usuarios:
Si quieres validar la parte de autorización:
Si se te antoja usar registro de usuarios:
Si quieres un template gratuito, actualizado y muy bueno:
Es muy interesante tu caso de uso, probé una solución un poco mas sencilla, no estoy seguro si cumple a cabalidad con tus requerimientos, en esta solución se puede usar
django.contrib
sin complicaciones para login y demás.Eso sí agregando cada usuario a un grupo de usuarios de Django para posteriores filtros en los views, un usuario puede pertenecer a N grupos sin problemas, desde el sitio de administración puedes asignar a los usuarios a determinados grupos.
Perdón por la informalidad del código, pero es una vista global de como se puede construir la base de datos, los atributos son valores de pruebas.
models.py
Se me viene a la cabeza que la clase
PacienteEspecializado
puede ser una historia clínica o cualquier otra cosa.Al registrarlos en
admin.py
, el código sobra pero bueno.admin.py
Si tienes alguna pregunta o la solución tiene algún error házmelo saber.
Un saludo amigo. Yo uso un enfoque similar al tuyo, creando grupos de usuarios en Groups de Django. Extendiendo el modelo con un modelo "Usuario" y un FK hacia User (Todos mis roles requieren los mismos campos).
Las ultimas funciones aseguran que la creación de un "Usuario" se relacione directamente con la creación de un "User". Lo hice siguiendo este tutorial: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone
Otra recomendación es que protejas los templates. No sé que tan recomendable sea puesto que no he hecho protección desde las vistas. Yo he agregado un templatetag en la app usuarios:
Este es el código de user_tags.py:
Luego simplemente la cargas con "load" en tu template. https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/
Ahora, tu app es requerida para un sólo un hospital. Mi problema surgió cuando un usuario tiene varios roles en varias empresas, es decir, es técnico en una y cliente en otra, en ese caso se actualizó el fk hacia empresa, y ahora tiene las reparaciones de la empresa en la que es cliente.
Estoy en este dilema, necesitaría extender la tabla
y añadir empresa_id. Así podría seleccionar a que empresa pertenece el rol en el que se está desempeñando, y al estar los templates protegidos no tendría acceso a ciertas vistas. Espero te sirva y te dejo el enfoque, por si tu app crece y la requieras utilizar en múltiples hospitales, y te evites este quebradero de cabeza en el que estoy.
Ознакомьтесь с этим руководством, если оно поможет: https://simpleisbetterthancomplex.com/tutorial/2018/01/18/how-to-implement-multiple-user-types-with-django.html
Удачи и программирования!