Home > Enterprise >  How do I register a custom user type in Django 4.1?
How do I register a custom user type in Django 4.1?

Time:12-31

So, I am a beginner and I'm coding a django application that has a 3 user types in total but to make the code readable and understandable I'm just gonna assume we have 2 user types. One is a doctor and one is a patient.

I've created this custom user so far:

in models.py

class User(AbstractUser):
    is_doc = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)

    objects = UserManager()

manager.py

class UserManager(BaseUserManager):

    def create_user(self, email, password=None):

        if email is None:
            raise TypeError('Users must have an email address.')

        user = self.model(email=self.normalize_email(email))
        user.set_password(password)
        user.save()

        return user
    def create_patient(self, email, password):
        if password is None:
            raise TypeError('Must have a password')
        
        user = self.model(email=self.normalize_email(email))
        user.set_password(password)
        user.is_patient = True
        user.save()

    def create_superuser(self, email, password):

        if password is None:
            raise TypeError('Superusers must have a password.')

        user = self.create_user(email, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()

        return user

Patient Model is as follows:

class Patient(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=70)
    last_name = models.CharField(max_length=70)
    address = models.CharField(max_length=210)
    phone = models.CharField(max_length=15)
    email = models.EmailField(max_length=110)
    password = models.CharField(max_length=65)

    def __str__(self):
        return self.first_name   " "   self.last_name

My form for Patient:

class PatientForm(forms.ModelForm):

    class Meta:
        model = Patient
        fields = ['first_name', 'last_name', 'address', 'phone', 'email', 'password']

        widgets = {
            'first_name': forms.TextInput(attrs={'placeholder': 'First Name'}),
            'last_name': forms.TextInput(attrs={'placeholder': 'Last Name'}),
            'address': forms.TextInput(attrs={'placeholder': 'Address'}),
            'phone': forms.TextInput(attrs={'placeholder': 'Phone Number'}),
            'email': forms.EmailInput(attrs={'placeholder': 'Email'}),
            'password': forms.PasswordInput(attrs={'placeholder': 'Password (Minimum Length: 8)'}),
        }

Current Views.py:

def RegPatient(request):
    if request.method == "POST":
        form = PatientForm(request.POST)
        if form.is_valid():
            FName = form.cleaned_data['first_name']
            LName = form.cleaned_data['last_name']
            C_Address = form.cleaned_data['address']
            C_Phone = form.cleaned_data['phone']
            C_Email = form.cleaned_data['email']
            C_Password = form.cleaned_data['password']
            Reg = Patient(first_name= FName, last_name= LName, address= C_Address, phone= C_Phone, email= C_Email, password= C_Password)
            Reg.save()
            return HttpResponseRedirect('/Login/')

        else:
            for field in form.errors:
                form[field].field.widget.attrs['class']  = ' is-invalid'
            return render(request, 'Home/RegPatient.html', {'form': form})
    
    else:
        form = PatientForm()
        return render(request, 'Home/RegPatient.html', {'form': form})

I have separate signups for patient and doctor and don't want a user type field in my form so I have all the detail fields in my form except user type. How should my view look like so that it saves Patient with a user type is_patient? and am I missing something out? Cause I've tried to edit it so many times, tried getting help from Django Docs but I'm still stuck.

CodePudding user response:

First, lets talk about the Manager and Models. The Manager you are using is not really necessary, its possible to just set up the field on User object creation. As for the Model you can use model inheritance to have an extended Patient model based on your User model:

class User(AbstractUser):
    is_doctor = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)

class Patient(User):
    address = models.CharField(max_length=210)
    phone = models.CharField(max_length=15)

    class Meta:
        verbose_name_plural = "Patients"

Although, I would say the right approach to your problem is to use Django authentication groups, instead of adding fields to your User model.

As for the signup form, it should contain confirmation and validation of the password and the username field unless you are doing a login with email. To hold the information of is_patient field, use an HiddenInput (I couldn't replicate it with 'ModelForm' will need to dig further into that.):

forms.py

from django.contrib.auth.hashers import make_password
from django.forms import ValidationError

class PatientSignUpForm(forms.Form):
    username = forms.CharField(
        required=True, 
        widget=forms.TextInput(attrs={'placeholder': 'username'}))

    first_name = forms.CharField(
        required=True, 
        widget=forms.TextInput(attrs={'placeholder': 'first name'}))

    last_name = forms.CharField(
        required=False, 
        widget=forms.TextInput(attrs={'placeholder': 'last name'}))

    email = forms.EmailField(
        required=True, 
        widget=forms.TextInput(attrs={'placeholder': 'email'}))

    address = forms.CharField(
        required=True, 
        widget=forms.TextInput(attrs={'placeholder': 'address'}))

    phone = forms.CharField(
        required=True, 
        widget=forms.TextInput(attrs={'placeholder': 'XXX-XXXXXXXXX'}))

    password = forms.CharField(required=True, widget=forms.PasswordInput)

    password_confirmation = forms.CharField(required=True, widget=forms.PasswordInput)

    is_patient = forms.BooleanField(widget=forms.HiddenInput)

    def clean(self):
        password = self.cleaned_data['password']
        password_confirmation = self.cleaned_data['password_confirmation']

        if len(password) < 8 or len(password_confirmation) < 8:
            raise ValidationError("Passwords must have at least 8 characters")
        elif password != password_confirmation:
            raise ValidationError("Passwords must be equal")
        else:
            self.cleaned_data['password'] = make_password(self.cleaned_data['password_confirmation'])
            del self.cleaned_data['password_confirmation']
            return self.cleaned_data

Lastly, in views.py create an instance of PatientSignUpForm with an initial value for is_patient field.

from app import models, forms

def patient_signup(request):
    if request.method == 'POST':
        form = forms.PatientSignUpForm(request.POST)
        if form.is_valid():
            models.Patient.objects.create(**form.cleaned_data)
            return redirect('')

    else:
        form = forms.PatientSignUpForm(initial={'is_patient': True})

    return render(request, 'patient_signup.html', {'form': form})
  • Related