environment DJANGO VERSION 1.9 Python 2.7.6
I added a field (scores) to a model class in models.py like this
from django.db import models
from django
Those migration issues bother me too when i have to update my app with new columns, so i've made a small bash with some python to search for troublesome columns, remove them, migrate, re-add them and migrate again.
Here is the resolve.sh
that calls python and migrations (has to be placed in the same folder as your manage.py
file, like the .py
files) :
python manage.py shell < check.py
read -p "Does it seem ok ? (y for ok/n for remigrate)" migrateok
if [ $migrateok = "n" ]
then
python manage.py shell < rm_badcolumns.py
python manage.py makemigrations
sleep 1
python manage.py migrate
python manage.py shell < resume_badcolumns.py
python manage.py makemigrations
sleep 1
python manage.py migrate
echo It should work now..
else
echo No changes were made..
fi
check.py
checks if there are issues with some models in the database :
from .models import *
import os, sys
from shutil import move
from django.db import connection
tables = connection.introspection.table_names()
seen_models = connection.introspection.installed_models(tables)
errorColumn = []
is_fine = "EVERYTHING LOOKS FINE!"
#looping through models to detect issues
for model in seen_models:
try:
print(model.objects.all())
except:
is_fine = "WARNING SOME MODELS ARE CORRUPTED"
print(is_fine)
This check will tell the user if some models are not sync with your database.
If the user chooses to "re-migrate", it calls rm_badcolumns.py
:
from .models import *
import os, sys
from shutil import move
from django.db import connection
tables = connection.introspection.table_names()
seen_models = connection.introspection.installed_models(tables)
errorColumn = []
for model in seen_models:
try:
model.objects.all()
except:
errorColumn.append(str(sys.exc_info()[1])[30::]+' =')
#this weird expression just get the column that causes trouble
#you may have to adapt indexes depending on error output in exc_info
os.chdir('.//')
#removing columns from models.py based on the error pattern
def replace(pattern, subst):
with open('models_sub.py','w') as fout:
with open('models.py','r') as models:
for line in models:
fout.write(line.replace(pattern, subst))
os.remove('models.py')
move('models_sub.py','models.py')
#applying this func to each error, and commenting out columns with an error mark to catch them back later
for errorStr in errorColumn:
replace(errorStr, '#error_mark '+errorStr)
print 'Removing troublesome column for re-entering..'
Then resolve.sh
will start another migration.
We uncomment the troublesome columns with resume_badcolumns.py
to get them migrated again :
from .models import *
import os, sys
from shutil import move
from django.db import connection
os.chdir('.//')
#same search and replace func but returning True if sthg was replaced, and False otherwise
def replace(pattern, subst):
a = False
with open('models_sub.py','w') as fout:
with open('models.py','r') as models:
for line in models:
fout.write(line.replace(pattern, subst))
if pattern in line:
a = True
os.remove('models.py')
move('models_sub.py','models.py')
return a
a = True
#while error_marks are replaced, we go on looping
while a:
a = replace('#error_mark ', '')
print 'Re-adding troublesome columns..'
We make a final migration and everything should be fine.
This is a kind of heavy and dirty artillery for a small problem but i wanted it to be automatized. A few points may need some rework, such as the way i identify which column is not synced, and i'd appreciate comments about this.