Google Code предлагается на следующих языках: English – Español – 日本語 – 한국어 – Português – Pусский – 中文(简体) – 中文(繁體)
Хранение данных в масштабируемом веб-приложении может быть непростой задачей. В определенный момент времени пользователь может взаимодействовать с любым из десятков веб-серверов, а его следующий запрос может отправиться уже не на тот веб-сервер, который обрабатывал предыдущий. Все веб-серверы должны взаимодействовать с данными, которые также распределены по десяткам компьютеров, возможно расположенным в разных точках планеты.
Google App Engine позволяет вам забыть о подобных проблемах. Инфраструктура App Engine занимается распределением, копированием и регулированием нагрузки данных с помощью простого API, а вы получаете мощный механизм поиска и транзакции.
Вот новая версия примера helloworld/helloworld.py, сохраняющая приветствия в хранилище данных. Далее на странице обсуждаются новые фрагменты примера.
import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
for greeting in greetings:
if greeting.author:
self.response.out.write('<b>%s</b> wrote:' % greeting.author.nickname())
else:
self.response.out.write('An anonymous person wrote:')
self.response.out.write('<blockquote>%s</blockquote>' %
cgi.escape(greeting.content))
# Write the submission form and the footer of the page
self.response.out.write("""
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
</body>
</html>""")
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/')
application = webapp.WSGIApplication(
[('/', MainPage),
('/sign', Guestbook)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Замените helloworld/helloworld.py этим файлом и перезагрузите адрес http://localhost:8080/ в своем браузере. Добавьте несколько сообщений, чтобы убедиться, что их сохранение и отображение выполняется правильно.
App Engine включает API моделирования данных для Python. Он похож на API моделирования данных Django, но использует масштабируемое хранилище данных App Engine.
В приложении гостевой книги нам нужно сохранять приветствия, размещенные пользователями. Каждое из них содержит имя автора, содержание сообщения, а также дату и время его размещения, чтобы сообщения можно было отображать в хронологическом порядке.
Чтобы воспользоваться API моделирования данных, импортируйте модуль google.appengine.ext.db:
from google.appengine.ext import db
Ниже определяется модель данных для приветствия:
class Greeting(db.Model): author = db.UserProperty() content = db.StringProperty(multiline=True) date = db.DateTimeProperty(auto_now_add=True)
Это определяет модель Greeting с тремя свойствами: author, значением которого является объект User, content, значением которого является строка и date со значением datetime.datetime.
Некоторые конструкторы свойств принимают параметры для более сложной настройки поведения. Передача конструктору db.StringProperty параметра multiline=True означает, что значения этого свойства могут содержать символы перевода строки. Передача конструктору db.DateTimeProperty параметра auto_now_add=True настраивает модель так, что она автоматически присваивает новым объектам свойство date при создании объекта, если приложение не предоставляет это значение иным способом. Полный список типов свойств и их параметров приведен в Справочном руководстве хранилища данных.
Теперь у нас есть модель данных для приветствий, и приложение может использовать ее для создания новых объектов Greeting и их размещения в хранилище данных. Ниже представлена новая версия обработчика Guestbook, создающего новые приветствия и сохраняющего их в хранилище данных:
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/')
Такой обработчик Guestbook создает новый объект Greeting и задает для его свойств author и content значения, указанные пользователем. Он не задает свойства date, поэтому date автоматически устанавливается на "сейчас" согласно конфигурации нашей модели.
Наконец, метод greeting.put() сохраняет наш новый объект в хранилище данных. Если этот объект был получен через запрос, метод put() обновит существующий объект. Так как мы создали этот объект с помощью конструктора модели, метод put() добавит новый объект в хранилище данных.
Хранилище данных App Engine имеет сложный механизм запросов для моделей данных. Поскольку хранилище данных App Engine не является обычной реляционной базой данных, запросы определяются не с помощью SQL. Вместо этого запросы можно писать на языке, подобном SQL, который мы называем GQL. GQL дает доступ к функциям механизма запросов хранилища данных App Engine с использованием привычного синтаксиса.
Ниже представлена новая версия обработчика MainPage, запрашивающего приветствия из хранилища данных:
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
for greeting in greetings:
if greeting.author:
self.response.out.write('<b>%s</b> wrote:' % greeting.author.nickname())
else:
self.response.out.write('An anonymous person wrote:')
self.response.out.write('<blockquote>%s</blockquote>' %
cgi.escape(greeting.content))
# Write the submission form and the footer of the page
self.response.out.write("""
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
</body>
</html>""")
Запрос выполняется в этой строке:
greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
Можно также вызвать метод gql(...) для класса Greeting и убрать из запроса текст SELECT * FROM Greeting:
greetings = Greeting.gql("ORDER BY date DESC LIMIT 10")
Как и в SQL, ключевые слова (например, SELECT) не зависят от регистра. Однако названия от регистра зависят.
Запрос возвращает полные объекты данных, поэтому нет смысла выбирать из модели определенные свойства. Все запросы GQL начинаются с текста SELECT * FROM model (или это подразумевается методом gql(...) модели) ради сходства со своими SQL-эквивалентами.
Запрос GQL может иметь условие WHERE, фильтрующее набор результатов в зависимости от значений одного или нескольких свойств. В отличие от SQL, GQL-запросы не могут содержать констант. Вместо этого в GQL используется привязка параметров для всех значений в запросах. Например, вот так можно получить приветствия, отправленные только текущим пользователем:
if users.get_current_user():
greetings = Greeting.gql("WHERE author = :1 ORDER BY date DESC",
users.get_current_user())
Вместо позиционных можно также использовать именованные параметры:
greetings = Greeting.gql("WHERE author = :author ORDER BY date DESC",
author=users.get_current_user())
Кроме GQL, API хранилища данных предоставляет еще один механизм построения объектов запросов, использующий методы. Приведенный выше запрос также можно создать следующим образом:
greetings = Greeting.all()
greetings.filter("author =", users.get_current_user())
greetings.order("-date")
Полное описание GQL и API запросов приведено в справочном руководстве хранилища данных.
Веб-сервер разработки использует локальную версию хранилища данных для тестирования приложения, использующую временные файлы. Данные хранятся, пока существуют временные файлы, а веб-сервер не удаляет их, пока вы не укажете ему сделать это.
Если вам нужно, чтобы сервер разработки очистил хранилище перед началом работы, используйте при запуске сервера параметр --clear_datastore:
dev_appserver.py --clear_datastore helloworld/
Теперь у нас есть работающее приложение гостевой книги, которое аутентифицирует пользователей с помощью аккаунтов Google, позволяет им отправлять сообщения и отображает сообщения, оставленные другими. Поскольку App Engine автоматически выполняет масштабирование, менять код по мере роста популярности приложения не нужно.
В этой последней версии HTML-содержание смешано с кодом обработчика MainPage. Это затруднит изменение внешнего вида приложения, особенно когда оно станет больше и сложнее. Для управления внешним видом можно воспользоваться шаблонами, а также ввести статические файлы для таблиц CSS-стилей.
Переходите к разделу Использование шаблонов.