将已有的MyISAM数据库转换为InnoDB与Django

8
有没有一种方法可以将一个完全填充的MyISAM数据库转换为InnoDB(以一种方式创建所有外键约束,就像我从头开始运行syncdb命令一样)?
4个回答

5
这可能有所帮助:
from django.core.management.base import BaseCommand
from django.db import connections


class Command(BaseCommand):

    def handle(self, database="default", *args, **options):

        cursor = connections[database].cursor()

        cursor.execute("SHOW TABLE STATUS")

        for row in cursor.fetchall():
            if row[1] != "InnoDB":
                print "Converting %s" % row[0],
                print cursor.execute("ALTER TABLE %s ENGINE=INNODB" % row[0])

将此添加到您的应用程序管理/命令文件夹下。然后,您可以使用manage.py命令将所有表格转换:
python manage.py convert_to_innodb

3

使用Django将MyISAM转换为InnoDB。

假设旧数据库是MyISAM。

使用以下命令将旧数据库的数据导出为json:

$ python manage.py dumpdata contenttypes --indent=4 --natural > contenttype.json
$ python manage.py dumpdata --exclude contenttypes --indent=4 --natural > everything_else.json

删除旧数据库,然后重新创建它。
在您的settings.py中添加InnoDB设置,如下所示:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'STORAGE_ENGINE': 'InnoDB',
        'NAME': 'yourdbname',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
        'OPTIONS': {
            'init_command': 'SET storage_engine=InnoDB',  # better to set this in your database config, otherwise django has to do a query everytime
        }
    }
}

创建表(Django也会添加关系) 确保不要添加管理员用户:

$ python manage.py syncdb --migrate

现在您想要清空所有旧表:

$ python manage.py sqlflush | ./manage.py dbshell

现在,您可以像这样将新数据加载到数据库中:
$ python manage.py loaddata contenttype.json
$ python manage.py loaddata everything_else.json

这就是你需要的。 我使用了Django==1.4。


2
您可以使用"./manage.py sqlflush |./manage.py dbshell"命令来清空所有的数据表。 - frog32
Django文档指出,当您的表已创建时,请删除init_command,因为它会向每个数据库连接添加一个SQL查询。相反,在您的MySQL配置中更改默认表类型。 - Emil Stenström
来到这里复制/粘贴代码的人:你可能尝试过这个并且出现了错误“"ERROR 1064 (42000) at line 1"”。那是因为在运行python manage.py sqlflush时有初始警告。为了规避这个问题:python manage.py sqlflush > flushdump.txt,删除初始警告,保存,然后python manage.py dbshell < flushdump.txt - Mærcos

2

真的吗?我的意思是,MyISAM表在其定义中没有存储外键约束。另一方面,Django有关于表关系的信息,不是吗?也许OP是在询问一种将表转换并同时添加在Django中定义的FK(对应关系)的方法? - ypercubeᵀᴹ
@ypercube - 你说得对,我不知道为什么Chris认为它不适合Django。 - Ohad
1
在Chris的评论中,他哪里说它不适用于Django了?他只是说迁移表与Django无关,这是正确的。按照他的指示操作,如果FK约束还不存在,您可以使用manage.py sqlindexes获取它们。 - Daniel Roseman
当他提到Django时,我感到困惑了。这是MySQL的问题,与Django无关! - Henley

1

我曾经遇到过类似的情况,我没有意识到我的托管提供商使用了如此老旧的MySQL版本,以至于它仍然默认为MyISAM,但我已经设置了基本的Django表。

这是在原始问题发布大约两个月后发布的:将传统的Django MySQL数据库从MyISAM转换为InnoDB

那篇文章和leech / Trey的答案描述了ALTER TABLE ___ ENGINE = INNODB命令,在MySQL中将表格转换,但问题是,即使表格被转换,它们也没有外键约束,如果表格一开始就是INNODB,那么这些约束将会设置好。

我在django-admin.py和manage.py上发现,python manage.py sqlall appname“打印给定应用程序名称的CREATE TABLE和initial-data SQL语句。”

我查看了settings.py中的INSTALLED_APPS,最终运行了类似于python manage.py sqlall admin auth contenttypes sessions sites messages staticfiles的命令(每个django.contrib.appname在INSTALLED_APPS中都需要运行一次)。这将显示初始的CREATE TABLE语句、索引和外键约束:
ALTER TABLE `django_admin_log` ADD CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`);
ALTER TABLE `django_admin_log` ADD CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_permission` ADD CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`);
ALTER TABLE `auth_group_permissions` ADD CONSTRAINT `permission_id_refs_id_a7792de1` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`);
ALTER TABLE `auth_group_permissions` ADD CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`);
ALTER TABLE `auth_user_user_permissions` ADD CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`);
ALTER TABLE `auth_user_groups` ADD CONSTRAINT `group_id_refs_id_f0ee9890` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`);
ALTER TABLE `auth_user_user_permissions` ADD CONSTRAINT `user_id_refs_id_f2045483` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_user_groups` ADD CONSTRAINT `user_id_refs_id_831107f1` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_message` ADD CONSTRAINT `user_id_refs_id_9af0b65a` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);

将所有表转换为ENGINE=INNODB后,我运行了上面的外键约束,并且认为如果我的数据库一开始就默认创建INNODB表,那么我应该拥有与其相同状态的数据库。

顺便提一下,正如Michael van de Waeter在他的答案中提到的,如果您希望Django创建的任何新表默认为INNODB,则应将'OPTIONS': {"init_command": "SET storage_engine=INNODB",}添加到settings.py中的DATABASES字典中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接