簡體   English   中英

為什么 Django 沒有在 MySQL 上創建外鍵約束?

[英]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,其中 ID 為“1” km_series 表

那么如何在手動分配時添加任何 ID,而不是將整個實例化的 object 作為 foreign_key 值傳遞? km_chapter 表

為什么 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM