Django模型南0.7.6迁移问题:表中的任何更改与另一个字段的默认值百分比

Posted

技术标签:

【中文标题】Django模型南0.7.6迁移问题:表中的任何更改与另一个字段的默认值百分比【英文标题】:Django model south 0.7.6 migration problems: Any change in a table with another field with percentage in default value 【发布时间】:2012-09-15 21:42:58 【问题描述】:

在我的数据库模型中添加一个包含日期字段格式的字段后,我遇到了问题。

像这样:

date_format = models.CharField(max_length=32, default='%B %Y')

但是,在同一迁移中,一些布尔值具有默认值。深入研究问题,并多次重建测试数据库....

问题在于表中的任何迁移都带有带有百分比符号的默认值。所以不是这个字段本身的迁移,而是任何迁移到同一个表(见我的第二个答案)

像这样添加一个字段:

show_category_name  = models.BooleanField(default=True)

with auto schememigration 给出了一个带有这一行的迁移文件:

 # -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models


class Migration(SchemaMigration):

    def forwards(self, orm):
        # Adding field 'NewsItemCategory.show_category_name'
        db.add_column('iamweb_newsitemcategory', 'show_category_name',
                      self.gf('django.db.models.fields.BooleanField')(default=True),
                      keep_default=False)

给出这个问题:

    bin/django migrate iamwebdjango.db.backends DEBUG (0.006) SELECT "south_migrationhistory"."id", "south_migrationhistory"."app_name", "south_migrationhistory"."migration", "south_migrationhistory"."applied" FROM "south_migrationhistory" WHERE "south_migrationhistory"."applied" IS NOT NULL ORDER BY "south_migrationhistory"."applied" ASC; args=()
Running migrations for iamweb:
 - Migrating forwards to 0020_auto__add_field_newsitemcategory_show_category_name__add_field_weblink.
 > iamweb:0020_auto__add_field_newsitemcategory_show_category_name__add_field_weblink
django.db.backends DEBUG (0.277) CREATE TABLE ROLLBACK_TEST (X INT); args=()
django.db.backends DEBUG (0.008) INSERT INTO ROLLBACK_TEST (X) VALUES (8); args=()
django.db.backends DEBUG (0.001) SELECT COUNT(X) FROM ROLLBACK_TEST; args=()
django.db.backends DEBUG (0.273) DROP TABLE ROLLBACK_TEST; args=()
django.db.backends DEBUG (0.177) CREATE TABLE STDDEV_TEST (X INT); args=()
django.db.backends DEBUG (0.000) SELECT STDDEV(*) FROM STDDEV_TEST; args=()
django.db.backends DEBUG (0.160) DROP TABLE STDDEV_TEST; args=()
django.db.backends DEBUG (0.151) CREATE TABLE DDL_TRANSACTION_TEST (X INT); args=()
django.db.backends DEBUG (0.000) CREATE TABLE DDL_TRANSACTION_TEST (X INT); args=()
django.db.backends DEBUG (0.155) DROP TABLE DDL_TRANSACTION_TEST; args=()
django.db.backends DEBUG (0.000) PRAGMA table_info("iamweb_newsitemcategory"); args=()
django.db.backends DEBUG (0.000) PRAGMA index_list("iamweb_newsitemcategory"); args=()
django.db.backends DEBUG (0.000) PRAGMA index_info("sqlite_autoindex_iamweb_newsitemcategory_1"); args=()
django.db.backends DEBUG (0.000) PRAGMA index_list("iamweb_newsitemcategory"); args=()
django.db.backends DEBUG (0.000) PRAGMA index_info("sqlite_autoindex_iamweb_newsitemcategory_1"); args=()
django.db.backends DEBUG (0.000) PRAGMA table_info("iamweb_newsitemcategory"); args=()
south DEBUG execute "CREATE TABLE "_south_new_iamweb_newsitemcategory" ("date_format" varchar(32) DEFAULT '%B %Y', "show_category_name" bool NOT NULL DEFAULT 1, "id" integer PRIMARY KEY, "menu_index" integer NOT NULL UNIQUE, "name" varchar(64) NOT NULL)" with params "[]"
 ! Error found during real run of migration! Aborting.

 ! Since you have a database that does not support running
 ! schema-altering statements in transactions, we have had 
 ! to leave it in an interim state between migrations.

! You *might* be able to recover with:
 ! The South developers regret this has happened, and would
 ! like to gently persuade you to consider a slightly
 ! easier-to-deal-with DBMS (one that supports DDL transactions)
 ! NOTE: The error which caused the migration to fail is further up.
