Одна из проблем, с которой вы столкнетесь, заключается в том, что создание уникального User.ID
будет нетривиальным. Проблема состоит в том, что две записи в базу данных могут происходить на разных шардах, оба проверяют примерно в одно и то же время существующие записи, которые соответствуют ограничению уникальности и не находят ни одного, затем обе создают идентичные записи (относительно уникального свойства), а затем иметь недопустимое состояние базы данных. Для решения этой проблемы appengine предоставляет средство, гарантирующее, что определенные сущности хранилища данных всегда размещаются на одном физическом компьютере.
Для этого вы используете ключи сущностей, чтобы сообщить Google, как организовать сущности. Предположим, вы хотите, чтобы имя пользователя было уникальным. Измените User
, чтобы оно выглядело так:
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
Да, это действительно так. Там нет имени пользователя, так как он будет использоваться в ключе, поэтому он не должен появляться отдельно. Если хотите, вы можете сделать это ...
class User(db.Model):
datejoined = db.DateTimeProperty(auto_now_add=True)
@property
def name(self):
return self.key().name()
Чтобы создать экземпляр User
, теперь вам нужно сделать что-то немного другое, вам нужно указать key_name
в методе init.
someuser = User(key_name='john_doe')
...
someuser.save()
Ну, на самом деле вы хотите убедиться, что пользователи не перезаписывают друг друга, поэтому вам нужно заключить создание пользователя в транзакцию. Сначала определите функцию, которая выполняет необходимую проверку:
def create_user(username):
checkeduser = User.get_by_key_name(username)
if checkeduser is not None:
raise db.Rollback, 'User already exists!'
newuser = User(key_name=username)
# more code
newuser.put()
Затем, вызовите его таким образом
db.run_in_transaction(create_user, 'john_doe')
Чтобы найти пользователя, вы просто делаете это:
someuser = User.get_by_key_name('john_doe')
Далее вам нужно каким-то образом связать контент с его пользователем, и наоборот. Одно из решений состоит в том, чтобы поместить контент в ту же группу сущностей, что и пользователь, объявив пользователя родителем контента. Для этого вам вообще не нужно менять контент, но вы создаете его немного по-другому (так же, как вы это делали с пользователем):
somecontent = Content(parent=User.get_by_key_name('john_doe'))
Итак, с учетом элемента контента вы можете найти пользователя, проверив его ключ:
someuser = User.get(somecontent.key().parent())
В обратном порядке, поиск всего контента для конкретного пользователя является лишь немного хитрее.
allcontent = Content.gql('where ancestor is :user', user=someuser).fetch(10)