Как решить какое-то отношение куриных яиц в ndb.Models?
У меня есть две сущности (события и пользователи). У каждого пользователя есть несколько событий, но я не хочу, чтобы они были сохранены в StructuredProperty, потому что в будущем должно быть возможно иметь несколько создателей / администраторов. Теперь у меня есть проблема, что пользователю нужен класс событий для определения и наоборот. Как я могу реализовать предполагаемую структуру?
Две модели с взаимоотношениями.
class Event(EndpointsModel):
_message_fields_schema = ("id", "name", "creator",
"datetime", "place", "category", "participants")
creator = ndb.KeyProperty(kind=User)
participants = ndb.KeyProperty(kind=User, repeated=True)
name = ndb.StringProperty()
datetime = ndb.DateTimeProperty(auto_now_add=True)
place = ndb.GeoPtProperty()
category = ndb.StringProperty(choices=('all', 'drinking'))
class User(EndpointsModel):
_message_fields_schema = ("id", "name", "password", "events")
name = ndb.StringProperty()
password = ndb.StringProperty()
events = ndb.KeyProperty(kind=Event, repeated=True)
def create_event(self, e_name, e_datetime, e_place, e_category):
event = Event(name=e_name, creator = self.key, datetime=e_datetime, place=e_place, category=e_category)
event.put()
self.events.append(event)
self.put()
def get_events(self):
return ndb.get_multi(self.events)
Сообщение об ошибке:
NameError: имя 'User' не определено
РЕДАКТИРОВАТЬ 1: Я изменил вид на строку, содержащую имя класса, как предложил Грег. Но это тоже не работает.
class Category(EndpointsModel):
_message_fields_schema = ("id", "name", "parent")
name = ndb.StringProperty()
parent = ndb.KeyProperty(kind='Category', default=None)
class Event(EndpointsModel):
_message_fields_schema = ("id", "name", "creator", "datetime",
"place", "category")
participants = ndb.KeyProperty(kind='User', repeated=True)
creator = ndb.KeyProperty(kind='User')
name = ndb.StringProperty()
datetime = ndb.DateTimeProperty(auto_now_add=True)
place = ndb.GeoPtProperty()
category = ndb.KeyProperty(Category)
class User(EndpointsModel):
_message_fields_schema = ("id", "name", "password")
name = ndb.StringProperty()
password = ndb.StringProperty()
events = ndb.KeyProperty(Event, repeated=True)
Теперь я получаю следующую трассировку стека:
ERROR 2014-01-21 09:38:39,764 service.py:191] Encountered unexpected error from ProtoRPC method implementation: BadValueError (Expected Key, got [])
Traceback (most recent call last):
File "/home/chris/Downloads/google_appengine/lib/protorpc-1.0/protorpc/wsgi/service.py", line 181, in protorpc_service_app
response = method(instance, request)
File "/home/chris/Downloads/google_appengine/lib/endpoints-1.0/endpoints/api_config.py", line 1321, in invoke_remote
return remote_method(service_instance, request)
[...]
value = self._call_shallow_validation(value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1227, in _call_shallow_validation
return call(value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1274, in call
newvalue = method(self, value)
File "/home/chris/Downloads/google_appengine/google/appengine/ext/ndb/model.py", line 1927, in _validate
raise datastore_errors.BadValueError('Expected Key, got %r' % (value,))
BadValueError: Expected Key, got []
3 ответа
Вы можете использовать строки в конструкторе KeyProperty для ссылки на виды, которые не имеют определения модели:
class Event(ndb.Model):
participants = ndb.KeyProperty(kind='User', repeated=True)
Вы не можете создавать такие ссылки на объекты. Вот некоторые решения: 1. Вы должны использовать обычный StringProperty для Event.creator или другой идентификатор для экземпляра User. 2. Удалить четные объекты из класса User - вы можете достичь четных по индексу в классе Events 3. Используйте третью модель сущностей, например, так:
class EventCreator(EndpointsModel):
creator = ndb.KeyProperty(kind=User)
event = ndb.KeyProperty(kind=Event)
и из класса User удалить создателя & из класса Event удалить
Вы можете указать ключевые свойства без параметра kind (это необязательно), а затем выполнить ручную проверку в своем конструкторе или предварительно установленный хук или что-то в этом роде - или, возможно, даже не беспокоиться о виде:
class Event(EndpointsModel):
creator = ndb.KeyProperty()
# Constructor option
def __init__(self, *args, **kwargs):
super(Event, self).__init__(*args, **kwargs)
if 'creator' in kwargs and kwargs['creator'] != 'User':
raise Exception('oh no')
# Hook option
_pre_put_hook(self):
if self.creator and self.creator.kind() != 'User':
raise Exception("oh no")
Фактический синтаксис, вероятно, будет немного другим. Не стесняйтесь редактировать.