Django使用South迁移时错误:字段列表中未知列

2 投票
2 回答
3788 浏览
提问于 2025-04-16 22:23

我在使用schemamigration给我的数据库添加一个新列时遇到了一些问题。这个新列叫做'is_flagged',它是我应用'upload'中的Video模型的一个布尔值字段。当我运行迁移时,出现了以下错误:

....:~/..../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'")

有没有人知道为什么我不能进行迁移?即使我特意使用--add-field命令,情况也是一样。

我觉得问题可能出在另一个应用'score'中的一个ForeignKey(外键),它引用了Video对象。如果真是这样,应该怎么迁移那些被其他应用的外键引用的模型呢?

更新

我找到了一种变通方法,就是把'score'中的那个有问题的外键行注释掉,正常运行迁移,然后再把那行取消注释,而不去迁移'score'本身。这种方法可以解决问题,但不太优雅,如果应用之间有很多外键的话,会很麻烦。正如我之前问的,有没有什么办法可以自动避免这种情况,而不需要去编辑那个有外键的模型?

2 个回答

5

我不确定这是不是你想要的答案,但我遇到过类似的问题,这个方法帮我解决了。如果你修改了模型(也就是你定义的数据结构),但没有正确更新数据库,那么你就会遇到同样的错误。运行syncdb命令不会改变已经创建的表,所以在你加载任何额外数据之前,你必须先重置数据库。

python manage.py reset (app_name)

然后再同步一次你的数据库,这样就应该没问题了。

python manage.py syncdb 
5

问题并不是你有一个指向你正在迁移的模型的 ForeignKey。这种情况很常见,South 处理得也很好。真正的问题在于你在这个外键声明中做了一些非常非常糟糕的事情。

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

这个默认声明会在导入时执行查询,并取第一个值。在导入时执行的事情是大忌(尤其是查询)。所以发生的事情是,当 South 导入模型以便检查它们并生成模式迁移时,Video.objects.all() 被执行了。但是因为 Video 模型被修改了(你刚添加了一个新字段),而这个字段在数据库中还不存在,所以 Django 的 ORM 报错了。

如果你真的想把这个作为默认值,那就用一个可调用的对象来代替。

def get_default_video():
     return Video.objects.all()[0]

...
video = models.ForeignKey(Video, default=get_default_video)

注意: 虽然我一时想不出有什么好理由把第一个 Video 记录设为视频外键的默认值。你到底想要做什么呢?

撰写回答