Without any prior migrations I have added custom User model in core app to enable custom authentication by following the documentation entry Django 2.0 / Customizing authentication in Django
Then I made migrations:
$ python manage.py makemigrations
Migrations for 'core':
core/migrations/0001_initial.py
- Create model User
At 0001_initial.py
migration class begins with:
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
]
I have looked through the official documentation Django 2.0 / Migrations and this file obviously is an initial migrations since it has initial = True
. But why does it have a whole chain of dependencies starting with 0009_alter_user_last_name_max_length
? Did I made any mistake?
When migrations are ran this is the output:
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, core, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying core.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying sessions.0001_initial... OK
When custom User model is omitted 0001_initial.py
starts with:
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
Additionally, I wasn't able to find a good explanation of what migrations.swappable_dependency(settings.AUTH_USER_MODEL)
exactly does. What does it do and why is it even called "swappable_dependency"? It would be great if someone could demystify this part for me as well or point in right direction to explore on my own. 🙂
Source code of custom User model.
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError('Email not defined.')
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(
email,
password=password,
)
user.is_staff = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
objects = UserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
This is normal and expected behaviour - you still need the migrations from django.contrib.auth
to be applied to your database.
If you look at those migrations they include various other models that are needed by the auth app - things like Permission
and Group
. The User
model has fields that reference these other models, so you need migrations to have set those up first.
Because User
is a swappable dependency, Django will ignore the User
migrations in the auth
app an use yours instead. But the migrations for all the other auth
models will be applied from auth.migrations
.
It is because of this dependency on the auth
migrations that is very difficult to change a custom user model after you've already set up your project:
Due to limitations of Django’s dynamic dependency feature for swappable models, the model referenced by
AUTH_USER_MODEL
must be created in the first migration of its app (usually called0001_initial
); otherwise, you’ll have dependency issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With