django - 无法插入数据,Django 主键没有默认值
问题描述
在 Django 3.0 中,我有一组模型,包括一个抽象BaseData
、一个Data
扩展它的模型和一个外键到的基础数据FKData
模型Data
:
# models.py
from django.db import models
class BaseData(models.Model):
class Meta:
abstract = True
class Data(BaseData):
data = models.ForeignKey(
FKData,
on_delete=models.CASCADE,
blank=True,
null=True,
default=None
)
class FKData(models.Model):
text = models.CharField(
help_text='underlying data'
)
当我尝试插入到Data
. 例如,
mysql> INSERT INTO appname_data (data_id) SELECT data_id FROM appname_othertable
ERROR 1364 (HY000): Field 'basedata_ptr_id' doesn't have a default value
basedata_ptr_id
是 Django 生成的主键字段,Data
由于是 的子类BaseData
:
mysql> DESCRIBE appname_data;
+-----------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+-------+
| basedata_ptr_id | int(11) | NO | PRI | NULL | |
| data_id | int(11) | YES | MUL | NULL | |
+-----------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
该错误听起来好像没有设置为AUTO INCREMENT
正常主键的方式?
如果我尝试使用 Django shell 填充Data
表格,我会得到相同的错误,但堆栈跟踪可能会更大:
Traceback (most recent call last):
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 209, in execute
res = self._query(query)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 315, in _query
db.query(q)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/connections.py", line 239, in query
_mysql.connection.query(self, query)
MySQLdb._exceptions.IntegrityError: (1364, "Field 'basedata_ptr_id' doesn't have a default value")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<console>", line 6, in <module>
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/base.py", line 746, in save
force_update=force_update, update_fields=update_fields)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/base.py", line 784, in save_base
force_update, using, update_fields,
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/base.py", line 887, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/base.py", line 926, in _do_insert
using=using, raw=raw,
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/query.py", line 1204, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1391, in execute_sql
cursor.execute(sql, params)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 209, in execute
res = self._query(query)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 315, in _query
db.query(q)
File "/home/username/ProjectName/env/lib/python3.6/site-packages/MySQLdb/connections.py", line 239, in query
_mysql.connection.query(self, query)
django.db.utils.IntegrityError: (1364, "Field 'basedata_ptr_id' doesn't have a default value")
出了什么问题,我该如何解决?
编辑:我决定擦除我的数据库并停止所有开发,同时我花了几周的时间重建它,这一切都是因为我忽略了一行,因为我正在使用“有期限的完美主义者框架”。
然而,这个问题值得更好的回答。根据评论,我怀疑接近答案的最佳方法如下:
考虑两种情况。
方案 A
- 我定义
BaseData
为一个抽象类
class BaseData(models.Model):
class Meta:
abstract = True
- 我跑来
makemigrations
创建一个迁移文件
方案 B
- 我定义
BaseData
为非抽象类
class BaseData(models.Model):
class Meta:
pass
- 我跑来
makemigrations
创建一个迁移文件。 - 我
BaseData
变成了一个抽象类
class BaseData(models.Model):
class Meta:
abstract = True
- 我跑来
makemigrations
创建第二个迁移文件。
原则上,场景 B 的两个迁移的组合应该完全等于场景 A 的迁移。在实践中,有些不同。回答这个问题的第一步是确定两种方案之间的迁移指令有何不同。然后,我们可以制定一个手动编辑迁移文件的流程,在不擦除数据库的情况下解决问题,以供以后遇到同样问题的人使用。
解决方案
推荐阅读
- python - cryptography.hazmat.bindings._openssl import ffi, lib ImportError: DLL load failed:
- sql - 在列前添加一些数字
- tensorflow - 将事件侦听器添加到 Tensorflow 模型找到的标签
- php - 带有查找条件的 Mongodb 随机聚合查询
- react-native - 想在多个选择器中通过循环生成数字反应原生
- java - 基于多个值创建唯一的 hashCode
- reporting-services - SSRS 返回不正确的 WW
- bash - 如何解析变量中存储的输出,存储结果并根据结果触发另一个脚本
- c++ - c++多线程读取文件
- excel - 如何制作星形复选框?