Схема ролей пользователей в Django

Большое приветственное сообщество

Мой вопрос связан с типом управления пользователями и пользователями схемы в Django. В начале я прошу вас извиниться на тот случай, если мои вопросы могут быть слишком «новичками» или бессмысленными, я начинаю связывать меня с Django Схемы пользователей и их различные возможности работы в проектах.

У меня следующая ситуация.

Я создаю приложение, в котором у меня будет три разных типа пользователей:

  • Медицинский
  • Пациент
  • Физиотерапевт

Я использую схему аутентификации Django по умолчанию (django.contrib.auth).

Первоначально я думал об этой схеме сущностей, в которой таблица User является таблицей auth_user, в которой Django сохраняет созданных пользователей:

Схема подумала (плохо - ?)

У меня есть поля is_patient, is_medical и is_physiotherapist, такие как логические атрибуты в таблице User.

Как конкретная деталь, я понимаю, что в модели Django по умолчанию Пользователь не может изменять или добавлять атрибуты или поля.

Это важная и веская причина, по которой я не могу добавить логические поля is_patient, is_medical и is_physiotherapist в таблицу User.

Классическая рекомендация — расширить модель пользователя с помощью таблицы профилей пользователей, в которой я добавляю поля или атрибуты в модель пользователя через отношения OneToOne. Базовый образец выглядит следующим образом:

Расширение модели пользователей Django

Таким образом, я понимаю, что мои пользователи в Django могут иметь полевую фотографию и загружать ее в данный момент...

Воспользовавшись предыдущим, следующая схема может подойти или может быть альтернативой для управления ролями пользователей (типы пользователей patient, medical и physiotherapist)?

Думала другая схема

У меня будут отношения между:

  • Пользователь-медик и пользователь-пациент

  • физиотерапевт-пользователь и пациенты-пользователи

и так между ними и другими столами...

При таком подходе эти отношения не пострадают?

Различные пользователи будут сохранены между таблицами Users и UserProfile. Является ли это хорошей практикой в ​​смысле масштабируемости? Мои таблицы могут быть аварийными или моя база данных?


Кроме того, я также видел другие альтернативы, такие как:

  1. Ролевая Таблица/Модель

У меня будет таблица/модель ролей, независимая или отдельная, и это может быть связано с моделью пользователя Django (например, у одного пользователя может быть много ролей). Этот подход может быть полезен, когда я хочу хранить эксклюзивную информацию о роли в спецификации ?

  1. Разрешения и авторизация Django

Я игнорирую или не знаю степень детализации, которая позволяет мне работать. С одной стороны, я видел, что система разрешений и авторизации позволяет мне работать с операциями создания, редактирования и удаления ....

Здесь я могу увидеть создание групп? Например, медицинская группа и назначать им разрешения и связывать эти разрешения с пользователями, составляющими группу? Это еще одна хорошая альтернатива? Эта опция кажется более одиночной, хотя я не знаю, может ли пользователь выполнять некоторые операции в соответствии с групповыми привилегиями, которые имеют ... Я не знаю, правильно ли это мышление

  1. AUTH_USER_MODEL Создание пользовательской модели пользователя

Мои требования к пациентам, врачам и физиотерапевтам требуют создания пользовательской модели пользователя?


person bgarcial    schedule 10.12.2015    source источник
comment
эй, есть ли что-то пропущенное или неудовлетворительное в моем ответе? :) Было бы здорово получить отзыв!   -  person Ire    schedule 18.12.2015
comment
@Ire, твой ответ был очень полезен для меня. С некоторой другой ориентацией я решил настроить свою пользовательскую модель и связать ее с моделями Medic, Patient, Physio в отношениях OneToOne. ">cldup.com/lqB3367kAp.png - cldup.com/jxVsgfneGb.png) и когда я добавляю атрибуты в User, мне нужно настроить свои формы администратора, чтобы они отображались там.   -  person bgarcial    schedule 18.12.2015
comment
@Ire, я немного не понимаю, когда вы говорите: наличие пользовательских моделей и групп было бы излишним и усложнило бы обслуживание вашего приложения. На самом деле, я еще не пробовал процесс авторизации, но я согласен с вами в создании групп и запросе, существует ли конкретный пользователь (пациент, врач или физиотерапевт) и принадлежит ли он к группе ...   -  person bgarcial    schedule 18.12.2015
comment
Почему лучше сделать это явно, как показано ниже (таким образом, менее вероятно, что вы получите доступ к атрибутам, которые не существуют в этом объекте!) Вместо подкласса модели пользователя с помощью AbstractUser?   -  person bgarcial    schedule 18.12.2015


