NDB querying a GenericProperty in repeated Expando StructuredProperty

社会主义新天地 提交于 2019-12-06 12:01:18

It's easy using GQL:

Item.gql("WHERE variants.dynamic = 'a'").fetch()

Also this works:

s = StringProperty()
s._name = 'variants.dynamic')
Item.query(s == 'a').fetch()

Please do file a feature request; however it's going to be a balancing act. What syntax would you like to use?

UPDATE:

The same thing works with GenericProperty(), or any other Property subclass.

The reason that GenericProperty('variants.dynamic') is forbidden is to prevent people from doing hacks like this:

class MyHack(ndb.Model):
  foo = StringProperty('bar.baz')

which will confuse the serialization and deserialization code.

Maybe we can add a flag to Property that skips this check but then disallows using the property in a model definition (it would only allow it in a query).

Or maybe we can make this work (I think this would be hard though):

Item.query(Item.variants.dynamic == 'a').fetch()

(only if variants is an Expando).

You can do this with a bit of magic.

SHORT ANSWER:

variants_dynamic_property = ndb.GenericProperty()
variants_dynamic_property._name = 'variants.dynamic'
q = Item.query(variants_dynamic_property == 'a')

LONG ANSWER:

Since you are querying for a GenericProperty, you'll need to create one as the docs state, e.g.:

FlexEmployee.query(ndb.GenericProperty('location') == 'SF')

Similarly, when querying for a StucturedProperty, the docs state you can use a property of the property, e.g.:

Contact.query(Contact.address.city == 'Amsterdam')

So combining these, you would need

Item.query(ndb.GenericProperty('variants.dynamic') == 'a')

but trying to construct the property via ndb.GenericProperty('variants.dynamic') results in the following exception:

  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/utils.py", line 136, in positional_wrapper
    return wrapped(*args, **kwds)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2366, in __init__
    super(GenericProperty, self).__init__(name=name, **kwds)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/utils.py", line 136, in positional_wrapper
    return wrapped(*args, **kwds)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 765, in __init__
    raise ValueError('Name %r cannot contain period characters' % (name,))
ValueError: Name 'variants.dynamic' cannot contain period characters

But you can get around this by using the constructor with no property name and then setting the name after the fact:

variants_dynamic_property = ndb.GenericProperty()
variants_dynamic_property._name = 'variants.dynamic'

Hackish Solution:

A temporary solution: Using a ComputedProperty to query by - in our case:

(adding the following to the model definition)

computed_prop = ndb.ComputedProperty(lambda self: self.repeating_prop[0].sub_prop if self.repeating_prop else None)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!