用Django自帶MySQL ORM操作外鍵前的正確修改方式

在給網站數據庫優化的過程中,需要給幾張表增加外鍵限制,方便管理員界面的聯表操作。

調研發現,網上提供的幾種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還需要進一步的修改。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章