Search code examples
pythondjangodjango-south

Django error when using South migration: Unknown column in 'field list'


I'm running into a problem when using schemamigration to add a column to my database. The field in question, 'is_flagged', is a boolean belonging to the Video model in my app 'upload'. When running the migration, I get the following:

....:~/..../webapp$ python manage.py schemamigration upload --auto
Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    execute_manager(settings)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 219, in execute
    self.validate()
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 249, in validate
    num_errors = get_validation_errors(s, app)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/validation.py", line 36, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 146, in get_app_errors
    self._populate()
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 61, in _populate
    self.load_app(app_name, True)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/loading.py", line 78, in load_app
    models = import_module('.models', app_name)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/home/..../score/models.py", line 43, in <module>
    class Score(models.Model):          # matches with one specific user and one specific video
  File "/home/..../score/models.py", line 45, in Score
    video = models.ForeignKey(Video, default=Video.objects.all()[0])    # default value shouldn't end up in real objects
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 190, in __getitem__
    return list(qs)[0]
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 84, in __len__
    self._result_cache.extend(self._iter)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 273, in iterator
    for row in compiler.results_iter():
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 680, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/util.py", line 34, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 86, in execute
    return self.cursor.execute(query, args)
  File "/usr/lib/pymodules/python2.7/MySQLdb/cursors.py", line 166, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib/pymodules/python2.7/MySQLdb/connections.py", line 35, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.OperationalError: (1054, "Unknown column 'upload_video.is_flagged' in 'field list'")

Any idea why it won't let me migrate? The same happens when I specifically use --add-field too.

I think the problem might lie in a ForeignKey in another app ('score', as you can see in the traceback) which references the Video object. If that's the case, what is the proper way to migrate models which are referenced by ForeignKeys in other apps?

Update

I found a workaround, which is to comment out the offending ForeignKey line in 'score', run the migration as usual, and finally uncomment the line, without ever migrating 'score' itself. This works, but it's not elegant, and would be cumbersome if there were many ForeignKeys between apps. As I asked before, is there any way to avoid this automatically, without having to edit the model with the ForeignKey to the model with the new field?


Solution

  • The problem is not that you have a ForeignKey pointed to the model you are migrating. That is a very common situation, and South definitely deals fine with that. The real problem is that you are doing something very very bad in that FK declaration.

    video = models.ForeignKey(Video, default=Video.objects.all()[0])
    

    This default declaration is going to execute the query at import time and take it's first value. Things that execute at import time are a big no-no (especially a query). So what happens is, when South imports the models so that it can introspect them and generate the schemamigration, Video.objects.all() is executed. But because Video model was changed (you've just added a new field), which doesn't exist yet in DB, Django's ORM raises an error.

    If you really want to set that as your default value, then use a callable instead

    def get_default_video():
         return Video.objects.all()[0]
    
    ...
    video = models.ForeignKey(Video, default=get_default_video)
    

    Note: Although I cannot think of a good reason in the first place, for setting the first Video record as default value for the video FK. What are you trying to do?