User roles schema on Django

做~自己de王妃 提交于 2019-12-05 09:27:37

In this situation, especially if you want to store different infos for Patients, Medics and Physiotherapists you can create a Model for each and have a OneToOne field for each to the User model.

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

This way you can give different permissions/roles implicitly in your application logic for each type of user (and still use the groups and permissions that Django offers if you need them for special cases, eg ChiefMedical...).

You will have to define some methods for your application logic like

def user_is_patient(user):
     ...

If you follow this path it is a good idea to have good tests to make sure that you don't get unexpected things like a user who is a Medic and a Physio...

Django lets you subclass the user model as well. Under the covers it would do the same thing as the code above, so it is probably better to do it explicitly as shown above (this way it is less probable that you access attributes that don't exist in that object!)

Taking advantage of the previous, The following schema can be suited or can be an alternative for manage user roles (patient, medical and physiotherapist user types) ?

The schema you show isn't great because it makes you store the information for all user types in the same table (and with the same fields). For example, Medics and Physios will have a blood type field type like Patients which will probably not be defined.

The different users will be saved between the Users and UserProfile table. Is this a good practice in the scalability sense? My tables could be crash or my database?

There should be no scalability problems with this solution (as long as you don't have millions new entries writes every day) and you can always optimise the database at a further point. However, you will have to make sure that your app doesn't accept 'forbidden' entries (e.g. users with no Medic, Physio or Patient profile)

Here, can I see the groups creation? For example a medical group and allocate them permissions and linked this permissions to the users that compose the group ? Is this another good alternative? This option seem more single although I don't know if an user could make some operations according to the group privileges that have ... I don't know if this thinking is correct/right

You can (should) use Django's permission system to give permissions to your users. You can use them to give different rights to users of the same type (for example Medics that have more permissions than others... or have groups for chief physios...)

Django lets you assign permissions to a group.

But I don't think groups can replace the custom models for each user, since you want to store information for them. Having custom models and groups would be redundant and make your app harder to maintain.

My requirements for patient, medical and physiotherapist users, require build a custom user model?

This option wouldn't be great (unless it is your only option) because your app won't be reusable and you might have problems with some packages as well.

You can create a custom User model or not, in any case, you could have three separate models for storing pertinent data, depending on whether the user is patient, medical, physiotherapist, or any combination of these.

If your permissions scheme is determined solely by the role (patient, medical, physiotherapist) then you don't need to use Django's permissions system, because you know the role(s) of any user and you can, in the worst scenario, hardcode authorization rules.

I gave a glance at question's comments and I view some issues:

(

)

I realized that your user model does not match with the original data model since having get_medical_profile, get_patient_profile and get_physiotherapist_profile functions inside user model, with that you are assuming that any user could have multiple profiles at the same time, which isn't reflected neither in your profile models (Medical, Patient and Physiotherapist) using OneToOneField nor in original data model of the question, it's an important thing about abstraction and class-responsibility. The requirement (according the model below) seems to say "one user can have only one profile".

So.. I think this can be solved in a straightforward and clean way, you don't need to involve in overall authentication esquema like groups and permissions or adding additional attributes to user model:

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

As you see, you can have a profile which contains common fields shared by all profiles. and each profile has an specific model.

In addition, you can check if user is medical by this small function below, then if there is no an medical profile associated with profile then it will raise exception and it means it's a profile unspecified:

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

You can also use it in your templates (as a custom template tag) in this way:

{% if profile | is_medical_profile %}

With this approach you don't need to setup AUTH_USER_MODEL

I hope this improves your solution.


Additional notes:

Just in case you decide to have a custom user model, setup settings.AUTH_USER_MODEL and use it for foreign keys to User.

On a piece of text of awesome book Two scoops of Django says:

From Django 1.5 onwards, the official preferred way to attach ForeignKey, OneToOneField, or ManyToManyField to User

Therefore, your user profile model would change as follows:

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

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

Yes, it looks a bit strange, but that's what the official Django docs advice.

bgarcial

@geoom @Ire @lorenzo-peña I 've created an user through Django admin site and I checked their attributes (is_medical, is_patient, is_physiotherapist) via python shell

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}]

For the moment in my views.py I am doing that an user sign in only when this be one of three user types (medical, patient or physiotherapist)

# 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

If I check the other possible combinations (User patient,medical and physiotherapist) this could work?

I think create groups for (Medicals, Patients, Physiotherapists) and binding users for the authorization topic, although I should review other things for authorization process such as django guardian for example?

How about this?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!