[英]Why Django is not creating Foreign Key constraint on MySQL?
我對 Python 和 Django 並不陌生,但這是我第一次從頭開始創建一個全新的大項目,也是我第一次真正為整個數據庫創建模型,我有點困惑這里。
Django 是否真的沒有在數據庫上創建 ForeignKey 約束以檢查 ID 是否存在? 它只是一個邏輯 python 的東西,只有在服務器運行時才有效? 還是 MySQL 上發生的問題?
為了清楚我在說什么,我注意到的第一件事是因為作為 PHP 方面的 Laravel 開發人員,我習慣於始終檢查 PhpStorm/PyCharm 通過連接到數據庫和在 ZA502C9ZBE64d962912EA72 上生成的數據庫圖表,我們可以看到指向各個外鍵表關系的箭頭,但是在 Django 創建的數據庫上,JetBrains IDE 生成的數據庫圖上沒有單個箭頭。 所以我去測試了。
例如,我有以下模型:
class Series(models.Model):
class Meta:
app_label = 'core'
db_table = 'km_series'
verbose_name_plural = 'series' # added this to avoid plural being "seriess"
name = models.CharField(max_length=200)
description = models.TextField(default=None, blank=True, null=True)
cover_img = models.CharField(max_length=100, default=None, blank=True, null=True)
on_going = models.BooleanField(default=False)
date_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "{} - ID #{}".format(self.name, self.id)
class Chapter(models.Model):
class Meta:
app_label = 'core'
db_table = 'km_chapter'
series = models.ForeignKey(Series, on_delete=models.CASCADE)
number = models.IntegerField(validators=[MinValueValidator(0)])
name = models.CharField(max_length=150, default=None, blank=True, null=True)
date_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "#{} - {}".format(self.number, self.name)
我已經在其他領域使用models.ForeignKey
創建了超過 15 個模型。 我剛剛嘗試使用python manage.py shell
在 MySQL 上創建一個新行。
$ python manage.py shell
>>> from core.models import *
>>> Series
<class 'core.models.base_models.Series'>
>>> one = Series.objects.create(name='Test')
>>> one
<Series: Test - ID #1>
>>> one.id
1
>>> chapter = Chapter.objects.create(number=1)
MySQLdb.OperationalError: (1048, "Column 'series_id' cannot be null")
>>> chapter = Chapter.objects.create(number=1, series_id=2)
>>> chapter
<Chapter: #1 - None>
>>> chapter_1 = Chapter.objects.create(number=1, series=one)
>>> chapter_1
<Chapter: #1 - None>
>>> chapter = Chapter.objects.create(number=1, series_id=25)
那么如何在手動分配時添加任何 ID,而不是將整個實例化的 object 作為 foreign_key 值傳遞?
為什么 Django 允許我將 ID 設置為數據庫上不存在的 ID? 這不應該導致錯誤嗎? 我在我的模型上遺漏了什么嗎? 為什么這種事情沒有約束和驗證?
在深入研究了為什么 MySQL 會出現 FK 約束問題,並在使用python manage.py dbshell
命令檢查表創建之后,正如我建議在評論中所做的那樣,使用SHOW CREATE TABLE core_chapter;
,我發現了問題。
出於某種我不知道為什么的原因,我的數據庫是使用 MyISAM 創建的,這是一個不支持 FK 約束的 MySQL 存儲引擎。 我不得不將默認值更改為 InnoDB,因為它適用於表之間關系的這種類型的驗證。
在包含 MySQL 的 confs 的my.cnf
文件中,我通過添加default-storage-engine
屬性將 InnoDB 強制為默認值
[mysqld]
default-storage-engine = InnoDB
在 Django 設置上,我還添加了 DATABASE “OPTIONS”,如數據庫的 Django 文檔中所述,因此我的 DATABASES 值更改為:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'database_name',
'USER': 'database_user',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {'init_command': 'SET default_storage_engine=INNODB'},
}
}
更改所有這些后,刪除所有數據庫表,然后再次調用python manage.py migrate
,按預期創建約束,現在我的 PyCharm 生成的數據庫圖表顯示所有箭頭完美地顯示了關系。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.