我正在尝试在 Django 中的两个模型之间添加外键关系,但出现此错误。
Notification
型号:
class Notification(models.Model):
...
lab_extension = models.ForeignKey(Labs, on_delete=models.CASCADE, null=True, to_field='lab_id')
...
Lab
型号
class Lab(models.Model):
...
lab_id = models.AutoField(primary_key=True)
...
将此外键字段分配给
Notification
模型后,我在执行python manage.py migrate
时收到此错误:
django.db.utils.OperationalError: (3780, "Referencing column 'lab_extension_id' and referenced column 'lab_id' in foreign key constraint [constraint name] are incompatible.")
如果我从
AutoField
模型中删除 Lab
并使用默认的 id 字段,此错误可能不会持续存在。但我正处于项目的某个阶段,我无法做到这一点。我还意识到外键字段通常不可为空,但对于这个项目,Notification
模型可能会也可能不会指向Lab
模型。
做
SHOW CREATE TABLE notification
给了我这个:
notification_notification, CREATE TABLE `notification_notification` (
`id` int NOT NULL AUTO_INCREMENT,
`read` tinyint(1) NOT NULL,
`message` longtext NOT NULL,
`user_id` int NOT NULL,
`category` varchar(2) NOT NULL,
`created` datetime(6) NOT NULL,
`question_id` int DEFAULT NULL,
`submission_id` int DEFAULT NULL,
`update_request_id` int DEFAULT NULL,
`lab_extension_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `notification_notific_user_id_e9d6f5f4_fk_user_mana` (`user_id`),
KEY `notification_notification_question_id_af1ad55d_fk_qa_question_id` (`question_id`),
KEY `notification_notific_submission_id_78f78d05_fk_community` (`submission_id`),
KEY `notification_notific_update_request_id_39cf03ba_fk_community` (`update_request_id`),
CONSTRAINT `notification_notific_submission_id_78f78d05_fk_community` FOREIGN KEY (`submission_id`) REFERENCES `community_communitysubmission` (`id`),
CONSTRAINT `notification_notific_update_request_id_39cf03ba_fk_community` FOREIGN KEY (`update_request_id`) REFERENCES `community_submissionupdaterequest` (`id`),
CONSTRAINT `notification_notific_user_id_e9d6f5f4_fk_user_mana` FOREIGN KEY (`user_id`) REFERENCES `user_manager_user` (`id`),
CONSTRAINT `notification_notification_question_id_af1ad55d_fk_qa_question_id` FOREIGN KEY (`question_id`) REFERENCES `qa_question` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3241 DEFAULT CHARSET=latin1
做
SHOW CREATE TABLE lab
给了我这个:
lab, CREATE TABLE `lab` (
`lab_id` int unsigned NOT NULL AUTO_INCREMENT,
`user_id` int unsigned NOT NULL,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`project_dir` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '/opt/PacketAccess/',
`lab_model` int unsigned NOT NULL DEFAULT '0',
`project_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`pn_account` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`deployed` int NOT NULL,
`progress` int NOT NULL,
`request_time` int NOT NULL,
`deploy_time` int NOT NULL,
`destroy_time` int NOT NULL,
`user_ip` varchar(260) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`status` int NOT NULL DEFAULT '1',
`labRegion` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT 'EWR1',
`pn_progress` int NOT NULL,
`pn_project_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT 'n/a',
`pn_host_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT 'unknown',
`pn_device_id` varchar(255) COLLATE utf8_bin NOT NULL,
`pn_device_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`pn_sdn_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`pn_nfmp_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`pn_flow_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`pn_nfmt_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`pn_nrcx_ip` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '0.0.0.0',
`pn_nrcs_ip` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '0.0.0.0',
`pn_elastic_ip` varchar(40) COLLATE utf8_bin NOT NULL,
`lab_version` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '17.3',
`lab_tags` varchar(255) COLLATE utf8_bin NOT NULL,
`user_email` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT 'n/a',
`voucher_id` int NOT NULL,
`admin_password` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`oss_password` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`deployed_email` text CHARACTER SET utf8 COLLATE utf8_bin,
`lab_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`customer_lab_ip` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '0.0.0.0',
`deployment_test` tinyint(1) DEFAULT NULL,
`ssl_enabled` tinyint(1) DEFAULT NULL,
`associated_lab_id` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`lab_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11995 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin
注意:为了保护隐私,我更改了本文中的一些表和字段的名称,因此如果某些名称不一致,请忽略。
对我来说,问题出在整理。
我检查了第一个表的排序规则为:
select column_name, COLLATION_NAME, CHARACTER_SET_NAME from information_schema.`COLUMNS` where table_name = "<table_name>";
然后将默认数据库排序规则修复为:
alter database <database_name> CHARACTER SET <utf8mb4> COLLATE <utf8mb4_desired_value>;
这是问题,
在实验台上
`lab_id` int unsigned NOT NULL AUTO_INCREMENT
在通知中
lab_extension_id` int DEFAULT NULL
这些字段不同,不能设置为外键,请将一种类型移至另一种类型。
我也有类似的问题。 您的问题源于具有不同的默认字符集和排序规则。
当您运行 SHOW CREATE TABLE 通知时, 结果的最后一行显示
) ENGINE=InnoDB AUTO_INCREMENT=3241 DEFAULT CHARSET=latin1
当您运行 SHOW CREATE TABLE 实验室时, 结果的最后一行显示
) ENGINE=InnoDB AUTO_INCREMENT=11995 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin
您的两列只是使用自己的表的字符集和排序规则,并且它们恰好不同。
据我所知,django 并没有真正处理字符集和排序规则(也许有人可以纠正我); django 将只使用数据库正在使用的任何默认值;问题和解决方案与数据库相关。
您需要做的就是使所有内容都匹配(数据类型、字符集、排序规则),然后 Django 应该能够使您的外键约束。
老版本的MySQL似乎默认字符集和排序规则是latin1,现在默认是utf8。如果您从旧数据库转储并恢复到新数据库,您可能会遇到此错误(看来您和我都是此问题的受害者)。
就我而言,我已经有了数据库的转储,而这个新数据库只是实验性的,因此我删除了实验数据库,使用正确的字符集和排序规则重新创建了它,并使用我拥有的转储恢复了它,然后运行我的 Django 迁移。
删除数据库 yourdbname;
创建数据库 yourdbname 字符集 latin1 整理 latin1_swedish_ci;
如果您所在的数据库不应该被删除,您可以尝试在数据库级别、表级别或列级别上更新字符集和排序规则。 看来您已经搞乱了字符集和排序规则,因为您的实验室表有一些不同的列(如 SHOW CREATE TABLE 实验室所示)