Django1.8.5 Mezzanine4.1.0 IntegrityError


環境

$ pip freeze
Django==1.8.5
Mezzanine==4.1.0
django-contrib-comments==1.6.2
django-cors-headers==1.1.0
djangocms-installer==0.8.7
mysql-connector-python==2.0.4
mysqlclient==1.3.6
oauthlib==1.0.3

エラー。

IntegrityError at /ja/admin/blog/blogpost/add/

(1452, 'Cannot add or update a child row: a foreign key constraint fails (`my_db`.`blog_blogpost`, CONSTRAINT `blog_blogpost_site_id_3174b190300edb81_fk_django_site_id` FOREIGN KEY (`site_id`) REFERENCES `django_site` (`id`))')

SQLでの再現。

mysql> INSERT INTO `blog_blogpost` (`comments_count`, `keywords_string`, `rating_count`, `rating_sum`, `rating_average`, `site_id`, `title`, `slug`, `_meta_title`, `description`, `gen_description`, `created`, `updated`, `status`, `publish_date`, `expiry_date`, `short_url`, `in_sitemap`, `content`, `user_id`, `allow_comments`, `featured_image`) VALUES (0, '', 0, 0, 0, 1, 'title', 'title', '', '', 1, '2016-03-15 21:40:49', '2016-03-15 21:40:49', 1, '2016-03-15 21:40:49', NULL, NULL, 0, '<p></p><p>conte</p><p></p>', 1, 1, NULL);

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`mydb`.`blog_blogpost`, CONSTRAINT `blog_blogpost_site_id_3174b190300edb81_fk_django_site_id` FOREIGN KEY (`site_id`) REFERENCES `django_site` (`id`))

mysql> desc blog_blogpost;
+-----------------+---------------+------+-----+---------+----------------+
| Field           | Type          | Null | Key | Default | Extra          |
+-----------------+---------------+------+-----+---------+----------------+
| id              | int(11)       | NO   | PRI | NULL    | auto_increment |
| comments_count  | int(11)       | NO   |     | NULL    |                |
| keywords_string | varchar(500)  | NO   |     | NULL    |                |
| rating_count    | int(11)       | NO   |     | NULL    |                |
| rating_sum      | int(11)       | NO   |     | NULL    |                |
| rating_average  | double        | NO   |     | NULL    |                |
| title           | varchar(500)  | NO   |     | NULL    |                |
| slug            | varchar(2000) | YES  |     | NULL    |                |
| _meta_title     | varchar(500)  | YES  |     | NULL    |                |
| description     | longtext      | NO   |     | NULL    |                |
| gen_description | tinyint(1)    | NO   |     | NULL    |                |
| created         | datetime      | YES  |     | NULL    |                |
| updated         | datetime      | YES  |     | NULL    |                |
| status          | int(11)       | NO   |     | NULL    |                |
| publish_date    | datetime      | YES  | MUL | NULL    |                |
| expiry_date     | datetime      | YES  |     | NULL    |                |
| short_url       | varchar(200)  | YES  |     | NULL    |                |
| in_sitemap      | tinyint(1)    | NO   |     | NULL    |                |
| content         | longtext      | NO   |     | NULL    |                |
| allow_comments  | tinyint(1)    | NO   |     | NULL    |                |
| featured_image  | varchar(255)  | YES  |     | NULL    |                |
| site_id         | int(11)       | NO   | MUL | NULL    |                |
| user_id         | int(11)       | NO   | MUL | NULL    |                |
+-----------------+---------------+------+-----+---------+----------------+
23 rows in set (0.01 sec)

外部キーのsite_id周りかな。
このポストの実行前にMezzanineの設定からサイトの編集をした。example.comを削除して適当なサイトを追加。この時に削除されたサイトのIDが参照エラーになっていると予想。

参照先のテーブル。

mysql> desc django_site;
+--------+--------------+------+-----+---------+----------------+
| Field  | Type         | Null | Key | Default | Extra          |
+--------+--------------+------+-----+---------+----------------+
| id     | int(11)      | NO   | PRI | NULL    | auto_increment |
| domain | varchar(100) | NO   |     | NULL    |                |
| name   | varchar(50)  | NO   |     | NULL    |                |
+--------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

案の定、Mezzanine上のサイトから変更されたレコードが見える。
id: 3になっているのは初期値のexample.comを削除して適当なサイトを追加してエラーになったのでそれを消して、またexample.comを追加したため。

mysql> select * from django_site \G
*************************** 1. row ***************************
    id: 3
domain: example.com
  name: example.com
1 row in set (0.00 sec)

IDをエラー前に変更するとエラーが出なくなった。Mezzanineのサイトを安易に変更したことに起因するエラーだった。けっこう重要な項目だったみたい。

mysql> update django_site set id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> select * from django_site \G
*************************** 1. row ***************************
    id: 1
domain: example.com
  name: example.com
1 row in set (0.00 sec)