Error in migration: iamweb:0020_auto__add_field_newsitemcategory_show_category_name__add_field_weblink
Traceback (most recent call last):
  File "bin/django", line 33, in <module>
    djangorecipe.manage.main('palmrif.developmentsettings')
  File "/media/storage/django/sites/palmrif/eggs/djangorecipe-0.20-py2.7.egg/djangorecipe/manage.py", line 16, in main
    management.execute_manager(mod)
  File "/media/storage/django/sites/palmrif/parts/django/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/media/storage/django/sites/palmrif/parts/django/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/media/storage/django/sites/palmrif/parts/django/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/media/storage/django/sites/palmrif/parts/django/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/management/commands/migrate.py", line 108, in handle
    ignore_ghosts = ignore_ghosts,
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/__init__.py", line 213, in migrate_app
    success = migrator.migrate_many(target, workplan, database)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 235, in migrate_many
    result = migrator.__class__.migrate_many(migrator, target, migrations, database)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 310, in migrate_many
    result = self.migrate(migration, database)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 133, in migrate
    result = self.run(migration)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 107, in run
    return self.run_migration(migration)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 81, in run_migration
    migration_function()
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 57, in <lambda>
    return (lambda: direction(orm))
  File "/media/storage/django/sites/palmrif/local_checkouts_dev/iamweb/iamweb/migrations/0020_auto__add_field_newsitemcategory_show_category_name__add_field_weblink.py", line 14, in forwards
    keep_default=False)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/sqlite3.py", line 31, in add_column
    field.column: self._column_sql_for_create(table_name, name, field, False),
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/generic.py", line 44, in _cache_clear
    return func(self, table, *args, **opts)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/sqlite3.py", line 103, in _remake_table
    ", ".join(["%s %s" % (self.quote_name(cname), ctype) for cname, ctype in definitions.items()]),
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/generic.py", line 273, in execute
    cursor.execute(sql, params)
  File "/media/storage/django/sites/palmrif/parts/django/django/db/backends/util.py", line 38, in execute
    sql = self.db.ops.last_executed_query(self.cursor, sql, params)
  File "/media/storage/django/sites/palmrif/parts/django/django/db/backends/__init__.py", line 505, in last_executed_query
    return smart_unicode(sql) % u_params
TypeError: not enough arguments for format string

我正在使用 South 0.7.6。奇怪的是,这个版本应该已经修复了这个bug,见:Release notes 0.7.6. bug fix default boolean value in sqlite

使用sqlite3、python 2.7.2、django 1.3.1(顺便说一下,在生产中使用mysql,但是sqlite中的测试数据库很方便)

注意问题出在迁移文件的第 14 行,也就是这一行:

        db.add_column('iamweb_newsitemcategory', 'show_category_name',
                  self.gf('django.db.models.fields.BooleanField')(default=True),
                  keep_default=False)

没有足够的论据......对于初学者来说很好:这条线不是我创建的,South 做了:)

堆栈跟踪有点混乱,因为调试行的最后一行(堆栈跟踪之前是:

south DEBUG execute "CREATE TABLE "_south_new_iamweb_newsitemcategory" ("date_format" varchar(32) DEFAULT '%B %Y', "show_category_name" bool NOT NULL DEFAULT 1, "id" integer PRIMARY KEY, "menu_index" integer NOT NULL UNIQUE, "name" varchar(64) NOT NULL)" with params "[]"

所以这可能与 South 仍然想要解析字符串有关,因为这个执行命令中的 '%B %Y'....

在解决这个问题 4 天后(当然不是全职),我开始怀疑南方之路....但是,没有找到更好的选择。

【问题讨论】:

我可以看到回溯和失败的行吗? 【参考方案1】:

我刚刚在南方邮件列表上回复了。总结一下:布尔值是无辜的,百分比是有罪的,Sqlite 是一个玩具,因此它的南后端有点疯狂,显然有一个错误。即将推出的新版 South 应该避免在数据库中存储默认值,这可能会解决您的问题(至少对于测试而言)。

票 #317 无关紧要。就目前而言,Ticket #1192 应该由当前在 pull request 中的代码修复(或者你可以从我的 fork 中选择它,https://bitbucket.org/shaib/south)。

【讨论】:

谢伯杰,非常感谢!我删除了带有百分比的默认值,但我期待这个新的南后端版本。 (我坚持官方发布)。目前 SQL lite 可能只是一个玩具,但对于开发来说,这是 django 的唯一离线替代品。但是感谢您的努力,我很高兴您修复了这个错误。新的一年有个美好的开始!【参考方案2】:

啊,问题可能不在 '%B %Y' 默认值中。 (因此我对问题和标题的编辑) sqlite 中的默认布尔值似乎存在一些问题。请参阅我在问题中的编辑。 并且布尔值不支持 True 和 false 的默认值。 见South ticket

迁移文件中建议的解决方案是:

 if db.backend_name == "sqlite3":
   default = 1
else:
   default = True
db.add_column('node_entry', 'visible', self.gf('django.db.models.fields.BooleanField')(default=default), keep_default=False)

但这不起作用,进一步阅读,它应该在我正在使用的南方版本中得到解决......

【讨论】:

【参考方案3】:

很确定问题出在默认值“%B %Y”上。 那个迁移顺利,但在此之后新的迁移出错了。 我发现是因为我有 3 个布尔值字段,我希望默认为真。 其中 2 个在一个表格中,这个百分比在另一个字段中。 我标记了这 2 个迁移,只剩下一个没问题。

问题在于用百分号重新创建表格

查看曲目:

   File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/sqlite3.py", line 31, in add_column
    field.column: self._column_sql_for_create(table_name, name, field, False),
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/generic.py", line 44, in _cache_clear
    return func(self, table, *args, **opts)
  File "/media/storage/django/sites/palmrif/eggs/South-0.7.6-py2.7.egg/south/db/sqlite3.py", line 103, in _remake_table
    ", ".join(["%s %s" % (self.quote_name(cname), ctype) for cname, ctype in definitions.items()]),

所以我想我会尝试重新打开南票并让他们访问这个网站。 并更改这张票的标题。

我在工单上添加了评论:http://south.aeracode.org/ticket/317

【讨论】:

以上是关于Django模型南0.7.6迁移问题:表中的任何更改与另一个字段的默认值百分比的主要内容,如果未能解决你的问题,请参考以下文章

Django:迁移错误中的加载数据

如何在南迁移期间调用 django 模型类的静态方法

Django 南迁移 - 添加 FULLTEXT 索引

测试使用南迁移的 Django 应用程序

南迁移和 django 迁移有啥区别?

陷入 django 南迁移 - TransactionManagement 错误