python - migraciones - makemigrations django
Compruebe si hay migraciones Django pendientes (7)
En Django, ¿hay una manera fácil de verificar si todas las migraciones de base de datos se han ejecutado? He encontrado manage.py migrate --list
, que me da la información que quiero, pero el formato no es muy legible por la máquina.
Para contexto: tengo un script que no debería comenzar a ejecutarse hasta que la base de datos haya sido migrada. Por diversas razones, sería complicado enviar una señal del proceso que está ejecutando las migraciones. Así que me gustaría que mi script revise periódicamente la base de datos para ver si se han ejecutado todas las migraciones.
1.10 notas de la versión:
La nueva opción
makemigrations --check
hace que el comando salga con un estado distinto de cero cuando se detectan cambios en el modelo sin migraciones.
Aquí está mi solución de Python para obtener información sobre los estados de migración:
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
El resultado de esta función se ve así:
[(True, ''contenttypes.0001_initial''),
(True, ''auth.0001_initial''),
(False, ''admin.0001_initial''),
(False, ''admin.0002_logentry_remove_auto_add'')]
Tal vez ayude a algunos de ustedes ...
Lo django_migrations
buscando en la base de datos en la tabla django_migrations
witch store todas las migraciones aplicadas
Tratar,
python manage.py migrate --list | grep "/[ /]/|^[a-z]" | grep "[ ]" -B 1
devoluciones,
<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
Actualización :
Si ha actualizado la versión de Django> = 1.11
, use el siguiente comando,
python manage.py showmigrations | grep ''/[ /]/|^[a-z]'' | grep ''[ ]'' -B 1
Usando el código @Ernest, he escrito manage_custom.py
para las migraciones pendientes. Puede obtener la lista de migraciones pendientes y también migrar esas migraciones pendientes (solo), por lo tanto, le ahorrará tiempo.
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()
Uso:
# 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 : Por favor, configure el entorno según la estructura de su proyecto.
./manage.py showmigrations
#check que migraciones ya realizadas se han aplicado o no
(o: ./manage.py showmigrations someApp
#para aplicación específica solo)
./manage.py makemigrations --dry-run
#check para realizar migraciones
(o: ./manage.py makemigrations someApp --dry-run
# para una aplicación específica solo)
./manage.py makemigrations
#hacer las migraciones
(o: ./manage.py makemigrations someApp
#para aplicación específica solo)
./manage.py showmigrations
#check que migraciones ya realizadas se han aplicado o no
(o: ./manage.py showmigrations someApp
#para aplicación específica solo)
./manage.py sqlmigrate someApp 0001
# ver cambios de SQL para aplicaciones y migraciones específicas
./manage.py migrate
#apply migrations
(o: ./manage.py migrate someApp
aplicaciones # para aplicaciones específicas solo)
./manage.py showmigrations
#check que migraciones ya realizadas se han aplicado o no
(o: ./manage.py showmigrations someApp
#para aplicación específica solo)
./manage.py makemigrations --dry-run
#check para realizar migraciones
(o: ./manage.py makemigrations someApp --dry-run
# para una aplicación específica solo)
PD:
./manage.py migrate someApp zero
#unapply todas las migraciones para una aplicación específica
Cáscara
La única solución simple que he encontrado hasta ahora está funcionando.
./manage.py showmigrations | grep ''/[ /]''
que generará una cadena vacía en caso de que se hayan aplicado todas las migraciones.
Sin embargo, está estrechamente vinculado al formato de salida.
Pitón
Verifiqué el código fuente del comando migrate
y parece que esto debería hacer el truco:
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 False if executor.migration_plan(targets) else True
# Usage example.
if is_database_synchronized(DEFAULT_DB_ALIAS):
# All migrations have been applied.
pass
else:
# Unapplied migrations found.
pass