Django:如何查找哪个CHECK约束失败



我使用的是django 3。sqlite数据库。我遇到一种情况,其中一个模型中的实例无法保存。我得到一个完整性错误和"CHECK约束失败",后面跟着我的模型名称("post"在我的"压力"下;应用:press_post)。我已经查过了,我想这意味着我的一个字段的值是不可能的?如果有人能更准确、更精确地解释它的意思,那就很有帮助了。大多数情况下,我想知道如何找出哪个检查约束失败了,以便修复它(模型中的哪个字段或哪个数据块导致了问题)。模型中的其他实例保存没有任何问题,而其他一些实例存在与此实例相同的问题。

我可以访问shell_plus中的实例并查看数据。看起来还行……但显然我遗漏了一些东西。

错误输出:

---------------------------------------------------------------------------
IntegrityError                            Traceback (most recent call last)
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in _execute(self, sql, params, *ignored_wrapper_args)
83             else:
---> 84                 return self.cursor.execute(sql, params)
85 
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py in execute(self, query, params)
422         query = self.convert_query(query)
--> 423         return Database.Cursor.execute(self, query, params)
424 
IntegrityError: CHECK constraint failed: press_post
The above exception was the direct cause of the following exception:
IntegrityError                            Traceback (most recent call last)
<ipython-input-8-0c61e89703f4> in <module>
----> 1 post.save()
~/pastrami/pastrami/press/models.py in save(self, *args, **kwargs)
438         #     postreport_check(self)
439 
--> 440         super(Post, self).save(*args, **kwargs)
441 
442     # tags
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/base.py in save(self, force_insert, force_update, using, update_fields)
724                 update_fields = frozenset(loaded_fields)
725 
--> 726         self.save_base(using=using, force_insert=force_insert,
727                        force_update=force_update, update_fields=update_fields)
728     save.alters_data = True
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/base.py in save_base(self, raw, force_insert, force_update, using, update_fields)
761             if not raw:
762                 parent_inserted = self._save_parents(cls, using, update_fields)
--> 763             updated = self._save_table(
764                 raw, cls, force_insert or parent_inserted,
765                 force_update, using, update_fields,
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/base.py in _save_table(self, raw, cls, force_insert, force_update, using, update_fields)
843                       for f in non_pks]
844             forced_update = update_fields or force_update
--> 845             updated = self._do_update(base_qs, using, pk_val, values, update_fields,
846                                       forced_update)
847             if force_update and not updated:
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/base.py in _do_update(self, base_qs, using, pk_val, values, update_fields, forced_update)
897                 (filtered._update(values) > 0 or filtered.exists())
898             )
--> 899         return filtered._update(values) > 0
900 
901     def _do_insert(self, manager, using, fields, returning_fields, raw):
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/query.py in _update(self, values)
800         query.annotations = {}
801         self._result_cache = None
--> 802         return query.get_compiler(self.db).execute_sql(CURSOR)
803     _update.alters_data = True
804     _update.queryset_only = False
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/sql/compiler.py in execute_sql(self, result_type)
1557         related queries are not available.
1558         """
-> 1559         cursor = super().execute_sql(result_type)
1560         try:
1561             rows = cursor.rowcount if cursor else 0
~/pastrami/rye/lib/python3.8/site-packages/django/db/models/sql/compiler.py in execute_sql(self, result_type, chunked_fetch, chunk_size)
1173             cursor = self.connection.cursor()
1174         try:
-> 1175             cursor.execute(sql, params)
1176         except Exception:
1177             # Might fail for server-side cursors (e.g. connection closed)
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in execute(self, sql, params)
96     def execute(self, sql, params=None):
97         with self.debug_sql(sql, params, use_last_executed_query=True):
---> 98             return super().execute(sql, params)
99 
100     def executemany(self, sql, param_list):
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in execute(self, sql, params)
64 
65     def execute(self, sql, params=None):
---> 66         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
67 
68     def executemany(self, sql, param_list):
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in _execute_with_wrappers(self, sql, params, many, executor)
73         for wrapper in reversed(self.db.execute_wrappers):
74             executor = functools.partial(wrapper, executor)
---> 75         return executor(sql, params, many, context)
76 
77     def _execute(self, sql, params, *ignored_wrapper_args):
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in _execute(self, sql, params, *ignored_wrapper_args)
82                 return self.cursor.execute(sql)
83             else:
---> 84                 return self.cursor.execute(sql, params)
85 
86     def _executemany(self, sql, param_list, *ignored_wrapper_args):
~/pastrami/rye/lib/python3.8/site-packages/django/db/utils.py in __exit__(self, exc_type, exc_value, traceback)
88                 if dj_exc_type not in (DataError, IntegrityError):
89                     self.wrapper.errors_occurred = True
---> 90                 raise dj_exc_value.with_traceback(traceback) from exc_value
91 
92     def __call__(self, func):
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/utils.py in _execute(self, sql, params, *ignored_wrapper_args)
82                 return self.cursor.execute(sql)
83             else:
---> 84                 return self.cursor.execute(sql, params)
85 
86     def _executemany(self, sql, param_list, *ignored_wrapper_args):
~/pastrami/rye/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py in execute(self, query, params)
421             return Database.Cursor.execute(self, query)
422         query = self.convert_query(query)
--> 423         return Database.Cursor.execute(self, query, params)
424 
425     def executemany(self, query, param_list):
IntegrityError: CHECK constraint failed: press_post

这是[edit: simplified]模型(只包括导致问题的字段)

class Post(models.Model):
doi = models.CharField(max_length=50, blank=True)
detailed_alts = models.JSONField(default=dict, blank=True)
alts = models.JSONField(default=dict, blank=True)

这是被[edit: simplified]覆盖的保存函数。

def save(self, *args, **kwargs):  # when saving, update alts
if bool(self.doi) is True:
self.detailed_alts = self.get_alts['detailed']
self.alts = self.get_alts['simple']

[编辑]

我从有用的评论中意识到问题是在我的自定义保存函数中更新了两个字段。检查约束失败,因为对于某些实例,我要求为这些JSONFields设置一些不允许的东西:使用numpy (np.nan)

的nan值这里是代码的相关(冒犯)部分:我的模型的get_alts方法。

def get_alts(self):
if 'context' in detailed_alts:
[do stuff]
else:
alts['context'] = np.nan
alts['rank'] = np.nan
return {'detailed': detailed_alts, 'simple': alts}

对于"context"不在detailed_alts字典中的实例,我不能将更改保存到实例中,因为我已将值设置为np。nan,这在JSONField中是不允许的。改变np。nan到' nan '修复了问题。

至于这是如何计算出来的,我只需要尝试注释掉保存函数的部分,直到我击中导致保存失败的部分。然后,我测试了保存函数中的每一行,但在尝试保存之前从未出现错误。所以,我突然意识到问题可能出在json字段上,因为我以前在序列化日期时遇到过一次问题。

谢谢你的帮助。问题是,在我的自定义保存函数中,当评估一个条件时,我分配了一个np。将一个值赋给字典中的一个键,然后将该键赋给模型的一个json字段。显然这是不允许的。我猜jsonfields不能序列化np.nan。我不知道从长远来看该怎么做,但将它们更改为"NaN"文本是有效的。大多数实例没有问题的原因是大多数实例没有返回nan值。

在Google上按标题搜索(我搜索的是django determine what field caused check constraint to fail),这个答案会出现在搜索结果的最前面(对我来说是第一个)。但实际上没有什么可以回答题目所提出的问题。

我终于能够通过深入调试PyCharm中的调用堆栈来找出导致问题的字段。在django.db.models.base.Model._do_insert中,当我检查要插入的对象的值时,在进入manager._insert之前,我发现在添加约束之前,我已经为字段提供了默认值,但是这些默认值现在与我的约束相冲突。因此,为了节省一些调试工作,我建议在_do_insert中设置一个断点,并查看模型对象的字段值。

最新更新