首页 > 解决方案 > DeserializationError: ['“F(view_count) + Value(1)” value must be an integer.']

问题描述

我正在使用 Django 3.2

我正在使用 F 值来增加字段值(以避免潜在的竞争条件) -正如官方文档中所建议的那样

这是我的代码片段(引发异常的部分):

  def __update_fields(self, interaction_type):

        if interaction_type == Engagement.VIEW:
            self.view_count = F('view_count') + 1
        #elif check which field needs updating ...

        self.save() # By the time we get here, the necessary field (NOTE: **SINGULAR** word 'field') would have been updated

        self.refresh_from_db()   

我收到此错误:

DeserializationError: ['“F(view_count) + Value(1)” value must be an integer.']: (poll.poll:pk=10) field_value was 'F(view_count) + Value(1)'

这是完整的堆栈跟踪:

Internal Server Error: //path/to/example
Traceback (most recent call last):
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 1836, in to_python
    return int(value)
ValueError: invalid literal for int() with base 10: 'F(view_count) + Value(1)'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/core/serializers/python.py", line 144, in Deserializer
    data[field.name] = field.to_python(field_value)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 1838, in to_python
    raise exceptions.ValidationError(
django.core.exceptions.ValidationError: ['“F(view_count) + Value(1)” value must be an integer.']

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/views/generic/detail.py", line 107, in get
    context = self.get_context_data(object=self.object)
  File "/path/to/myproj/poll/views.py", line 513, in get_context_data
    poll.interact(self.request.user, Engagement.VIEW, self.request)
  File "/path/to/myproj/social/models.py", line 988, in interact
    self.__update_fields(interaction_type)
  File "/path/to/myproj/social/models.py", line 947, in __update_fields
    self.save()
  File "/path/to/myproj/poll/models.py", line 97, in save
    super().save(*args, **kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/base.py", line 726, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/base.py", line 774, in save_base
    post_save.send(
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 180, in send
    return [
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/path/to/myproj/moderation/register.py", line 321, in post_save_handler
    moderated_obj = ModeratedObject.objects.get_for_instance(instance)
  File "/path/to/myproj/moderation/managers.py", line 73, in get_for_instance
    moderated_object = self.get(object_pk=instance.pk,
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/query.py", line 431, in get
    num = len(clone)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/query.py", line 262, in __len__
    self._fetch_all()
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/query.py", line 1324, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/query.py", line 69, in __iter__
    obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/base.py", line 515, in from_db
    new = cls(*values)
  File "/path/to/myproj/moderation/models.py", line 66, in __init__
    super().__init__(*args, **kwargs)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/db/models/base.py", line 505, in __init__
    post_init.send(sender=cls, instance=self)
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 180, in send
    return [
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/path/to/myproj/moderation/fields.py", line 90, in post_init
    self._deserialize(value))
  File "/path/to/myproj/moderation/fields.py", line 54, in _deserialize
    obj = next(obj_generator).object
  File "/path/to/myproj/env/lib/python3.8/site-packages/djmoney/serializers.py", line 55, in Deserializer
    for inner_obj in PythonDeserializer([obj], **options):
  File "/path/to/myproj/env/lib/python3.8/site-packages/django/core/serializers/python.py", line 146, in Deserializer
    raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
django.core.serializers.base.DeserializationError: ['“F(view_count) + Value(1)” value must be an integer.']: (poll.poll:pk=10) field_value was 'F(view_count) + Value(1)'

这个神秘错误的含义是什么(我传递的值 [1],显然是一个整数)。我该如何解决这个问题?

[[编辑]]

我在调试控制台中做了一些额外的调查,看看表达式实际返回了什么F('field_name') + 1

结果如下:

my_object.view_count   # This is immediately after the assignment `F() + var`
<CombinedExpression: F(view_count) + Value(1)>
my_object.save()       # Saving to see if exception thown (none thrown)
None
photo.view_count       # Checking to see what on earth is stored in the field
<CombinedExpression

因此,似乎 django 文档是错误的或者我误解了如何安全地增加字段值 - 直接在数据库中编写 SP 可能会更快,甚至编写一个线程安全类来处理这个 - 它真的不应该这么难做到这一点。

标签: djangodjango-modelsdjango-querysetrace-condition

解决方案


将我的评论转换为答案以添加更多上下文。

view_count 的初始值是否可能不是整数?例如没有?

此外,从堆栈跟踪中,我看到在__update_fields. 如果对那里的当前实例执行更多操作view_count,则可能会因此而出现问题。基本上,如果以后使用相同的 python 实例,值view_count将是。<CombinedExpression: F(view_count) + Value(1)>

保存后您可能需要从数据库中刷新实例。


推荐阅读