В предыдущей статье мы выяснили, что такое Google AppEngine, что с ним можно делать, и создали самое простое и примитивное приложение для GAE — helloworld с минимальной поддержкой аутентификации пользователей. Попробуем расширить это приложение, рассмотрев, попутно, возможности Google AppEngine.
Наше предыдущее приложение было предельно простым, и, как таковое, ни в какой архитектуре не нуждалось. Теперь мы ставим перед собой более сложную и более реальную задачу — соответственно, нам следует подумать о том, что будет, когда приложение начнет расти. Разумеется, наша задача выдумана и для нее никакой архитектуры тоже не требуется, но для примера попробуем все сделать «по науке».
Вот так будет выглядеть наше приложение с точки зрения структуры. Голубые прямоугольники обозначают, что эти страницы доступны и видны для всех. Желтый означает, что его содержимое может меняться, если активна пользовательская сессия. Оранжевые целиком закрыты от внешнего мира и на них можно попасть только если перед этим залогиниться.
Две страницы на картинке выше будут предоставлены нам GAE — а именно, «Login with Google» и «Logout». Все, что требуется от нас это:
В нашем приложении модель хранения данных будет совсем несложной, однако, как мне кажется, этого будет вполне достаточно чтобы проиллюстрировать возможности GAE Datastore. Допустим, нам нужно хранить информацию о пользователе, а именно — его идентификатор, дату и время последнего визита и количество визитов. На языке GAE Datastore это будет выглядеть вот так:
http://code.google.com/p/habr-gae-helloworld/source/browse/trunk/model.py
Разберемся, кто здесь что. Класс
Этого достаточно, чтобы объект был сохранен и доступен позже как часть entity
Это была вторая часть из цикла статей про AppEngine. В следующих частях мы доберемся до вкусного — собственно написание контроллера и представления. Жду ваших комментариев, предложений и вопросов.
P.S. посоветуйте пожалуйста хороший syntax highlighter для Питона, который будет нормально работать с Хабром? tohtml.com которым я всегда пользовался генерирует нечто несовместимое с Парсером.
Update: Третья часть — habrahabr.ru/blogs/gae/81933
Структура и архитектура
Наше предыдущее приложение было предельно простым, и, как таковое, ни в какой архитектуре не нуждалось. Теперь мы ставим перед собой более сложную и более реальную задачу — соответственно, нам следует подумать о том, что будет, когда приложение начнет расти. Разумеется, наша задача выдумана и для нее никакой архитектуры тоже не требуется, но для примера попробуем все сделать «по науке».
Вот так будет выглядеть наше приложение с точки зрения структуры. Голубые прямоугольники обозначают, что эти страницы доступны и видны для всех. Желтый означает, что его содержимое может меняться, если активна пользовательская сессия. Оранжевые целиком закрыты от внешнего мира и на них можно попасть только если перед этим залогиниться.
Две страницы на картинке выше будут предоставлены нам GAE — а именно, «Login with Google» и «Logout». Все, что требуется от нас это:
- Написать главную страницу, которая будет давать какую-то вменяемую информацию и предлагать логиниться
- Написать вариант главной страницы для пользователей, которые уже залогинились
- Написать login-handler, который будет регистрировать факт логина и перенаправлять пользователя на главную страницу
- Написать страницу статистики, которая будет показывать, сколько раз пользователь логинился в систему и когда был последний раз.
Модель
В нашем приложении модель хранения данных будет совсем несложной, однако, как мне кажется, этого будет вполне достаточно чтобы проиллюстрировать возможности GAE Datastore. Допустим, нам нужно хранить информацию о пользователе, а именно — его идентификатор, дату и время последнего визита и количество визитов. На языке GAE Datastore это будет выглядеть вот так:
#!/usr/bin/env python # encoding: utf-8 """ model.py $Id: model.py 4 2010-01-25 12:14:48Z sigizmund $ Created by Roman Kirillov on 2010-01-25. """ import datetime from google.appengine.ext import db from google.appengine.api import users class Visitor(db.Model): ''' Simple object which uses Google DataStore persistence model ''' '''UserProperty encapsulates information about a Google's user account available to application. It is set to use current user as a default user automatically whever new object is created''' user = db.UserProperty(required = True, auto_current_user_add = True) '''DateTimeProperty uses standard underlying datetime.datetime and is set to auto-update to now() whenever record is saved''' lastVisit = db.DateTimeProperty(auto_now = True) '''Very simple integer property with default value of 0''' hits = db.IntegerProperty(default = 0)
http://code.google.com/p/habr-gae-helloworld/source/browse/trunk/model.py
Разберемся, кто здесь что. Класс
Visitor
унаследован от стандартного GAE класса google.appengine.ext.db.Model
, который является интерфейсом к Datastore — все классы, которые хотят быть персистентными с использованием данной технологии, должны расширять этот класс. У нашего класса Visitor
есть три поля данных: user
, lastVisit
и hits
. Рассмотрим их в деталях, начиная с последнего.db.IntegerProperty hits
инкапсулирует обычный целочисленный тип данных. По умолчанию всем новым объектам этого класса присваивается значение 0. Все просто:u = Visitor() u.hits = 1 # ... hitsCount = u.hits
Работа с такими полями абсолютно прозрачна — как правило, вы используете их так же, как и объекты базового, целочисленного типа.
-
lastVisit
— подобно предыдущему,db.DateTimeProperty
инкапсулирует встроенный тип данных, только на этот раз этоdatetime.datetime
. Разницы, по большому счету, нет — точно так же работает с полем как с указанным типом данных. Поле настроено так, что обновлять вручную его не нужно — каждый раз, когда запись сохраняется, значение поля устанавливается вnow()
(в данном случае это разумно). db.UserProperty user
— самое интересное из использованых здесь. Оно инкапсулирует GAE класс users.User — не надо хранить емейл пользователя, не надо хранить уникальный ID на случай, если email поменяется — это все там. И естественно, это именно тот класс, объект которого вы получите сделавusers.get_current_user()
. В настройках поля указано, что каждый раз, когда объект будет создаваться, значение этого поля будет устанавливаться согласно текущему пользователю.
hits
) и сохраняем его в Datastore: u = Visitor() u.hits = 17 u.put()
Этого достаточно, чтобы объект был сохранен и доступен позже как часть entity
Visitor
. Про то, как искать объекты по значению определенного поля, я расскажу чуть-чуть попозже — в следующей части статьи. Исходники нашего тестового приложения постепенно обретают свое пристанище здесь и будут выкладываться по мере написания.Это была вторая часть из цикла статей про AppEngine. В следующих частях мы доберемся до вкусного — собственно написание контроллера и представления. Жду ваших комментариев, предложений и вопросов.
P.S. посоветуйте пожалуйста хороший syntax highlighter для Питона, который будет нормально работать с Хабром? tohtml.com которым я всегда пользовался генерирует нечто несовместимое с Парсером.
Update: Третья часть — habrahabr.ru/blogs/gae/81933