繁体   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