I am working on an application in which I have three different types of users or roles (Patient, Doctor and Physiotherapist)
The concerns that I will state in this question derive from this initial post that I made and from the illustrative answer that I received from @cesar-bustios
I will recapitulate a little the answer I got from the previous post that I refer to in order to provide the complete example here in my question and be able to have more elements of analysis.
1. A custom users model has been created After creating the Django project, create the application called userprofile
# settings.py
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'userprofile',
]
# Seleccionamos que userprofile establezca el manejo de nuestros usuarios
AUTH_USER_MODEL = 'userprofile.User'
2 . We create our user schema (roles Patient
, Medical
, and Physiotherapist
)
# userprofile/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.
# Creamos la clase User que hereda de AbstractUser para adicionar
# tres atributos booleanos `is_medical`, `is_physiotherapist`, e `is_patient`
class User(AbstractUser):
is_medical = models.BooleanField(default=False)
is_physiotherapist = models.BooleanField(default=False)
is_patient=models.BooleanField(default=False)
# Obtenemos los perfiles de cada usuario acorde a su tipo
def get_medical_profile(self):
medical_profile = None
if hasattr(self, 'medicalprofile'):
medical_profile=self.medicalprofile
return medical_profile
def get_patient_profile(self):
patient_profile = None
if hasattr(self, 'patientprofile'):
patient_profile = self.patientprofile
return patient_profile
def get_physiotherapist_profile(self):
physiotherapist_profile = None
if hasattr(self, 'physiotherapistprofile'):
physiotherapist_profile = self.physiotherapistprofile
return physiotherapist_profile
class Meta:
db_table = 'auth_user'
# Le decimos que estos campos vayan a la tabla auth_user
# de igual nombre que la de django.contrib.auth
# Creamos un modelo Profile por cada rol o tipo de usuario
# `Medical`, `Physiotherapist`, y `Patient` en donde en cada uno
# almacenaremos datos propios de cada rol de usuario
class MedicalProfile(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PatientProfile(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PhysiotherapistProfile(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
I have seen that when inheriting from the class AbstractUser
to create a custom user model using AUTH_USER_MODEL
, when we perform the first migration, I see that we do not have the User module in the admin since we have customized it using AbstractUser, and so it is necessary to register it from manually in my admin.py file with the attributes that User handles in Django.
At the end of the day this is no problem, it logs:
3. Registering the classes/models User
, PatientProfile
, MedicalProfile
and PhysiotherapistProfile
in the Django admin
Detail that in the case of class UserAdmin
, we are inheriting from admin.ModelAdmin
#userprofile/admin.py
from django.contrib import admin
from .models import User, PhysiotherapistProfile, PatientProfile, MedicalProfile
from django.contrib.auth.admin import UserAdmin
# Registramos el modelo User con los atributos por defecto que
# Django provee, además de los atributos booleanos
# 'is_medical','is_patient','is_physiotherapist'
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('id','username','password','first_name','last_name',
'email','is_staff','is_active','is_superuser',
'is_medical','is_patient','is_physiotherapist',
'last_login','date_joined')
# Registramos los modelos para cada tipo de usuario
@admin.register(PatientProfile)
class PatientAdmin(admin.ModelAdmin):
list_display = ('id','name','active','user_id',)
@admin.register(MedicalProfile)
class MedicalAdmin(admin.ModelAdmin):
list_display = ('id','name','active','user_id',)
@admin.register(PhysiotherapistProfile)
class PhysiotherapistAdmin(admin.ModelAdmin):
list_display = ('id','name','active','user_id',)
So when migrating and when we go to the admin via the web, we detail that we already have the models Users
, PatientProfile
, MedicalProfile
, andPhysiotherapistProfile
If I enter User, and edit a user, I can detail that I have added the three boolean attributes is_medical
, is_patient
,is_physiotherapist
In the same way when I want to create a user in the administrator, I have these same three attributes available:
But one of the things that I detail is that when I am creating the user, the Password text field does not encrypt the content that one writes:
And by storing it like this, therefore, it is also displayed in plain text when we look at the list of users:
4. Making the Password field appear encrypted
django admin and django in general use PBKDF2 by default as encryption mechanism or function
In this post they say that when we register a model that inherits from AbstractUser
, in the class that we create for its registration in the admin.py file, it must be inherited from the class UserAdmin
and not from the admin.ModelAdmin that we use to register the models in the administrator from Django. By doing this, UserAdmin makes my password field come out encrypted both when entered and when I view it.
We make our User
custom model inherit from UserAdmin
instead of admin.ModelAdmin
#userprofile/admin.py
# Hacemos que nuestro modelo User personalizado
# herede de UserAdmin en lugar de admin.ModelAdmin
@admin.register(User)
class UserAdmin(UserAdmin):
list_display = ('id','username','password','first_name','last_name','email','is_staff','is_active','is_superuser','is_medical','is_patient','is_physiotherapist','last_login','date_joined')
After making this change, if I want to create a user, the field to enter the password is protected:
As well as if I want to view it after I have saved said previously created user:
The fact that we inherit from UserAdmin
and not from admin.ModelAdmin
, solves the problem so that the passwords are encrypted or "hased" in the Django administrator, but then, already inheriting from UserAdmin, if I am going to create a new user in User, the fields do not appear or attributes we added earlier from is_patient
, is_physiotherapist
and fromis_medical
These attributes no longer appear, on user creation, which were ultimately the reason to create a custom model and inherit fromAbstractUser
Es lógico, no aparecen, porque ya estoy heredando de UserAdmin
y asumo que al hacer esto, el sobreescribirá los campos que colocará en el administrador, los cuales asumo que son todos los de por defecto de Django menos los tres atributos booleanos de is_patient
, is_physiotherapist
y de is_medical
que yo he agregado antes.
Tengo esa inquietud.
¿Qué mecanismo habría para que con nuestro modelo personalizado quede el password hasheado en el admin?
o
Que cuando heredemos de UserAdmin,¿cómo podemos tambien ver reflejados los campos adicionados en el admin como is_patient
, is_physiotherapist
y de is_medical
?
A veces me pregunto si son tan necesarios estos tres campos booleanos is_patient
, is_physiotherapist
y de is_medical
o con el solo hecho de tener User
relacionado con PatientProfile
, con MedicalProfile
y con PhysiotherapistProfile
, sería suficiente para tener estos tres roles de usuario y que cada uno tenga sus propios privilegios, como lo tengo en este acercamiento
Claro esto es algo que yo debo probar.
Cualquier ayuda, consideración o aporte será altamente apreciado. Muchas gracias.
Quiero comenzar diciendo que si existiera una medalla por posts largos te la ganarías :)
Vamos, el tema con el
UserAdmin
es que está hecho exclusivamente para el usuario original de Django y usa formularios de creación y edición especiales para ese modelo. Lo que tienes que hacer entonces es heredarlos y modificarlos a tu gusto.Our file names may differ since I created the project in your first question and am using that same project.
Once our forms have been created, the only thing they do is change the original model to our custom model, we must also create a
UserAdmin
custom one to use these forms:This should be enough. Tell me how it goes.