#25313: Document how to migrate from a built-in User model to a custom User 
model
-------------------------------+------------------------------------
     Reporter:  Carl Meyer     |                    Owner:  nobody
         Type:  New feature    |                   Status:  new
    Component:  Documentation  |                  Version:  1.8
     Severity:  Normal         |               Resolution:
     Keywords:                 |             Triage Stage:  Accepted
    Has patch:  0              |      Needs documentation:  0
  Needs tests:  0              |  Patch needs improvement:  0
Easy pickings:  0              |                    UI/UX:  0
-------------------------------+------------------------------------

Comment (by Carsten Fuchs):

 Based on

   - Aymeric's [https://code.djangoproject.com/ticket/25313#comment:2
 approach above],
   - Tobias's blog post https://www.caktusgroup.com/blog/2019/04/26/how-
 switch-custom-django-user-model-mid-project/,
   - Vitor's blog post
 https://simpleisbetterthancomplex.com/tutorial/2016/07/26/how-to-reset-
 migrations.html

 I tried to write a summary. These steps worked well for me, although I'm
 sure there is room for improvement:


 == Assumptions

   - Your project doesn't have a custom user model yet.

   - All existing users must be kept.

   - There are no pending migrations and all existing migrations are
 applied.

   - It is acceptable that all previous migrations are lost and can no
 longer be unapplied, even if you use version control to checkout old
 commits that still have the migration files. This is the relevant downside
 of this approach.


 == Preparations

   - Make sure that ''any third party apps'' that refer to the Django User
 model only use the
     [https://docs.djangoproject.com/en/3.0/topics/auth/customizing
 /#referencing-the-user-model generic referencing methods].

   - Make sure that ''your own reusable apps'' (apps that are intended to
 be used by others) use the generic reference methods.

   - I suggest to ''not'' do the same with your project apps:
     The switch to a custom user model is only done once per project and
 never again.
     It is easier (and in my opinion also clearer) to change `from
 django.contrib.auth.models import User`
     to something else (as detailed below) than replacing it with generic
 references that are not needed in project code.

   - Make sure that you have a backup of your code and database!


 == Update the code

   - You can create the new user model in any existing app or a newly
 created one.
     My preference is to create a new app:
     {{{#!python
         ./manage.py startapp Accounts
     }}}
     I chose the name "Accounts", but any other name works as well.

   - Aymeric: „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).“
     In `Accounts/models.py`:
     {{{#!python
         from django.contrib.auth.models import AbstractUser
         from django.db import models


         class User(AbstractUser):
             class Meta:
                 db_table = 'auth_user'
     }}}

   - In `settings.py`, add the app to `INSTALLED_APPS` and update the
 `AUTH_USER_MODEL` setting:
     {{{#!python
         INSTALLED_APPS = (
             # ...
             'Accounts',
         )

         AUTH_USER_MODEL = 'Accounts.User'
     }}}

   - In your project code, replace all imports of the Django user model:
     {{{#!python
         from django.contrib.auth.models import User
     }}}
     with the new, custom one:
     {{{#!python
         from Accounts.models import User
     }}}

   - Delete all old migrations. (Beforehand, see if
 [https://code.djangoproject.com/ticket/25313#comment:14 comment 14] is
 relevant to you!)
     For example, in the project root:
     {{{#!sh
         find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
         find . -path "*/migrations/*.pyc" -delete
     }}}

   - Create new migrations from scratch:
     {{{#!sh
         ./manage.py makemigrations
     }}}

   - Make any changes to your `admin.py` files as required.
     (I cannot give any solid information here, but this is not crucial for
 the result and so the details can still be reviewed later.)

   - Make sure that your testsuite completes successfully! (A fresh test
 database must be used, it cannot be kept from previous runs.)

   - At this point, the changes to the code are complete. This is a good
 time for a commit.

 Note that we're done – except that the new migration files mismatch the
 contents of the `django_migrations` table.

 (It may even be possible to serve your project at this point: It's easy to
 back off before the database is actually changed. ''Only'' do this if you
 understand that you ''cannot even touch'' the migrations system as long as
 the steps below are not completed!)


 == Update the database

   - Truncate the `django_migrations` table. MySQL 8 example:
     {{{#!sql
         TRUNCATE TABLE django_migrations;
     }}}
     This is possibly different for other databases or verions of MySQL <
 8.

   - Fake-apply the new set of migrations
     {{{#!sh
         ./manage.py migrate --fake
     }}}

   - Check the ContentTypes as described at
 [https://code.djangoproject.com/ticket/25313#comment:12 comment 12]


 == Conclusion

   - The upgrade to the custom user model is now complete.
     You can make changes to this model and generate and apply migrations
 for it as with any other models.

   - As a first step, you may wish to unset `db_table` and generate and
 apply the resulting migrations.

   - In my opinion, the `startproject` management command should anticipate
 the introduction of a custom user model.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/25313#comment:18>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.6761631b1837cd183489900d99fce0e9%40djangoproject.com.

Reply via email to