100👍
Shell
The only simple solution I’ve found so far is running
./manage.py showmigrations | grep '\[ \]'
which will output an empty string in case all migrations have been applied.
However, it is closely tied to the output format.
Python
I checked the source code of migrate
command and it seems like this should do the trick:
from django.db.migrations.executor import MigrationExecutor
from django.db import connections, DEFAULT_DB_ALIAS
def is_database_synchronized(database):
connection = connections[database]
connection.prepare_database()
executor = MigrationExecutor(connection)
targets = executor.loader.graph.leaf_nodes()
return not executor.migration_plan(targets)
# Usage example.
if is_database_synchronized(DEFAULT_DB_ALIAS):
# All migrations have been applied.
pass
else:
# Unapplied migrations found.
pass
63👍
1.10 release notes:
The new
makemigrations --check
option makes the command exit with a non-zero status when model changes without migrations are detected.
If you don’t want to create the migrations, combine it with --dry-run
:
python manage.py makemigrations --check --dry-run
Note that this doesn’t check whether the migrations were applied, it only checks whether the migration files were created.
UPDATE for Django 4.2: --check
will not create missing migration files and --dry-run
is not required anymore.
UPDATE: the management command migrate
also has a --check
option:
Makes migrate exit with a non-zero status when unapplied migrations are detected.
- [Django]-Django Server Error: port is already in use
- [Django]-Ignoring Django Migrations in pyproject.toml file for Black formatter
- [Django]-Using Cloudfront with Django S3Boto
22👍
Try,
python manage.py migrate --list | grep "\[ \]\|^[a-z]" | grep "[ ]" -B 1
returns,
<app_1>
[ ] 0001_initial
[ ] 0002_auto_01201244
[ ] 0003_auto_12334333
<app_2>
[ ] 0031_auto_12344544
[ ] 0032_auto_45456767
[ ] 0033_auto_23346566
<app_3>
[ ] 0008_auto_3446677
Update:
If you have updated Django version >= 1.11
, use below command,
python manage.py showmigrations | grep '\[ \]\|^[a-z]' | grep '[ ]' -B 1
- [Django]-Navigation in django
- [Django]-Storing an Integer Array in a Django Database
- [Django]-Automatic creation date for Django model form objects
18👍
3.1 release notes
The new migrate –check option makes the command exit with a non-zero status when unapplied migrations are detected.
https://docs.djangoproject.com/en/3.1/ref/django-admin/#cmdoption-migrate-check
so finally we can
python manage.py migrate --check
- [Django]-Paginate relationship in Django REST Framework?
- [Django]-Pytest.mark.parametrize with django.test.SimpleTestCase
- [Django]-Unique fields that allow nulls in Django
13👍
./manage.py showmigrations
#check which already-made migrations have been applied or not
(or: ./manage.py showmigrations someApp
#for specific app alone)
./manage.py makemigrations --dry-run
#check for migrations to be made
(or: ./manage.py makemigrations someApp --dry-run
#for specific app alone)
./manage.py makemigrations
#make the migrations
(or: ./manage.py makemigrations someApp
#for specific app alone)
./manage.py showmigrations
#check which already-made migrations have been applied or not
(or: ./manage.py showmigrations someApp
#for specific app alone)
./manage.py sqlmigrate someApp 0001
#view SQL changes for specific app & migration
./manage.py migrate
#apply migrations
(or: ./manage.py migrate someApp
#for specific app alone)
./manage.py showmigrations
#check which already-made migrations have been applied or not
(or: ./manage.py showmigrations someApp
#for specific app alone)
./manage.py makemigrations --dry-run
#check for migrations to be made
(or: ./manage.py makemigrations someApp --dry-run
#for specific app alone)
PS:
./manage.py migrate someApp zero
#unapply all migrations for specific app
The documentation for these commands can be found here on the Django project’s website.
- [Django]-How to define two fields "unique" as couple
- [Django]-IntegrityError duplicate key value violates unique constraint – django/postgres
- [Django]-Create if doesn't exist
6👍
Here is my Python soloution to get some information about the migration-states:
from io import StringIO # for Python 2 use from StringIO import StringIO
from django.core.management import call_command
def get_migration_state():
result = []
out = StringIO()
call_command('showmigrations', format="plan", stdout=out)
out.seek(0)
for line in out.readlines():
status, name = line.rsplit(' ', 1)
result.append((status.strip() == '[X]', name.strip()))
return result
The result of this function looks like that:
[(True, 'contenttypes.0001_initial'),
(True, 'auth.0001_initial'),
(False, 'admin.0001_initial'),
(False, 'admin.0002_logentry_remove_auto_add')]
Maybe it helps some of you guys..
- [Django]-What is the max size of 'max_length' in Django?
- [Django]-Simple Log to File example for django 1.3+
- [Django]-How can I check the size of a collection within a Django template?
4👍
Using @Ernest code, I’ve written a manage_custom.py
for pending migrations. You can get the list of pending migrations also migrate those pending migrations (only), hence saving your time.
manage_custom.py
__author__ = "Parag Tyagi"
# set environment
import os
import sys
import django
sys.path.append('../')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
django.setup()
from django.core.management import execute_from_command_line
from django.db import DEFAULT_DB_ALIAS, connections
from django.db.migrations.executor import MigrationExecutor
class Migration(object):
"""
A custom manage.py file for managing pending migrations (only)
"""
def __init__(self, migrate_per_migration_id=False):
"""
:param migrate_per_migration_id: Setting this to `True` will migrate each pending migration of any
particular app individually. `False` will migrate the whole app at a time.
You can add more arguments (viz. showmigrations, migrate) by defining the argument with prefix as 'ARGV_'
and create its functionality accordingly.
"""
self.ARG_PREFIX = 'ARGV_'
self.MIGRATE_PER_MIGRATION_ID = migrate_per_migration_id
self.ARGV_showmigrations = False
self.ARGV_migrate = False
@staticmethod
def get_pending_migrations(database):
"""
:param database: Database alias
:return: List of pending migrations
"""
connection = connections[database]
connection.prepare_database()
executor = MigrationExecutor(connection)
targets = executor.loader.graph.leaf_nodes()
return executor.migration_plan(targets)
def check_arguments(self, args):
"""
Method for checking arguments passed while running the command
:param args: Dictionary of arguments passed while running the script file
:return: Set the argument variable ('ARGV_<argument>') to True if found else terminate the script
"""
required_args = filter(None, [var.split(self.ARG_PREFIX)[1] if var.startswith(self.ARG_PREFIX)
else None for var in self.__dict__.keys()])
if any(k in args for k in required_args):
for arg in required_args:
if arg in args:
setattr(self, '{}{}'.format(self.ARG_PREFIX, arg), True)
break
else:
print ("Please pass argument: {}"
"\ne.g. python manage_custom.py {}".format(required_args, required_args[0]))
sys.exit()
def do_migration(self):
"""
Migrates all the pending migrations (if any)
"""
pending_migrations = self.get_pending_migrations(DEFAULT_DB_ALIAS)
if pending_migrations:
done_app = []
for mig in pending_migrations:
app, migration_id = str(mig[0]).split('.')
commands = ['manage.py', 'migrate'] + ([app, migration_id] if self.MIGRATE_PER_MIGRATION_ID else [app])
if self.ARGV_migrate and (app not in done_app or self.MIGRATE_PER_MIGRATION_ID):
execute_from_command_line(commands)
done_app.append(app)
elif self.ARGV_showmigrations:
print (str(mig[0]))
else:
print ("No pending migrations")
if __name__ == '__main__':
args = sys.argv
migration = Migration()
migration.check_arguments(args)
migration.do_migration()
Usage:
# below command will show all pending migrations
python manage_custom.py showmigrations
# below command will migrate all pending migrations
python manage_custom.py migrate
PS: Please setup environment as per your project structure.
- [Django]-Can't install via pip because of egg_info error
- [Django]-Django TextField and CharField is stripping spaces and blank lines
- [Django]-How to implement followers/following in Django
1👍
Tested for Django 3.2:
python manage.py makemigrations --check --dry-run
expected output would be:
'No changes detected'
if there are no pending changes in the Models requiring a migration to be created
python manage.py migrate --plan
expected output would be:
'Planned operations: No planned migration operations.'
You can use it in python script with call_command and develop a way to check for the expected output. If there are any pending makemigrations
of migrate
calls, the output will be different from the expected and you can understand that something is missing.
I’m running this at a CI/CD pipeline with very good results.
- [Django]-Django Rest Framework model serializer with out unique together validation
- [Django]-Django Server Error: port is already in use
- [Django]-Do django db_index migrations run concurrently?
0👍
I checked it by looking up the table django_migrations
, which stores all applied migrations.
- [Django]-When to use get, get_queryset, get_context_data in Django?
- [Django]-Getting Values of QuerySet in Django
- [Django]-Django Sitemaps and "normal" views
0👍
Make it simple:
$ until python manage.py migrate --check ; do echo "Migration not completed" ; done
- [Django]-Specifying limit and offset in Django QuerySet wont work
- [Django]-WARNING: Running pip as the 'root' user
- [Django]-How do you catch this exception?
0👍
Here is another python solution, using a custom Django command :
from io import StringIO
from time import sleep
from django.core.management import BaseCommand, call_command
class Command(BaseCommand):
def handle(self, *, **__):
pending_migrations = True
while pending_migrations:
output = StringIO()
call_command("migrate", plan=True, stdout=output)
command_result = output.getvalue()
pending_migrations = not "No planned migration operations" in command_result
if pending_migrations:
sleep(5)
It will retry every 5 seconds (I need it in my case but it’s no mandatory to do so).
To use it, simply run python manage.py wait_for_migrations
, assuming the code above is in a file wait_for_migrations.py
, in a Django app, under <app>/management/commands
(whole path: <app>/management/commands/wait_for_migrations.py
.
To learn more about custom commands : LINK
I use this custom command in the startup sequence of my celery docker containers to be sure the database has been migrated by the Django backend container, before starting celery itself.
- [Django]-Class Based Views VS Function Based Views
- [Django]-How to use "get_or_create()" in Django?
- [Django]-Django order_by query set, ascending and descending