Pull to refresh

Google AppEngine с самого начала: Модель

Reading time 4 min
Views 6.3K
В предыдущей статье мы выяснили, что такое Google AppEngine, что с ним можно делать, и создали самое простое и примитивное приложение для GAE — helloworld с минимальной поддержкой аутентификации пользователей. Попробуем расширить это приложение, рассмотрев, попутно, возможности Google AppEngine.

Структура и архитектура


Наше предыдущее приложение было предельно простым, и, как таковое, ни в какой архитектуре не нуждалось. Теперь мы ставим перед собой более сложную и более реальную задачу — соответственно, нам следует подумать о том, что будет, когда приложение начнет расти. Разумеется, наша задача выдумана и для нее никакой архитектуры тоже не требуется, но для примера попробуем все сделать «по науке».


gaehabr

Вот так будет выглядеть наше приложение с точки зрения структуры. Голубые прямоугольники обозначают, что эти страницы доступны и видны для всех. Желтый означает, что его содержимое может меняться, если активна пользовательская сессия. Оранжевые целиком закрыты от внешнего мира и на них можно попасть только если перед этим залогиниться.

Две страницы на картинке выше будут предоставлены нам GAE — а именно, «Login with Google» и «Logout». Все, что требуется от нас это:
  1. Написать главную страницу, которая будет давать какую-то вменяемую информацию и предлагать логиниться
  2. Написать вариант главной страницы для пользователей, которые уже залогинились
  3. Написать login-handler, который будет регистрировать факт логина и перенаправлять пользователя на главную страницу
  4. Написать страницу статистики, которая будет показывать, сколько раз пользователь логинился в систему и когда был последний раз.
C чего же начать? Как обычно — с самого начала.

Модель


В нашем приложении модель хранения данных будет совсем несложной, однако, как мне кажется, этого будет вполне достаточно чтобы проиллюстрировать возможности 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
Tags:
Hubs:
+22
Comments 11
Comments Comments 11

Articles