Every now and then I see some questions pop up in stackoverflow 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.
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 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.
How to Resolve It
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.
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 set
db_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__.pyfile inside the migrations folder).
Now update value of
AUTH_USER_MODELin your settings.py with
myapp.User(Custom User Model) like
AUTH_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
Fake-apply the new set of migrations using
python manage.py migrate --fake.
db_table="your_custom_table"or remove it altogether.
Make other changes to the custom model, generate migrations, apply them.
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:
FYI: this process was mentioned in the 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.
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.