bgarcial
bgarcial

Reputation: 3213

Override the save() method

I have a custom users schema in Django for work with roles or users type, creating an application named userprofile which will be or will setup my custom user model.

In my settings.py I have the following configuration:

INSTALLED_APPS = [
        ...
    'userprofile',
]
#Custom model Users
AUTH_USER_MODEL = 'userprofile.User'

I customize my User class (userprofile/models.py) that inherit of the AbstractUser class for add some fields to my User model due to my requirements demanded me.

I also create these another models for roles/profile users (MedicalProfile, PatientProfile, PhysiotherapistProfile) with their own fields or attributes

In addition MedicalProfile, PatientProfile, PhysiotherapistProfile have a OneToOneField relationship with my custom model/class User so:

from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save

class User(AbstractUser):
    is_medical = models.BooleanField(default=False)
    is_physiotherapist = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    slug = models.SlugField(max_length=100, blank=True)
    photo = models.ImageField(upload_to='avatars', null = True, blank = True)

    # Overriding the save method
    def save(self, *args, **kwargs):
    if self.is_medical:
        profile = MedicalProfile(user=self)
        super(User, self).save(self, *args, **kwargs)
        profile.save()


    # We get the profiles user according with their type
    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'

class MedicalProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PatientProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PhysiotherapistProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)

My Question

I want to focus my question in relation to the override process save() method:

def save(self, *args, **kwargs):
    if self.is_medical:
        profile = MedicalProfile(user=self)
        super(User, self).save(self, *args, **kwargs)
        profile.save()

I want, each that an user is created, automatically be created their profile (MedicalProfile, PatientProfile, PhysiotherapistProfile) according to if their field checked (is_medical, is_patient, is_physiotherapist)

The inconvenient that I have is with my override process is the following:

enter image description here

I don't know about it, in relation of the reason by which is setup the user PK to None ...

What alternatives can I have for solve this situation and when I create an user, their profile instance be saved (MedicalProfile, PhysiotherapistProfile, PatientProfile) depending of the attribute checkbo/field (is_medical, is_physiotherapist , is_patient) that I choose?

I bring to all my apologies before, in case of the my question do not be suited or appropriated with the stackoverflow philosophy or by the extense of my question.

The reason that it's extense is that I want give all details for get an answer

Any orientation I will be grateful and will be appreciated

Upvotes: 2

Views: 2119

Answers (2)

bgarcial
bgarcial

Reputation: 3213

My class User located in userprofile/models.py is overriding the save method, stayed so:

class User(AbstractUser):
    is_medical = models.BooleanField(default=False)
    is_physiotherapist = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    slug = models.SlugField(max_length=100, blank=True)
    photo = models.ImageField(upload_to='avatars', null = True, blank = True)

    def save(self, *args, **kwargs):
        user = super(User, self).save( *args, **kwargs)

        # Creating and user with medical, patient and physiotherapist profiles
        if self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
                and self.is_patient and not PatientProfile.objects.filter(user=self).exists()\
                and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            patient_profile=PatientProfile(user=self).save()
            physiotherapist_profile=PhysiotherapistProfile(user=self).save()
            #profile.save()

        # Creating and user with medical and patient profiles
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
            and self.is_patient and not PatientProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            patient_profile=PatientProfile(user=self).save()

        # Creating and user with medical and physiotherapist profiles
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
            and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            physiotherapist_profile=PhysiotherapistProfile(user=self).save()

        # Creating and user with physiotherapist and patient profiles
        elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists()\
            and self.is_patient and not PatientProfile.objects.filter(user=self).exists():

            physiotherapist_profile = PhysiotherapistProfile(user=self).save()
            patient_profile = PatientProfile(user=self).save()

        # Creating and user with medical profile
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists():
            profile = MedicalProfile(user=self)
            profile.save()

        # Creating and user with patient profile
        elif self.is_patient and not PatientProfile.objects.filter(user=self).exists():
            profile = PatientProfile(user=self)
            profile.save()

        # Creating and user with physiotherapist profiles
        elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():
            profile = PhysiotherapistProfile(user=self)
            profile.save()



    # We get the profiles user according with their type
    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

    # We redefine the attributes (create db_table attribute) in class Meta to say to Django
    # that users will save in the same table that the Django default user model
    # https://github.com/django/django/blob/master/django/contrib/auth/models.py#L343
    class Meta:

        db_table = 'auth_user'

class MedicalProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PatientProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PhysiotherapistProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)

# Enter the username as slug field
@receiver(post_save, sender = settings.AUTH_USER_MODEL)
def post_save_user(sender, instance, **kwargs):
    slug = slugify(instance.username)
    User.objects.filter(pk=instance.pk).update(slug=slug)

the save() method let me save the users with all possible combinations of profiles.

But, is there a better way to do this?

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 600041

You need to do something in your save method if the user is not medical; you still need to actually save the object.

A fixed implementation would be:

def save(self, *args, **kwargs):
    user = super(User, self).save(self, *args, **kwargs)
    if self.is_medical:
        MedicalProfile(user=self).save()

Upvotes: 2

Related Questions