Change inheritance to OneToOne‍ relation in Django models

369 Views Asked by At

I have models that have a inheritance relationship. I want to turn this relationship into a OneToOne‍‍‍‍‍‍‍‍ relationship, without removing any data in project.

This is structure of models:

class BaseFieldsModel(models.Model):
    create_date = DateTimeField(auto_now_add=True,)
    update_date = DateTimeField(auto_now=True,)
    created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss')  

class User(AbstractBaseUser,BaseFieldsModel):
    # Some fields


class Teacher(User):
    # Some fields

class Student(User): 
    # Some fields 

All things was good until I want to resructure my database because of this problem that I had in this design. In new DB model, I want to have something like this: (OneToOne Relation)

class User(AbstractBaseUser,BaseFieldsModel):
    # Some fields


class Teacher(BaseFieldsModel):
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='student_user')
    # Some fields

class Student(BaseFieldsModel): 
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='teacher_user')
    # Some fields   

So I did run makemigrations:

Migrations for 'UserManager':
  UserManager/migrations/0022_auto_20200425_1233.py
    - Change managers on student
    - Change managers on teacher
    - Add field create_date to student
    - Add field created_by to student
    - Add field update_date to student
    - Add field updated_by to student
    - Add field create_date to teacher
    - Add field created_by to teacher
    - Add field update_date to teacher
    - Add field updated_by to teacher
    - Alter field user_ptr on student
    - Alter field user_ptr on teacher

and then run migrate and got this error:

django.core.exceptions.FieldError: Local field 'create_date' in class 'Student' clashes with field of the same name from base class 'User'.

# Tested solutions

1.first failed solution:

Create Teacher and Student without inheritance form BaseFielsModel:

class User(AbstractBaseUser,BaseFieldsModel):
    # Some fields


class Teacher(models.Model):
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='student_user')

    create_date = DateTimeField(auto_now_add=True,)
    update_date = DateTimeField(auto_now=True,)
    created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss')  

    # Some other fields

class Student(models.Model): 
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='teacher_user')

    create_date = DateTimeField(auto_now_add=True,)
    update_date = DateTimeField(auto_now=True,)
    created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss')  

    # Some other fields 

Then run makemigrations:

Migrations for 'UserManager':
  UserManager/migrations/0022_auto_20200425_1240.py
    - Change managers on student
    - Change managers on teacher
    - Add field create_date to student
    - Add field created_by to student
    - Add field update_date to student
    - Add field updated_by to student
    - Add field create_date to teacher
    - Add field created_by to teacher
    - Add field update_date to teacher
    - Add field updated_by to teacher
    - Alter field user_ptr on student
    - Alter field user_ptr on teacher

Then migrate and again raise error:

django.core.exceptions.FieldError: Local field 'create_date' in class 'Student' clashes with field of the same name from base class 'User'.

2.Second failed solution:

Create Teacher and Student without BaseFielsModel and its fields:

class User(AbstractBaseUser,BaseFieldsModel):
    # Some fields


class Teacher(models.Model):
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='student_user')

    # Some other fields

class Student(models.Model): 
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='teacher_user')
    # Some other fields

Then run makemigrations:

Migrations for 'UserManager':
  UserManager/migrations/0022_auto_20200425_1243.py
    - Change managers on student
    - Change managers on teacher
    - Alter field user_ptr on student
    - Alter field user_ptr on teacher

and run migrate:

 Applying UserManager.0022_auto_20200425_1243... OK

Then add these fields to Student and Teacher:

create_date = DateTimeField(auto_now_add=True,)
    update_date = DateTimeField(auto_now=True,)
    created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss')  

Then run makemigrations:

Migrations for 'UserManager':
  UserManager/migrations/0023_auto_20200425_1245.py
    - Add field create_date to student
    - Add field created_by to student
    - Add field update_date to student
    - Add field updated_by to student
    - Add field create_date to teacher
    - Add field created_by to teacher
    - Add field update_date to teacher
    - Add field updated_by to teacher

And migrate:

django.core.exceptions.FieldError: Local field 'create_date' in class 'Student' clashes with field of the same name from base class 'User'.

3.Third successful solution (Bad practice)

Rename all fields that had clash with fields in User model:

class User(AbstractBaseUser,BaseFieldsModel):
    # Some fields


class Teacher(models.Model):
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='student_user')

    teacher_create_date = DateTimeField(auto_now_add=True,)
    teacher_update_date = DateTimeField(auto_now=True,)
    teacher_created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    teacher_updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss') 

    # Some other fields

class Student(models.Model): 
    user_ptr = OneToOneField('UserManager.User', primary_key=True,related_name='teacher_user')

    student_create_date = DateTimeField(auto_now_add=True,)
    student_update_date = DateTimeField(auto_now=True,)
    student_created_by = ForeignKey('UserManager.User', related_name='created_%(class)ss')  
    student_updated_by = ForeignKey('UserManager.User', related_name='updated_%(class)ss') 
    # Some other fields

Then makemigrations:

Migrations for 'UserManager':
  UserManager/migrations/0023_auto_20200425_1335.py
    - Add field student_create_date to student
    - Add field student_created_by to student
    - Add field student_update_date to student
    - Add field student_updated_by to student
    - Add field teacher_create_date to teacher
    - Add field teacher_created_by to teacher
    - Add field teacher_update_date to teacher
    - Add field teacher_updated_by to teacher

and finally migrate:

  Applying UserManager.0023_auto_20200425_1335... OK

And done!

What is wrong with Django? XD

0

There are 0 best solutions below