- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
这是我的ndb模型
from google.appengine.ext import ndb
from mainsite.rainbow.models.CFCSocialUser import CFCSocialUser
class CFCSocialGroup(ndb.Model):
def remove_duplicate(self, value):
raise Exception("Duplicate user detected")
name = ndb.StringProperty(required=True)
created_on = ndb.DateTimeProperty(auto_now_add=True)
updated_on = ndb.DateTimeProperty(auto_now=True)
created_by = ndb.StructuredProperty(CFCSocialUser)
members = ndb.StructuredProperty(CFCSocialUser, repeated=True, validator=remove_duplicate)
@staticmethod
def create_group(name):
"""Create a new group"""
group = CFCSocialGroup(name=name)
return group
def add_member(self, social_user):
"""Add a member to the local group"""
self.members.append(social_user)
我正在努力确保不会将同一用户添加到给定组。所以我试图验证成员属性 (StructuredProperty) 的值。
我的测试是
from unittest import TestCase
from mainsite.rainbow.models.CFCSocialGroup import CFCSocialGroup
from tests.test_CFCSocialUser import create_user
from tests.cfcsocialtests.testbase import CFCTestBase_NDB
from nose.tools import *
from nose.plugins.attrib import attr
class TestCFCSocialGroup(CFCTestBase_NDB):
@attr("CRUD")
@raises(Exception)
def test_duplicate_addition(self):
"""Test to detect duplicate users in groups"""
user1 = create_user()
user2 = create_user()
group = CFCSocialGroup.create_group('Group1')
group.add_member(user1)
group.add_member(user2)
测试未能引发异常。
调试代码如下
FAILED (errors=1)
MacBook-Pro:tests vinay$ nosetests -v test_CFCSocialGroup.py
Test to detect duplicate users in groups ... FAIL
======================================================================
FAIL: Test to detect duplicate users in groups
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/nose/tools/nontrivial.py", line 67, in newfunc
raise AssertionError(message)
AssertionError: test_duplicate_addition() did not raise Exception
-------------------- >> begin captured logging << --------------------
root: DEBUG: Using threading.local
root: WARNING: No ssl package found. urlfetch will not be able to validate SSL certificates.
root: DEBUG: all_pending: add <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator put(context.py:787)
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: AutoBatcher(_memcache_set_tasklet): creating new queue for ('set', 32, '', None)
root: DEBUG: initial generator put(context.py:787) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:810); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_memcache_set_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d0ec250 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _memcache_set_tasklet(context.py:1111)
root: DEBUG: initial generator _memcache_set_tasklet(context.py:1111) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec490>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: memcache.Set
root: DEBUG: Sending {'NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw': 1} to suspended generator _memcache_set_tasklet(context.py:1122)
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True>
root: DEBUG: suspended generator _memcache_set_tasklet(context.py:1122) returned None
root: DEBUG: all_pending: success: remove <Future 10d0ec250 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True>
root: DEBUG: Sending True to suspended generator put(context.py:810)
root: DEBUG: all_pending: add <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: AutoBatcher(_put_tasklet): creating new queue for None
root: DEBUG: suspended generator put(context.py:810) yielded <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:824); pending> is now blocked waiting for <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: nowevent: _finished_callback
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_put_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d0ec610 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _put_tasklet(context.py:348)
root: DEBUG: initial generator _put_tasklet(context.py:348) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec890>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: datastore_v3.Put
root: DEBUG: Sending [Key('CFCSocialUser', 'Vinay Joseph')] to suspended generator _put_tasklet(context.py:358)
root: DEBUG: all_pending: success: remove <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')>
root: DEBUG: suspended generator _put_tasklet(context.py:358) returned None
root: DEBUG: all_pending: success: remove <Future 10d0ec610 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')>
root: DEBUG: Sending Key('CFCSocialUser', 'Vinay Joseph') to suspended generator put(context.py:824)
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: AutoBatcher(_memcache_del_tasklet): creating new queue for (0, '', None)
root: DEBUG: suspended generator put(context.py:824) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:833); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: nowevent: _finished_callback
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_memcache_del_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d0ec850 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _memcache_del_tasklet(context.py:1130)
root: DEBUG: initial generator _memcache_del_tasklet(context.py:1130) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec210>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: memcache.Delete
root: DEBUG: Sending [2] to suspended generator _memcache_del_tasklet(context.py:1141)
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2>
root: DEBUG: suspended generator _memcache_del_tasklet(context.py:1141) returned None
root: DEBUG: all_pending: success: remove <Future 10d0ec850 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2>
root: DEBUG: Sending 2 to suspended generator put(context.py:833)
root: DEBUG: suspended generator put(context.py:833) returned Key('CFCSocialUser', 'Vinay Joseph')
root: DEBUG: all_pending: success: remove <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); result Key('CFCSocialUser', 'Vinay Joseph')>
root: DEBUG: all_pending: add <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending>
root: DEBUG: nowevent: _finished_callback
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator put(context.py:787)
root: DEBUG: all_pending: add <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: AutoBatcher(_memcache_set_tasklet): creating new queue for ('set', 32, '', None)
root: DEBUG: initial generator put(context.py:787) yielded <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:810); pending> is now blocked waiting for <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending>
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_memcache_set_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d0ecd10 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _memcache_set_tasklet(context.py:1111)
root: DEBUG: initial generator _memcache_set_tasklet(context.py:1111) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ecf50>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: memcache.Set
root: DEBUG: Sending {'NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw': 1} to suspended generator _memcache_set_tasklet(context.py:1122)
root: DEBUG: all_pending: success: remove <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True>
root: DEBUG: suspended generator _memcache_set_tasklet(context.py:1122) returned None
root: DEBUG: all_pending: success: remove <Future 10d0ecd10 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True>
root: DEBUG: Sending True to suspended generator put(context.py:810)
root: DEBUG: all_pending: add <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: AutoBatcher(_put_tasklet): creating new queue for None
root: DEBUG: suspended generator put(context.py:810) yielded <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:824); pending> is now blocked waiting for <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); pending>
root: DEBUG: nowevent: _finished_callback
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_put_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d132110 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _put_tasklet(context.py:348)
root: DEBUG: initial generator _put_tasklet(context.py:348) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d132450>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: datastore_v3.Put
root: DEBUG: Sending [Key('CFCSocialUser', 'Vinay Joseph')] to suspended generator _put_tasklet(context.py:358)
root: DEBUG: all_pending: success: remove <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')>
root: DEBUG: suspended generator _put_tasklet(context.py:358) returned None
root: DEBUG: all_pending: success: remove <Future 10d132110 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='vinay@vinayjoseph.com', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')>
root: DEBUG: Sending Key('CFCSocialUser', 'Vinay Joseph') to suspended generator put(context.py:824)
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: AutoBatcher(_memcache_del_tasklet): creating new queue for (0, '', None)
root: DEBUG: suspended generator put(context.py:824) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:833); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending>
root: DEBUG: nowevent: _finished_callback
root: DEBUG: idler: _on_idle
root: DEBUG: AutoBatcher(_memcache_del_tasklet): 1 items
root: DEBUG: all_pending: add <Future 10d0eca10 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); pending>
root: DEBUG: nowevent: _help_tasklet_along
root: DEBUG: Sending None to initial generator _memcache_del_tasklet(context.py:1130)
root: DEBUG: initial generator _memcache_del_tasklet(context.py:1130) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ece10>
root: DEBUG: idler: _on_idle
root: DEBUG: idler _on_idle removed
root: DEBUG: rpc: memcache.Delete
root: DEBUG: Sending [2] to suspended generator _memcache_del_tasklet(context.py:1141)
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2>
root: DEBUG: suspended generator _memcache_del_tasklet(context.py:1141) returned None
root: DEBUG: all_pending: success: remove <Future 10d0eca10 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); result None>
root: DEBUG: nowevent: _on_future_completion
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2>
root: DEBUG: Sending 2 to suspended generator put(context.py:833)
root: DEBUG: suspended generator put(context.py:833) returned Key('CFCSocialUser', 'Vinay Joseph')
root: DEBUG: all_pending: success: remove <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); result Key('CFCSocialUser', 'Vinay Joseph')>
--------------------- >> end captured logging << ---------------------
----------------------------------------------------------------------
Ran 1 test in 0.035s
FAILED (failures=1)
最佳答案
给定 models.py
中的这段代码:
class Member(ndb.Model):
name = ndb.StringProperty()
def remove_duplicates(prop, value):
raise Exception('Duplicate')
class Club1(ndb.Model):
members = ndb.StructuredProperty(Member, repeated=True, validator=remove_duplicates)
我可以创建一个Member
实例
> m = Member(name='Alice')
使用此 Member
实例创建一个 Club1
实例会触发验证:
> c1 = models.Club1(members=[m])
Traceback (most recent call last):
<snip>
File "models.py", line 60, in remove_duplicates
raise Exception('Duplicate')
Exception: Duplicate
但是,创建一个空的 Club1
实例然后附加一个 Member
不会:这实际上是您的测试用例。
> c1 = models.Club1()
> c1.members.append(m)
> c1.put()
Key('Club1', 6682831673622528)
我们可以子类化 ndb.StructuredProperty
并将验证放在子类中:
class MembersStructuredProperty(ndb.StructuredProperty):
def _validate(self, value):
raise Exception('Duplicate')
class Club2(ndb.Model):
members = MembersStructuredProperty(Member, repeated=True)
创建一个带有 Member
的 Club2
实例会像以前一样触发验证:
> c2 = models.Club2(members=[m])
Traceback (most recent call last):
<snip>
File "models.py", line 56, in _validate
raise Exception('Duplicate')
Exception: Duplicate
现在附加一个 Member
然后尝试写入数据存储也是如此:
> c2 = models.Club2()
> c2.members.append(m)
> c2.put()
Traceback (most recent call last):
<snip>
File "models.py", line 56, in _validate
raise Exception('Duplicate')
Exception: Duplicate
因此子类化 ndb.StructuredProperty
应该可以让您的测试通过。
我不知道为什么 ndb 的属性验证会这样,可以说这是一个错误,或者至少是未记录的行为。
编辑:
正如@DanCornilescu 在评论中观察到的,这是一个 known bug在 SDK 中
关于python - 重复的 ndb.StructuredProperty 的验证器未能触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37028762/
我有一个实体,其中有一个可变数量的另一个实体(所以我使用结构化属性,repeated=True),但是一个属性也可以容纳可变数量的单一实体类型。所以我的代码看起来像这样: class Property
虽然 NDB 文档说: Although a StructuredProperty can be repeated and a StructuredProperty can contain anoth
我的模型都有一个将模型转换为字典的方法: def to_dict(model): output = {} SIMPLE_TYPES = (int, long, float, bool,
StructuredProperty 是否引用父级或子级? class Invoices(ndb.Model): #Child class Customers(ndb.Model): #Parent
StructuredProperty 上没有 populate 方法(如 ndb.Model 上的方法),那么如何从字典中填充这些字段? 最佳答案 您仍然可以填充StructuredProperty。
我读过很多关于这两者的文章 ndb.StructuredProperty在 App Engine 的 NDB 中以及 ancestor queries 的使用将相关实体分组在一起。 但是,我不确定我是
我想将位置存储在 Google 的数据存储区中。每个条目应具有“sys”字段,其中应包含数据存储设置的信息。我有下面的类模型,并且 WebService JSON 请求/响应看起来不错,但我必须手动设
在一个汽车历史应用程序中,我必须创建不同的图表,其中某些车型可能会出现在一个或多个不同的图表中,如“最快的汽车”、“最好的汽车”等。然后必须在图表中对它们进行排序。我使用 StructuredProp
这里是 StructuredProperty from the docs 的示例: class Address(ndb.Model): type = ndb.StringProperty()
我有一个 HUser 模型(派生自 Google 的 User 类),它又包含 0 到 n 个社交帐户实例。这些帐户可以是对 Facebook、Twitter 或 LinkedIn 帐户的引用。我已经
假设我有一个 ndb.Model 类,我想将其用作另一个模型类的 StructuredProperty: class CommonExtraData(ndb.Model): count = n
这是我的ndb模型 from google.appengine.ext import ndb from mainsite.rainbow.models.CFCSocialUser import CFC
使用appengine mapreduce lib时,如何通过StructuredProperty进行过滤? 我尝试过: class Tag(ndb.Model): # ... tag
我正在尝试使用 Expando模型作为重复 StructuredProperty在另一个模型中。即,我想添加不定数量的Accounts给我的User模型。如Accounts根据其类型可以具有不同的属性
我使用 Google App Engine 进行后端开发,并使用数据存储模型和 Google Cloud Storage 来存储图像对象。这是我的媒体模型 class Media(ndb.Model)
我有一个 ndb.Model,其中包含一个 Repeated 属性。 class Resort(ndb.Model): name = ndb.StringProperty()
大家好,我正在尝试弄清楚如何针对以下情况构造我的查询 首先我定义了一个模型 class Variant(ndb.Expando): test = ndb.StringProperty() cl
大家好,我正在尝试弄清楚如何针对以下情况构造我的查询 首先我定义了一个模型 class Variant(ndb.Expando): test = ndb.StringProperty() cl
我是一名优秀的程序员,十分优秀!