Hi 

You are correct, 

s~cash-drawer> class SecondModel(ndb.Model):
...     important_prop = ndb.StringProperty(required=True)
...
s~cash-drawer> class FirstModel(ndb.Model):
...     some_prop = ndb.StringProperty()
...     some_other_prop = ndb.StructuredProperty(SecondModel, required=True)
...
s~cash-drawer> model2 = SecondModel()
s~cash-drawer> model2.put()
WARNING:root:initial generator _put_tasklet(context.py:270) raised 
BadValueError(Entity has uninitialized properties: important_prop)
WARNING:root:suspended generator put(context.py:733) raised 
BadValueError(Entity has uninitialized properties: important_prop)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", 
line 3187, in _put
    return self._put_async(**ctx_options).get_result()
  File "/home/timh/google_appengine/google/appengine/ext/ndb/tasklets.py", 
line 325, in get_result
    self.check_success()
  File "/home/timh/google_appengine/google/appengine/ext/ndb/tasklets.py", 
line 368, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/home/timh/google_appengine/google/appengine/ext/ndb/context.py", 
line 733, in put
    key = yield self._put_batcher.add(entity, options)
  File "/home/timh/google_appengine/google/appengine/ext/ndb/tasklets.py", 
line 371, in _help_tasklet_along
    value = gen.send(val)
  File "/home/timh/google_appengine/google/appengine/ext/ndb/context.py", 
line 280, in _put_tasklet
    keys = yield self._conn.async_put(options, datastore_entities)
  File 
"/home/timh/google_appengine/google/appengine/datastore/datastore_rpc.py", 
line 1542, in async_put
    pbs = [self.__adapter.entity_to_pb(entity) for entity in entities]
  File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", 
line 562, in entity_to_pb
    pb = ent._to_pb()
  File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", 
line 2906, in _to_pb
    self._check_initialized()
  File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", 
line 2783, in _check_initialized
    'Entity has uninitialized properties: %s' % ', '.join(baddies))
BadValueError: Entity has uninitialized properties: important_prop
s~cash-drawer> model2 = SecondModel()
s~cash-drawer> model1 = FirstModel(some_other_prop=model2)
s~cash-drawer> model1.put()
Key('FirstModel', 12001)
s~cash-drawer> model1
FirstModel(key=Key('FirstModel', 12001), some_other_prop=SecondModel())
s~cash-drawer>


However is it really a bug in NDB or NDB documentation.

Model validation is called at put() time, however a structured property 
components aren't directly written to the datastore as a model in your 
case. It is serialized and stored in a property of the outer model and the 
only model validation that will be performed is on .  You will also find 
that any hooks on that model used in the structured property won't have 
it's hooks called (pre_put, post_put, pre_delete . etc...)

Cheers

Tim



On Tuesday, November 4, 2014 10:43:04 PM UTC+8, Lapteuh wrote:
>
> I tested SecondModel() without parameters and result is same. Still no 
> error.
>
> вторник, 4 ноября 2014 г., 19:11:40 UTC+5 пользователь timh написал:
>>
>> Not sure I would interpret it as a bug
>>
>> If you do model2 = SecondModel()
>>
>> You would get the error you expect..
>>
>> Setting a property (especiallya StringProperty) explicitly to None, is 
>> not the same as not setting the value of the property.
>> The former will define the Property with a value of None, the second 
>> won't define a value for the property.
>>
>> You can see this also in the how indexes work, the former will have a 
>> value in the index, the later won't even have a record in the index for 
>> some_other_prop
>>
>> So in my opinion it isn't a bug, but could probably do with more explicit 
>> documentation.
>>
>> Just my 2c 
>>
>> Cheers
>>
>> T
>>
>> On Friday, October 24, 2014 9:04:13 PM UTC+8, Lapteuh wrote:
>>>
>>> Hello. Noticed a strange behavior in the library ndb. In my opinion it 
>>> looks like a bug.
>>>
>>> Example:
>>>
>>> class SecondModel(ndb.Model):
>>>     important_prop = ndb.StringProperty(required=True)
>>>
>>>
>>> class FirstModel(ndb.Model):
>>>     some_prop = ndb.StringProperty()
>>>
>>>     some_other_prop = ndb.StructuredProperty(SecondModel, required=True)
>>>     
>>>     
>>> def some_func():
>>>
>>>     buggy = None # attention here
>>>
>>>     model2 = SecondModel(important_prop=buggy)
>>>     model1 = FirstModel(some_other_prop=model2)
>>>     model1.put()
>>>     return 
>>>
>>>
>>> Despite the fact that the code does not need to work, he works. No 
>>> exception! '*required*' option in property '*important_prop*' from '
>>> *SecondModel*' just ignored.
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to google-appengine+unsubscr...@googlegroups.com.
To post to this group, send email to google-appengine@googlegroups.com.
Visit this group at http://groups.google.com/group/google-appengine.
For more options, visit https://groups.google.com/d/optout.

Reply via email to