BadValueError:属性X是必需的

1 投票
2 回答
1249 浏览
提问于 2025-04-17 18:51

我在一个实体模型中添加了一个列表属性,这个模型已经有很多现存的实例。

class MyModel(db.Model):

    new_property = db.ListProperty(item_type=str, default=None)

在把这个应用程序部署到实际环境后,刚开始运行得还不错,但过了一段时间就开始出现BadValueError错误,原因是在尝试从数据存储中获取记录时出错。

导致错误的代码其实就是直接调用数据存储的代码:

app_item = db.get(app_item_key)

我使用的是Python 2.7运行时的1.7.5版本。

有没有什么办法可以防止这个问题,或者至少能捕捉到这个错误,以便我能从数据存储中获取数据呢?

Traceback (most recent call last):
  File "/base/data/home/apps/app/4-15.365909351579418812/app.py", line 1739, in app_get
    app_item = db.get(app_item_key)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1533, in get
    return get_async(keys, **kwargs).get_result()
  File "/python27_runtime/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 604, in get_result
    return self.__get_result_hook(self)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1459, in __get_hook
    entities = rpc.user_data(entities)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/api/datastore.py", line 600, in local_extra_hook
    return extra_hook(result)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1503, in extra_hook
    model = cls1.from_entity(entity)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1438, in from_entity
    return cls(None, _from_entity=entity, **entity_values)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 970, in __init__
    prop.__set__(self, value)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 614, in __set__
    value = self.validate(value)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 3460, in validate
    value = super(ListProperty, self).validate(value)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 641, in validate
    raise BadValueError('Property %s is required' % self.name)
BadValueError: Property new_property is required

给关注这个问题的人:

根据Aaron D的建议,把默认值改成一个空列表解决了这个问题,所以:

new_property = db.ListProperty(item_type=str, default=None)

应该改成:

new_property = db.ListProperty(item_type=str, default=[])

2 个回答

0

我很确定你这里的示例代码不是你实际使用的。我敢打赌你在新属性中设置了 required=True。然后你在获取一个旧记录,而这个记录没有这个必需属性的值。只要去掉 'required=True',这些错误就会消失。如果你需要这个值是必需的,那么你需要在强制这个限制之前,先给这个字段添加一个默认值。

* 删除了一些关于 None 不是 ListProperty 有效默认值的完全无用的内容 *

所以我根据你提供的信息尝试重现这个情况,结果我找到了答案。我可以通过首先创建一个名为 new_property 的模型,这个模型的类型是 StringProperty,默认值是 None。然后用 put() 方法记录没有 new_property 值的记录,这样就会写入默认值 None,然后把模型定义中的 new_property 改为 ListProperty,再去获取这个记录。我们会得到相同的错误追踪信息。请看下面的日志。

s~lightning-catfish> class MyModel(db.Model):
...   pass
... 
s~lightning-catfish> x = MyModel()
s~lightning-catfish> x.put()
datastore_types.Key.from_path(u'MyModel', 1001L, _app=u's~lightning-catfish')
s~lightning-catfish> class MyModel(db.Model):
...    new_property = db.ListProperty(item_type=str,default=None)
... 
s~lightning-catfish> y = db.get(x.key())
s~lightning-catfish> y
<MyModel object at 0x9e09dcc>
s~lightning-catfish> y.new_property
[]
s~lightning-catfish>    new_property = db.StringProperty(defaul
KeyboardInterrupt
s~lightning-catfish> class MyModel(db.Model):
...    new_property = db.StringProperty(default=None)
... 
s~lightning-catfish> z = MyModel()
s~lightning-catfish> z.put()
datastore_types.Key.from_path(u'MyModel', 2001L, _app=u's~lightning-catfish')
s~lightning-catfish> class MyModel(db.Model):
...    new_property = db.ListProperty(item_type=str,default=None)
... 
s~lightning-catfish> a1 = db.get(z.key())
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 1533, in get
    return get_async(keys, **kwargs).get_result()
  File "/home/timh/google_appengine/google/appengine/api/apiproxy_stub_map.py", line 604, in get_result
    return self.__get_result_hook(self)
  File "/home/timh/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1459, in __get_hook
    entities = rpc.user_data(entities)
  File "/home/timh/google_appengine/google/appengine/api/datastore.py", line 600, in local_extra_hook
    return extra_hook(result)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 1503, in extra_hook
    model = cls1.from_entity(entity)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 1438, in from_entity
    return cls(None, _from_entity=entity, **entity_values)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 970, in __init__
    prop.__set__(self, value)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 614, in __set__
    value = self.validate(value)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 3460, in validate
    value = super(ListProperty, self).validate(value)
  File "/home/timh/google_appengine/google/appengine/ext/db/__init__.py", line 641, in validate
    raise BadValueError('Property %s is required' % self.name)
BadValueError: Property new_property is required
s~lightning-catfish> 

要修复这些数据,你需要在较低的层级访问它,并更改记录中存储的数据类型。

如果你需要,我有不使用模型来获取和存储实体的代码。

* 最后你应该尝试的事情 *

尝试使用以下代码或类似的代码来获取对象,而不使用模型。这样你可以得到底层的数据,包含类型等信息,以字典的形式返回。这将显示数据存储中的内容。

from google.appengine.api import datastore
from google.appengine.api import datastore_errors

def get_entities(keys):
    rpc = datastore.GetRpcFromKwargs({})
    keys, multiple = datastore.NormalizeAndTypeCheckKeys(keys)
    entities = None
    try:
        entities = datastore.Get(keys, rpc=rpc)
    except datastore_errors.EntityNotFoundError:
        assert not multiple

    return entities


x = get_entities([some_key])
1

在你提到的错误追踪中,查看Google App Engine的源代码中的__init__.py文件,你会发现一个注释,在ListProperty的文档注释中(第3428行)写着:

注意,'required'的唯一允许值是True。

所以,即使你没有提供这个值,看起来第3442行的代码是自动设置这个值的:self._require_parameter(kwds, 'required', True)

如果你继续查看源代码(第3500行),你会看到ListPropertyempty()函数的定义:

def empty(self, value):
    """Is list property empty.

    [] is not an empty value.

    Returns:
      True if value is None, else false.
    """
    return value is None

我想到两个可能导致错误的问题,但我还没有通过测试来验证。

1) 如果因为某种原因,你在那个字段中已经有数据(也许你在重复使用new_property这个名字?),而且它是空的,那么这很可能会导致你遇到的错误。我不太确定怎么解决这个问题,除了建议你使用一个独特的new_property名称。我在评论中提到的帖子解释了如何“修复”数据。

2) 由于你已经有记录,你的代码试图用默认值None来填充这些记录,这与empty()的测试匹配,然后抛出异常。在这种情况下,如果你提供一个默认值[],应该就能正常工作。

撰写回答