[英]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.