Ответы (4)


В этой ситуации, особенно если вы хотите хранить разную информацию для пациентов, медиков и физиотерапевтов, вы можете создать модель для каждого и иметь поле OneToOne для каждой модели пользователя.

class Medic(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    # other fields

class Physio(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    # other fields

class Patient(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    # other fields

Таким образом, вы можете неявно давать разные разрешения/роли в логике вашего приложения для каждого типа пользователя (и по-прежнему использовать группы и разрешения, которые предлагает Django, если они вам нужны для особых случаев, например, ChiefMedical...).

Вам нужно будет определить некоторые методы для логики вашего приложения, например

def user_is_patient(user):
     ...

Если вы пойдете по этому пути, неплохо было бы провести хорошие тесты, чтобы убедиться, что вы не получите неожиданных вещей, таких как пользователь, который является медиком и физиотерапевтом...

Django также позволяет создавать подклассы пользовательской модели. Под прикрытием он будет делать то же самое, что и приведенный выше код, поэтому, вероятно, лучше сделать это явно, как показано выше (таким образом менее вероятно, что вы получите доступ к атрибутам, которые не существуют в этом объекте!)

Воспользовавшись предыдущим, следующая схема может подойти или может быть альтернативой для управления ролями пользователей (пациент, врач и физиотерапевт)?

Схема, которую вы показываете, не очень хороша, потому что она заставляет вас хранить информацию для всех типов пользователей в одной таблице (и с одними и теми же полями). Например, в полях «Медики» и «Физиологи» будет тип поля «Группа крови», например «Пациенты», который, вероятно, не будет определен.

Различные пользователи будут сохранены между таблицами Users и UserProfile. Является ли это хорошей практикой в ​​смысле масштабируемости? Мои таблицы могут быть аварийными или моя база данных?

С этим решением не должно быть проблем с масштабируемостью (если у вас нет миллионов новых записей, записываемых каждый день), и вы всегда можете оптимизировать базу данных в дальнейшем. Однако вам нужно будет убедиться, что ваше приложение не принимает «запрещенные» записи (например, пользователи без профиля врача, физиотерапевта или пациента).

Здесь я могу увидеть создание групп? Например, медицинская группа и назначать им разрешения и связывать эти разрешения с пользователями, составляющими группу? Это еще одна хорошая альтернатива? Эта опция кажется более одиночной, хотя я не знаю, может ли пользователь выполнять некоторые операции в соответствии с групповыми привилегиями, которые имеют ... Я не знаю, правильно ли это мышление

Вы можете (должны) использовать систему разрешений Django, чтобы давать разрешения своим пользователям. Вы можете использовать их, чтобы предоставить разные права пользователям одного и того же типа (например, медикам, у которых больше прав, чем у других... или есть группы для главных физиотерапевтов...)

Django позволяет назначать разрешения группе.

Но я не думаю, что группы могут заменить пользовательские модели для каждого пользователя, поскольку вы хотите хранить для них информацию. Наличие пользовательских моделей и групп было бы излишним и усложнило бы поддержку вашего приложения.

Мои требования к пациентам, врачам и физиотерапевтам требуют создания пользовательской модели пользователя?

Этот вариант не был бы хорошим (если только это не ваш единственный вариант), потому что ваше приложение нельзя будет использовать повторно, и у вас также могут возникнуть проблемы с некоторыми пакетами.

person Ire    schedule 13.12.2015

Вы можете создать пользовательскую модель пользователя или нет, в любом случае у вас могут быть три отдельные модели для хранения соответствующих данных, в зависимости от того, является ли пользователь пациентом, врачом, физиотерапевтом или любой их комбинацией.

Если ваша схема разрешений определяется исключительно ролью (пациент, врач, физиотерапевт), то вам не нужно использовать систему разрешений Django, потому что вы знаете роли любого пользователя и можете, в худшем случае, хардкодить правила авторизации.

person Lorenzo Peña    schedule 13.12.2015

Я взглянул на комментарии к вопросу и вижу некоторые проблемы:

(https://cldup.com/jxVsgfneGb.png)

Я понял, что ваша пользовательская модель не соответствует исходной модели данных, поскольку в пользовательской модели есть функции get_medical_profile, get_patient_profile и get_physiotherapist_profile, при этом вы предполагаете, что любой пользователь может иметь несколько профилей одновременно, что не отражено ни в ваши модели профиля (медицина, пациент и физиотерапевт), использующие OneToOneField, ни в исходной модели данных вопроса, это важная вещь в отношении абстракции и ответственности за класс. Требование (в соответствии с приведенной ниже моделью), похоже, гласит: «один пользователь может иметь только один профиль».

введите здесь описание изображения

Итак.. Я думаю, что это можно решить простым и понятным способом, вам не нужно участвовать в общей аутентификации, такой как группы и разрешения, или добавлять дополнительные атрибуты в пользовательскую модель:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    # common fields shared by medical, patient and physiotherapist profiles

class MedicalUser(models.Model):
    profile = models.OneToOneField(UserProfile)
    # medical fields here

class PatientUser(models.Model):
    profile = models.OneToOneField(UserProfile)
    # patient fields here

class PhysiotherapistUser(models.Model):
    profile = models.ForeignKey(UserProfile)
    # patient fields here

Как видите, у вас может быть профиль, который содержит общие поля для всех профилей. и каждый профиль имеет определенную модель.

Кроме того, вы можете проверить, является ли пользователь медицинским, с помощью этой небольшой функции ниже, тогда, если нет медицинского профиля, связанного с профилем, это вызовет исключение, и это означает, что профиль не указан:

def is_medical_profile(profile):
    try:
        profile.medical_user
        return True
    except:
        return False

Вы также можете использовать его в своих шаблонах (в качестве пользовательского тега шаблона) следующим образом:

{% if profile | is_medical_profile %}

При таком подходе вам не нужно настраивать AUTH_USER_MODEL

Я надеюсь, что это улучшит ваше решение.


Дополнительные замечания:

На всякий случай, если вы решите использовать пользовательскую модель пользователя, настройте settings.AUTH_USER_MODEL и используйте ее для внешних ключей пользователя.

В отрывке из замечательной книги Two scoops of Django говорится:

Начиная с Django 1.5, официальный предпочтительный способ присоединения ForeignKey, OneToOneField или ManyToManyField к пользователю

Таким образом, ваша модель профиля пользователя изменится следующим образом:

from django.conf import settings
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)

Да, это выглядит немного странно, но именно так советует официальная документация Django.

person geoom    schedule 19.12.2015
comment
спасибо за рекомендации и лучшие практики: D. Ваш подход великолепен! Хотя, даже если я указываю отношение OneToOneField в своей модели данных, у пользователя может быть много профилей (медицинский, физиотерапевт и медицинский). Ниже в посте я сделал несколько тестов в cli - person bgarcial; 28.12.2015

@geoom @Ire @lorenzo-peña Я создал пользователя через административный сайт Django и проверил его атрибуты (is_medical, is_patient, is_physiotherapist) через оболочку Python.

In [6]: User.objects.filter(username='agarcial').values('is_medical','is_patient','is_physiotherapist')

Out[6]: [{'is_physiotherapist': True, 'is_patient': True, 'is_medical': True}]

На данный момент в моем views.py я делаю так, чтобы пользователь входил в систему только в том случае, если это один из трех типов пользователей (медицинский, пациент или физиотерапевт).

# Create your views here.


class ProfileView(LoginRequiredMixin, TemplateView):
    template_name = 'profile.html'
    def get_context_data(self, **kwargs):
        self.request.session['Hi'] = True
        context = super(ProfileView, self).get_context_data(**kwargs)
        is_auth = False
        name = None
        # Check if in the request goes the user
        user = self.request.user

        # Check about of possible cases (For now is one profile)
        if user.is_medical:
        #if self.request.user.is_authenticated():
            print (user.is_medical)
            is_auth = True
            profile=user.get_medical_profile()
            #name = self.request.user.username

            data = {
                'is_auth':is_auth,
                'profile':profile,
            }

            context.update({'userprofile':profile, 'data':data})
        elif user.is_patient:
            print (user.is_patient)
            is_auth=True
            profile=user.get_patient_profile()

            data = {
                'is_auth':is_auth,
                'profile':profile,
            }
            context.update({'userprofile':profile,'data':data})
        elif user.is_physiotherapist:
            print (user.is_physiotherapist)
            is_auth=True
            profile=user.get_physiotherapist_profile()

            data = {
                'is_auth':is_auth,
                'profile':profile,
            }
            context.update({'userprofile':profile,'data':data})
        return  context

    def get_userprofile(self):
        return self.request.user.userprofile

Если я проверю другие возможные комбинации (пользователь, пациент, врач и физиотерапевт), это может сработать?

Я думаю создать группы для (Врачи, Пациенты, Физиотерапевты) и привязать пользователей к теме авторизации, хотя я должен рассмотреть другие вещи для процесса авторизации, такие как django guardian например?

Как насчет этого?

person bgarcial    schedule 28.12.2015