2

我正在使用 django 3. sqlite 数据库。我有一种情况,其中一个模型中的实例无法保存。我收到一个完整性错误和“CHECK 约束失败”,然后是我的模型名称(我的“press”应用程序中的“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

这是[编辑:简化]模型(仅包括导致问题的字段)

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)

这是[编辑:简化]覆盖的保存功能。

    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']

[编辑]

我从有用的评论中意识到问题出在我的自定义保存功能中,我在其中更新了两个字段。Check 约束失败,因为在某些情况下,我要求为这些 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}

对于“上下文”不在detailed_alts 字典中的实例,我无法保存对实例的更改,因为我已将值设置为np.nan,我猜这在JSONField 中是不允许的。将 np.nan 更改为 'NaN' 解决了这个问题。

至于这是如何解决的,我只需要尝试注释掉保存功能的部分内容,直到找到导致保存失败的部分。然后我测试了保存功能中的每一行,但在尝试保存之前从未出错。因此,不知何故,我突然意识到问题可能出在 jsonfield 上,因为我之前在序列化日期时遇到过问题。

4

2 回答 2

0

感谢您的帮助。问题是在我的自定义保存函数中,在评估其中一个条件时,我将 np.nan 值分配给字典中的键,然后将其分配给模型的 jsonfield 字段之一。显然这是一个禁忌。我猜jsonfields不能序列化np.nan。从长远来看,我不确定该怎么做,但是将它们更改为“NaN”文本是可行的。大多数实例没有问题的原因是因为大多数没有返回 nan 值。

于 2021-08-30T05:13:40.193 回答
0

沿着标题行的谷歌搜索(我的具体搜索是django determine what field caused check constraint to fail)将在结果中拉高这个答案(首先对我来说)。但实际上几乎没有回答标题提出的问题。

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

于 2021-12-19T10:39:09.790 回答