Django: Changing User Model in Mid-Project
Jan 03, 2019 · 3 Min Read · 0 Like · 6 CommentsEvery now and then I see some questions pop up in Stack Overflow with title:
ValueError: Related model ‘app.User’ cannot be resolved
This is a very common issue and pops up when the user tries to run the migration. So, lets talk more about what is this problem and how can we solve it.
The problem
This error occurs when you have been using Django’s default User model, and in mid project, you need some changes in auth.User model and decided to use CustomUser.
Why It occurs
As per django documentation:
Changing AUTH_USER_MODEL after you’ve created database tables is significantly more difficult since it affects foreign keys and many-to-many relationship.
As auth.User is core part of Django, and when you change the tables, it can’t work properly. This problem is hard to identify even for myself, because of the error it throws due to migration.
Solution: easy way
The easiest(and cleanest) way is to delete all your migration files from all apps, drop the database. Then create a new database and connect your project to that. Then run python manage.py makemigrations
and python manage.py migrate
to make changes in DB. Means to make a clean start for the project, data wise.
Solution: hard Way
Dropping the Database is not always possible for us. So there is an another approach to resolve this issue(based on ticket #25313):
Create a custom user model identical to auth.User, call it
User
(so many-to-many tables keep the same name) and setdb_table='auth_user'
(so it uses the same table). Like this:from django.contrib.auth.models import AbstractUser class User(AbstractUser): class Meta: db_table='auth_user'
Throw away all your migrations from all the apps(except for
__init__.py
file inside the migrations folder).Now update value of
AUTH_USER_MODEL
in your settings.py withmyapp.User
(Custom User Model) likeAUTH_USER_MODEL = 'myapp.User'
.Recreate a fresh set of migrations using
python manage.py makemigrations
.Make a backup of your database.
Delete all entries from
django_migrations
table.Fake-apply the new set of migrations using
python manage.py migrate --fake
.Optional: Set
db_table="your_custom_table"
or remove it altogether.Make other changes to the custom model, generate migrations, apply them.
Solution: alternative way
You can take a different approach rather than overriding you auth.User model. You can define a new model(lets say Profile), and put your relevant fields there. Then, make a OneToOne
relation with auth.User like this:
class Profile(models.Model):
user = models.OneToOneField(User)
some_field = models.CharField(max_length=255, null=True, blank=True, default=None)
You can use post_save signals to create a profile automatically every time a User is created.
from django.dispatch import receiver
from django.core.signals import post_save
from django.contrib.auth.models import User
@receiver(post_save, sender=User)
def create_user_profile(sender, instance=None, created=None, **kwargs):
if created:
Profile.objects.create(user=instance)
You can use this easily in python:
user = User.objects.first()
user.profile.some_field # Thus you get value of some field from Profile
# OR
profile = Profile.objects.first()
user = profile.user # Thus you get auth.User
Or in template:
{{ user.profile.some_field }}
FYI: this process was mentioned in the django documentation as well.
For future projects
For future projects, you should use your CustomUser model from the beginning. It will reduce a lot of hassle when it comes to customizing User.
In conclusion
To Be Honest, this an old problem and there is no good way to resolve it(at least not in Django 2.1). Hopefully in future releases, it will be fixed.
Last updated: Jul 13, 2024
I won't spam you. Unsubscribe at any time.