syncdbの時のForeignKeyがつく条件ってなに?

Djangosyncdb 叩いた時に、同じように models.ForeignKey を使ってるのに結果が違う。簡単なアプリを作ってテストしてみた。テスト環境はこんな感じ。

models.py はこんな感じ。

from django.db import models

class Oya(models.Model):
    body = models.TextField()

class Ko(models.Model):
    parent = models.ForeignKey(Oya)
    body = models.TextField()

これで sql を叩くとこう出てくる。

BEGIN;
CREATE TABLE `hige_ko` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `parent_id` integer NOT NULL,
    `body` longtext NOT NULL
);
CREATE TABLE `hige_oya` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `body` longtext NOT NULL
);
ALTER TABLE `hige_ko` ADD CONSTRAINT parent_id_refs_id_4d095607 FOREIGN KEY (`parent_id`) REFERENCES `hige_oya` (`id`);
COMMIT;

hige_ko (Ko) が先に作られて hige_oya (Oya) が作られる。で、ちゃんと ALTER TABLE で外部キーを付け足してる事が分かる。これが期待してる通りの形。ココで models.py を書き換えてみる。

class Oya(models.Model):
    body = models.TextField()

# KoからKodomoへ変更。
class Kodomo(models.Model):
    parent = models.ForeignKey(Oya)
    body = models.TextField()

もう一回 sql を叩くとこう出る。

BEGIN;
CREATE TABLE `hige_oya` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `body` longtext NOT NULL
);
CREATE TABLE `hige_kodomo` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `parent_id` integer NOT NULL REFERENCES `hige_oya` (`id`),
    `body` longtext NOT NULL
);
COMMIT;

今度は hige_oya (Oya) が先に作られて次に hige_kodomo (Kodomo) が作られる。 ALTER TABLE 文が消えて、代わりにカラム定義部分に REFERENCES の一文が付いた。

この2つをそれぞれ syncdb 叩いて実際にテーブルを作ってみる。以下、それぞれの SHOW CREATE TABLE の実行結果。

mysql> SHOW CREATE TABLE `hige_ko`\G
*************************** 1. row ***************************
       Table: hige_ko
Create Table: CREATE TABLE `hige_ko` (
  `id` int(11) NOT NULL auto_increment,
  `parent_id` int(11) NOT NULL,
  `body` longtext NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `hige_ko_parent_id` (`parent_id`),
  CONSTRAINT `parent_id_refs_id_4d095607` FOREIGN KEY (`parent_id`) REFERENCES `hige_oya` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

次に後者だとこうなった。

mysql> SHOW CREATE TABLE `hige_kodomo`\G
*************************** 1. row ***************************
       Table: hige_kodomo
Create Table: CREATE TABLE `hige_kodomo` (
  `id` int(11) NOT NULL auto_increment,
  `parent_id` int(11) NOT NULL,
  `body` longtext NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `hige_kodomo_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

やっぱり後者には外部キー制約が付けられてない。ほとんど同じコードで実行してるのにこの違いはなんだ?これだと最初のクラス名を決める段階で生成されるSQLを意識せざるを得ない。それに、「生成されるかも知れない。されないかも知れない。」ってのが痛い。

かなり曖昧に見えるこの動作の判断基準ってどこだ?

Posted at: 
2007/07/02 00:16:09
2 Comments
0 TrackBacks
Tags: 
Django
Python
Trackback: 
http://humming.via-kitchen.com/2007/07/02/when-foreign-key-is-added/trackback/

TrackBacks

まだ登録されていません。

Comments

ymasuda

ちょっとコードを追いかけてみましたが、モデルクラス(+α)の名前から決まるhash値で、OyaとKo/Kodomoクラスのどちらが先に並ぶかによって、外部キー制約が付くか付かないかが決まってしまいます。(事実上制御できないですね。)現状、外部キー制約は「おまけ」と考えざるをえないようです。

Created at: 
2007/07/02 12:34:36

nobu

返事が遅くなってしまい申し訳ありません。
わざわざ調べてくださってありがとうございます。

やはりランダムに決められてしまうんですね。どちらか一方のみだったらまだ良いと思いますが、どちらになるか分からない。ってのは正直つらいですね。

改善されるまでは重要な所はデータベースを作っておいてinspectdbしてから整形するようにした方がよいのでしょうか?

Created at: 
2007/07/03 00:47:56

Add Comment

Add Comment