在給網站數據庫優化的過程中,需要給幾張表增加外鍵限制,方便管理員界面的聯表操作。
調研發現,網上提供的幾種models的配置都不能讓我的插入程序成功運行,在經過嘗試之後總結出了一個終極解決方案。
我的環境:Django==2.1.7,Python==3.6.1
我建表一般先過Navicat這種可視化軟件來生成mysql數據庫,所以我們直接在建表之後使用下面語句直接生成。
python manage.py inspectdb > app/models.py
// 'app' 是我項目名稱
生成的models.py部分代碼:
class InfoUpload(models.Model):
# 子表
upload_id = models.AutoField(primary_key=True)
contact_email = models.ForeignKey('InfoUser', model.DO_NOTHING, db_column='contact_email')
class Meta:
managed = False
db_table = 'info_upload'
class InfoUser(models.Model):
# 主表
user_id = models.AutoField(primary_key=True)
contact_email = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'info_user'
unique_together = (('user_id', 'contact_email'),)
可以看到在子表(有外鍵的表)中,外鍵contact_email生成了三個設置字段,'InfoUser'表示參照的表, model.DO_NOTHING是插入時的動作(感覺這個字段是個bug,我們一會要用級聯來替代它), db_column='contact_email'表中列名。
在主表中,contact_email只有一個最大長度字段。
在插入之後我們遇到了以下的報錯:
// 報錯 1
// 說我沒有設置級聯
django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`corpusdatabase`.`info_upload`, CONSTRAINT `upload_email` FOREIGN KEY
(`contact_email`) REFERENCES `info_user` (`contact_email`) ON DELETE CASCADE ON UPDATE CASCADE)')
// 報錯 2
// 說我沒有設置主鍵唯一
ERRORS:
pageContent.InfoUpload.contact_email: (fields.E311) 'InfoUser.contact_email' must set unique=True because it is referenced by a foreign key.
推測原因是inspectdb指令生成的models並不是完整狀態的,對於我這種懶人並不是很友好,還需要自己再加入一些設置。
不斷試錯之後得到最終版本如下:
class InfoUpload(models.Model):
upload_id = models.AutoField(primary_key=True)
upload_date = models.DateTimeField(blank=True, null=True)
contact_email = models.ForeignKey('InfoUser', on_delete='CASECADE', db_column='contact_email', to_field='contact_email', related_name="upload_name")
# models.DO+_NOTHING 改爲 on_delete='CASECADE', 設置級聯操作
# 加入 to_field='contact_email',指出參考表中哪一列
# 加入 related_name="upload_name", 方便之後的聯表查詢
class Meta:
managed = False
db_table = 'info_upload'
class InfoUser(models.Model):
user_id = models.AutoField(primary_key=True)
contact_email = models.CharField(max_length=255, unique=True)
# 增加字段unique=True,設置這個鍵的值是唯一的
class Meta:
managed = False
db_table = 'info_user'
unique_together = (('user_id', 'contact_email'),)
應該就能解決了。
綜上,這個故事告訴我們,不能太依賴inspectdb這條語句,對於生成的models還需要進一步的修改。