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