pythondjangodjango-admindjango-migrationsdjango-modeladmin

django: don't register ModelAdmin (exclude module-level code) when running makemigrations / migrate


I have made multiple changes to an existing django model (added new foreign key relation, etc). Before creating and applying these changes with manage.py makemigrations / migrate, I adapted the corresponding admin module's ModelAdmin for that app to reflect these unapplied changes.

Running makemigrations now fails with "ProgrammingError: {new_field} does not exist". I figure this happens because when makemigrations runs system checks, the ModelAdmins in admin.py are registered (executing queries on non-existant models that I try to create with the migrations).

Question: Is there any straight-forward way to exclude the ModelAdmins from being registered when running manage.py makemigrations / migrate without disabling system checks in total (see Django migration - disabel system checks)?

I can solve the problem by deleting my admin.py modules when running makemigrations / migrate and recreating them afterwards. There is really no need to check the admin modules when migrating, but I guess this will happen when registering ModelAdmins on the module-level of admin.py (as in the examples in the django admin documentation). I do not use a custom AdminSite.

On more general terms: is there any straight-forward way to exclude specific top-level module code from being executed when running a specific manage.py command like makemigrations or migrate?


Solution

  • I figured out a reasonable way to do this.

    Since I was so desperately searching for a django-native way to check for the current command, I did not think of simply evaluating the command line arguments like normal to do this.

    When calling makemigrations or migrate from the command line, I can get the name of the command with sys.argv[1]. This should work in any top-level code that is automatically executed when django runs system checks.

    The registering of ModelAdmins is caused through django.contrib.admin.autodiscover(), which is automatically called when using the default AdminConfig (i.e. when django.contrib.admin is included in the INSTALLED_APPS setting). We can use django.contrib.admin.apps.SimpleAdminConfig in the setting instead, so that autodiscover() will not be called automatically (see django admin docs).

    I changed the corresponding part in my settings.py from

    INSTALLED_APPS = [
        ...
       "django.contrib.admin",
        ...
    ]
    

    to

    MIGRATION_COMMAND = sys.argv[1] in ('makemigrations', 'migrate')
    INSTALLED_APPS = [
        ...
       "django.contrib.admin.apps.SimpleAdminConfig" if MIGRATION_COMMAND else "django.contrib.admin",
        ...
    ]
    

    This way, all the admin.py modules of my apps will be ignored when running makemigrations / migrate. I can now also use the custom MIGRATION_COMMAND setting anywhere else if I need to.