“no such column” after adding a field to the model

前端 未结 7 1558
抹茶落季
抹茶落季 2020-12-28 08:53

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         


        
7条回答
  •  时光说笑
    2020-12-28 09:22

    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.

提交回复
热议问题