Tengo un proyecto Python/Django. Debido a algunos retrocesos y otras cosas mixtas, terminamos en una especie de escenario extraño.
El escenario actual es así:
El código está actualizado
La carpeta de migraciones está detrás de la base de datos por una o dos migraciones. (Estas migraciones se aplicaron desde otro lugar y ese "otro lugar" ya no existe)
Agrego y modifico algunos modelos.
Lo que necesito:
Para poder ejecutar las migraciones y "ignorar" las tablas existentes y aplicar las nuevas. O cualquier forma alternativa de lograr esto.
¿Es eso posible?
Cuando aplica una migración, Django inserta una fila en una tabla llamada django_migrations . Esa es la única forma en que Django sabe qué migraciones ya se han aplicado y cuáles no. Entonces, las filas en esa tabla deben coincidir con los archivos en su directorio de migrations . Si perdió los archivos de migración después de que se aplicaron, o si hizo algo más para desincronizar las cosas, tendrá problemas... porque los números de migración en su base de datos se refieren a archivos de migración diferentes a los de su proyecto.
Entonces, antes de hacer cualquier otra cosa, debe volver a sincronizar las cosas eliminando las filas de la tabla django_migrations para cualquier archivo de migración que haya perdido de alguna manera y no pueda recuperar. La tabla debe contener filas solo para aquellas migraciones que tenga y que realmente se aplicaron correctamente a la base de datos .
Ahora necesita lidiar con cualquier cambio en su base de datos que Django Migrations no conozca... y para eso hay algunas opciones:
Si las cosas resultaron de tal manera que los cambios de la base de datos que ya se aplicaron a la base de datos están en archivos de migración diferentes a los que no lo estaban, entonces puede solucionarlo ejecutando sus migraciones una a la vez usando la opción --fake en cualquier cambios que en realidad ya están en la base de datos. La opción falsa simplemente escribe la fila en la tabla django_migrations marcando la migración como completada. Solo haga esto si la base de datos ya tiene todos los cambios contenidos en ese archivo de migración.
Y aquellos archivos de migración que contienen solo cambios que no se han aplicado a la base de datos, se ejecutan sin la opción --fake y Django los aplicará. p.ej:
# database already has it manage.py migrate myapp 0003 --fake # need it manage.py migrate myapp 0004 # database already has it manage.py migrate myapp 0005 --fakeSi tiene archivos de migración donde se han aplicado algunos pero no todos los cambios, entonces tiene un problema mayor. En ese caso, hay varias formas de hacerlo (elija SOLO UNA):
Edite los archivos de migración para colocar los cambios que ya se han aplicado (no importa si Django lo hizo o si lo hizo manualmente) en migraciones de menor número, y coloque todo lo que necesita hacer en archivos de mayor número. Ahora puede --fake los números más bajos y ejecutar los números más altos como de costumbre. Digamos que tiene 10 cambios que realizó en sus modelos, y 5 de esos cambios ya están en la base de datos, pero Django no los conoce... así que cuando ejecuta makemigrations , se crea una nueva migración con los 10 cambios. Esto normalmente fallará porque el servidor de la base de datos no puede, por ejemplo, agregar una columna que ya existe. Mueva estos cambios ya aplicados de su nuevo archivo de migración al archivo de migración anterior (ya aplicado). Django asumirá entonces que estos se aplicaron con la migración anterior y no intentará aplicarlos nuevamente. Luego puede migrate normalmente y se aplicarán los nuevos cambios.
Si no desea tocar su archivo de migración anterior, una forma más limpia de hacerlo es ejecutar primero makemigrations --empty appname para crear un archivo de migración vacío. Luego ejecute makemigrations , que creará otra migración con todos los cambios que Django cree que deben realizarse. Mueva las migraciones ya realizadas de ese archivo a la migración vacía que creó ... luego, --fake esa. Esto hará que la comprensión de Django de cómo se ve la base de datos estará sincronizada con la realidad y luego podrá migrate normalmente, aplicando los cambios en el último archivo de migración.
Deshazte de cualquier migración nueva que acabas de crear usando makemigrations. Ahora, comente o vuelva a colocar cualquier cosa en sus modelos que no se haya aplicado a la base de datos, dejando que su código coincida con lo que realmente está en la base de datos. Ahora puede realizar makemigrations y migrate appname --fake y volverá a sincronizar las cosas. Luego, descomente su nuevo código y ejecute 'makemigrations', luego migrate normalmente y se aplicarán los cambios. Si los cambios son pequeños (por ejemplo, agregar algunos campos), a veces esto es más fácil. Si los cambios son grandes, no lo es....
Puede continuar y (cuidadosamente) hacer cambios en la base de datos usted mismo, actualizando la base de datos. Ahora solo ejecuta migrate --fake y si no te equivocaste, entonces todo estará bien. Nuevamente, esto es fácil para cambios pequeños, no tan fácil para cambios complicados.
Puede ejecutar manage.py sqlmigrate > mychanges.sql . Esto genera mychanges.sql que contiene todo el SQL que Django hubiera ejecutado contra la base de datos. Ahora edite ese archivo para eliminar cualquier cambio que ya se haya aplicado, dejando lo que debe hacerse. Ejecute ese SQL usando pgadmin o psql (espero que esté usando postgresql). Ahora que se han realizado todos los cambios... por lo que puede ejecutar manage.py migrate --fake , esto hará que Django se sincronice con la realidad y debería estar listo. Si sus conocimientos de SQL son suficientes, esta es probablemente la solución más sencilla.
Debo añadir dos advertencias:
Primero, si aplica una migración posterior, por ejemplo, 0003_foobar.py, y luego las cosas no funcionan y decide volver atrás y aplicar 0002_bazbuz.py, entonces Django SACARÁ COSAS DE SU BASE DE DATOS. Por ejemplo, una columna que podría haber agregado en 0003 se eliminará junto con sus datos. Como dice que no puede perder datos, tenga mucho cuidado al volver.
En segundo lugar, no se apresure a ejecutar --fake . Asegúrese de que toda la migración que está a punto de falsificar ya esté en la base de datos. De lo contrario, se vuelve muy confuso. Si se arrepiente de falsificar migraciones y no desea retroceder, puede borrar el conocimiento de django de la migración falsificada eliminando esa fila de la tabla django_migrations . Está bien hacer esto... si entiendes lo que estás haciendo. Si sabe que la migración realmente no se aplicó, está bien.
Esta publicación de blog realmente lo clava. https://simpleisbetterthancomplex.com/tutorial/2016/07/26/how-to-reset-migrations.html
Permítanme resumir los pasos en su escenario 2 (tiene una base de datos de producción y desea cambiar el esquema o los modelos en una o más aplicaciones). En mi caso, tenía dos aplicaciones, cola y hoja de ruta, que tenían modificaciones de modelo que necesitaba aplicar a un sistema de producción. La clave era que ya tenía la base de datos, así que aquí es donde entra en juego --fake-initial.
Aquí están los pasos que seguí. Como siempre, haga una copia de seguridad de todo antes de comenzar. Trabajo en una máquina virtual, así que tomé una instantánea antes de seguir adelante.
1) Eliminar el historial de migración de cada aplicación.
python manage.py migrate --fake queue zero python manage.py migrate --fake routingslip zero2) Elimine todos los archivos de migración en todo el proyecto en el que residen las aplicaciones .
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete find . -path "*/migrations/*.pyc" -delete3) Hacer migraciones
python manage.py makemigrations4) Aplicar las migraciones, fingiendo inicial porque la base de datos ya existe y solo queremos los cambios:
python manage.py migrate --fake-initialFuncionó muy bien para mí.