Журнал LinuxFormat - перейти на главную

LXF117:google

Материал из Linuxformat
Версия от 23:51, 19 февраля 2010; Crazy Rebel (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск
Hardcore Linux Проверь себя на крутом проекте для продвинутых пользователей

Содержание

GAE: Создаем web-приложение

С Google App Engine легко создавать масштабируемые приложения, не вникая в детали масштабирования. Дэн Фрост закинет программу в облака.

Google App Engine – платформа для разработки приложений в инфраструктуре Google. Как и другие масштабируемые платформы, она дает возможность разместить приложение на «облаке» (LXF108), не тратясь на содержание собственной серверной «фермы».

В отличие от других решений по облачным вычислениям, Google App Engine применяется только для создания web-приложений. Вы можете управлять web-страницами, хранить информацию и взаимодействовать с внешними web-серверами, но не имеете доступа к файлам, дискам и базам данных, как было бы в обычной среде.

Это может заставить вас изменить структуру приложения, но зато в вашем распоряжении будут очень мощные инструменты. Google App Engine поддерживает учетные записи Google, обработку изображений, огромные хранилища данных и взаимодействие с некоторыми службами Google посредством библиотеки Google Data Library.

Пока поддерживаются только приложения на языке Python. Если это не ваш любимый язык программирования – «следите за рекламой»: в будущем появятся и другие.

Работа с App Engine

Сначала поработаем локально, пользуясь сервером разработчика dev_appserver.py, который имитирует реальную среду. Предоставляемая SDK, она включает работающий сервер, хранилище данных, псевдоучетные записи пользователей и все необходимое для создания приложения. Когда ваш новый шедевр Web 2.0 будет готов, разверните его на серверах Google с помощью скрипта appcfg.py, который загрузит программу на вашу учетную запись в App Engine (создайте ее на сайте http://appengine.google.com).

Пора установить среду разработки. Сначала позаботьтесь о наличии установленного Python 2.5, после чего можно загрузить App Engine для вашей ОС с сайта http://code.google.com/appengine/downloads.html. В Linux, распакуйте архив и добавьте App Engine в переменную окружения $PATH:

export PATH=$PATH:/path/to/google_appengine/

Проверьте, что это работает, набрав dev_appserver.py в командной строке – вы должны увидеть обычную страницу справки. Затем создайте каталог для своего приложения:

mkdir ~/myapp/

Теперь создайте файл ключа для App Engine: app.yaml. Он указывает App Engine, в каком каталоге находится приложение и как обращаться с каждым его файлом. Заполните ~/myapp/app.yaml таким содержимым:

application: mydemoapp
version: 1
runtime: python
api_version: 1
handlers:
 - url: /.*
   script: main.py

Этот файл сообщает App Engine, что имя приложения – mydemoapp, а все запросы должны передаваться скрипту main.py. Для обработки любого URL-адреса можно задать любой скрипт и даже применить шаблоны для использования различных файлов:

url: /browse/(.*?)/
script: /listings/\1.py

Приведенная выше конфигурация передает все в скрипт main.py, поэтому создайте этот файл и добавьте в него вывод традиционного сообщения:

print “Hello, World”

Наше скромное приложение готово. Запустите сервер с помощью скрипта dev_appserver.py и откройте в браузере адрес http://localhost:8080.

dev_appserver.py ~/myapp/

В App Engine допустимо большинство стандартных выражений Python; исключения в основном касаются доступа к файловой системе. Попробуйте добавить методы и классы, создайте модуль, и вы увидите, что среда вам знакома.

Применение webapp

В состав App Engine входит MV-каркас webapp, позволяющий создавать хорошо структурированные приложения всего несколькими строками кода. Первая строка импортирует его, затем создается обработчик – это простой класс, унаследованный от webapp.RequestHandler:

 from google.appengine.ext import webapp
 class ExampleApp(webapp.RequestHandler):
   def get(self):
     self.response.out.write(‘Hello, well structured world’)

В обработчике есть два важных метода – get() и post(). Первый вызывается для всех запросов HTTP GET, второй – для всех запросов HTTP POST. Следом за самим обработчиком запросов нужно зарегистрировать его в webapp и вызвать метод main() webapp:

 application = webapp.WSGIApplication(
   [(‘/’, ExampleApp)],
   debug=True)
   def main():
     run_wsgi_app(application)
     if __name__ == “__main__”:
       main()

Снова откройте в браузере URL приложения, и вы увидите весьма невыразительную строку текста. Давайте улучшим ее, переместив сообщение в шаблон – создайте файл index.html:

 <html>
 <head><title>Hi there!</title></head>
 <body><h1>Hello from the template</h1></body>
 </html>

Затем подключите шаблон, изменив метод get():

 def get(self):
   template_vars = {}
   self.response.out.write(template.render(path, template_vars))

Если вы хотите включить таблицы стилей, JavaScript, изображения или любые другие статические файлы, нужно предупредить об этом app.yaml. Добавьте в него следующие строки перед обработчиком url: /.*:

- url: /style
  static_dir: style

Затем создайте каталог style и файл app.css и включите их в index.html:

 <link rel=“stylesheet” href=”/style/app.css” type=“text/css”>

Теперь можно добавить в CSS-файл какой-нибудь стиль – сделайте это сами.

Сохранение моделей

Масштабирование баз данных – сложная задача, но Google нашел несколько умных способов ее решения, применив новый подход к традиционным реляционным БД.

BigTable от Google – сердце системы хранения данных App Engine. Это означает, что можно создавать приложения, способные масштабироваться до миллионов пользователей и страниц. BigTable – это распределенная система хранения, созданная для управления «петабайтами данных на тысячах стандартных серверов» (http://labs.google.com/papers/bigtable.html), но начать работать с ней в App Engine очень просто. Все начинается с моделей, создание которых требует несколько строчек кода. Модели в App Engine являются классами-расширениями db.Model. Их свойства аналогичны свойствам полей в таблицах обычных баз данных. Вот пример простой модели:

 class MyNote(db.Model):
   thenote = db.StringProperty(multiline=True)
   date = db.DateTimeProperty(auto_now_add=True)

В свойство date автоматически записывается текущее время благодаря методу auto_now_add, свойство thenote – просто строка. Типы параметров включают логический (boolean), целые числа (integer), числа с плавающей точкой (float), двоичные данные (blob), почтовые сообщения (emails) и другие.

Подготовка никакая не нужна – просто создайте экземпляр класса, установите его свойства и вызовите метод put():

 note = MyNote()
 note.thenote = ”Just a quick note”
 note.put()

В нашем примере мы начнем с создания модели для хранения комментариев и назовем ее Comment:

 class Comment(db.Model):
   content = db.StringProperty(multiline=True)
   date = db.DateTimeProperty(auto_now_add=True)
   author = db.UserProperty()


Теперь добавим в приложение немного данных, просмотрим их и установим им несколько интересных свойств. Чтобы добавить несколько комментариев, нужно создать форму, сохранить данные и затем отобразить их. Начнем с добавления формы в файл index.html:

 <form action=”/” method=”post” accept-charset=”utf-8”>
    <input type=”hidden” name=”parent” value=”{{ comment.key }}/>
    <textarea name=”comment”></textarea>
    <input type=”submit” value=”Add”></div>
 </form>

Затем добавим метод post() в контроллер.

 def post(self):
  c = Comment()
  c.content = self.request.get(‘comment’)
  c.author = users.get_current_user()
  c.put()
  self.redirect(‘/’)

Для извлечения данных из хранилища используется GQL, и по большей части он похож на SQL. Вам нужно заменить содержимое метода get() вызовом метода GQL класса Comment, который затем передать в шаблон:

 comments = Comment.gql(“ORDER BY date DESC“)
 template_vars =
   { ‘comments’: comments
 }
 self.response.out.write(template.render(‘index.html’,template_vars))

Наконец, можно пройтись по комментариям и отобразить их:

 {% for comment in comments %}
 <p>{{ comment.content }}</p>
 {% endfor %}


Для ясности и простоты добавления нового функционала переместите строку с обработкой комментариев в другой файл. Замените вторую строку из последнего примера на { % include ‘comment.html’ %} и создайте файл comment.html со следующим содержимым:

 
 <div class=“comment row1”>
 <p><strong�Posted on
   {{ comment.date }}</strong><br /> {{ comment.content }} </p>
 </div>

Использование пользователей

App Engine позволяет аутентифицировать пользователей по существующим учетным записям Google, и вашим посетителям нет нужды регистрироваться заново ради очередного web-приложения. Для всего этого используется пакет users:

 from google.appengine.api import users

Теперь можно получить доступ к имени пользователя и его email-адресу с помощью функции users.get_current_user(). Если пользователь еще не вошел в систему, можно перенаправить его на форму входа:

 if users.get_current_user():
   user = get_current_user()
   self.response.out.write(“You are logged in as: “ + user. nickname())
   else: self.redirect(users.create_login_url(“/home”))

Параметр /home – это URL, на который вы направляете пользователя после входа в систему.

В приложении обработки комментариев можно заставить пользователей регистрироваться, прежде чем начинать что-либо писать; перенаправим их на страницу входа:

 if users.get_current_user():
   comments = �omment.gql(“WHERE in_reply_to =:1 ORDER BY date DESC“, None)
   template_vars = {
     ‘comments’: comments
   }
   self.response.out.write(template.render(‘index.html’, template_vars))
 else:
   message = (<a href=’ %s’>Please login</a>.” %users. create_login_url(“/rels”))
   self.response.out.write(message)

Обновите приложение в браузере, чтобы убедиться, что аутентификация работает.

Теперь, когда пользователи вошли в систему, сохраняйте авторов всех комментариев, добавив следующую строку в метод post() перед командой c.put():

c.author = users.get_current_user()

Чтобы вывести имя и e-mail автора комментария, добавьте следующие строки в файл comment.html:

 <p><b>Posted by: <b>
 {% if comment.author.nickname %}
   {{ comment.author.nickname }} ({{ comment.author.email }})
 {% else %}
   Anonymous
 {% endif %}
 on {{ comment.date }}
 </p>

Связанные сущности

Отношения между сущностями задаются внутри модели с помощью метода ReferenceProperty, который ссылается на другую модель, или SelfReferenceProperty, который ссылается на текущую. Связать одну модель с другой можно примерно так:

related_thing = db.ReferenceProperty(OtherThing)

Если вы хотите, чтобы пользователи могли отвечать на сообщения, оставленные на доске объявлений, у каждого комментария должен быть родитель _parent_, которого мы назовем in_reply_to. Объявите это свойство, добавив в модель �omment следующую строку:

in_reply_to = db.SelfReferenceProperty()

Теперь можно добавить форму для каждого существующего комментария:

 <div>
   <div id=“comment-{{ comment.key }}style=“display:none;”>
     <form action=“/rels” method=“post” acceptcharset=“utf-8”>
       <input type=“hidden” name=“parent” value=”{{ comment.key }}/>
       <textarea name=“comment” rows=“7” cols=”30”></textarea>
       <input type=“submit” value=“Add”>
     </form>
   </div>
   <a href=“javascript:document.getElementById(‘comment-{{comment.key}}).style.display=’block’;”>Add comment</a>
 </div>

…а затем изменить метод post(), чтобы сохранить его:

 if self.request.get(‘parent’):
   key_name = self.request.get(‘parent’)
   p = db.get(db.Key(key_name))
   c.in_reply_to = p
 else:
   c.in_reply_to = None

Значение ‘parent’ из HTML-формы передается в метод post(). Затем для поиска объекта в хранилище данных используется метод db.Key(). Если посмотреть исходный код HTML, то вы увидите, что ключи – это длинные строки, а не целые числа.

При попытке ответить на комментарий легко заметить, что ответы появляются внизу страницы, поэтому следующий шаг – это структурировать комментарии иерархически. Вам понадобится обновить GQL, добавить файл comment.html и добавить метод в модель Comment. Назовем его get_replies:

 def get_replies(self):
   comments = Comment.gql(“where in_reply_to =:1 ORDER BY date DESC LIMIT 10”, self)
   return comments


Этот код возвращает все комментарии, являющиеся ответами на комментарий self. Комментариями верхнего уровня должны быть те, у которых поле in_reply_to не заполнено. Поэтому мы изменим GQL в методе get(), воспользовавшись константой Python None:

comments = Comment.gql(“WHERE in_reply_to =:1 ORDER BY date DESC“, None)

Если обновить страницу сейчас, вы увидите, что отображаются только комментарии верхнего уровня. Последний шаг – сделать comment.html иерархическим:

 <p>
   {% for comment in comment.get_replies %}
     {% include ‘comment.html’ %}
   {% endfor %} </p>

Обновите страницу, чтобы увидеть вложенные комментарии. Кликните по ссылке Add Comment, чтобы ответить на любой из комментариев.

Выгрузка вашего приложения

Для выгрузки используется еще одна утилита, appcfg.py. Нужно лишь указать опции команды update и местоположение приложения.

~/appEngineProject/ $ appcfg.py update helloworld/
Loaded authentication cookies from /Users/you/.appcfg_cookies
Scanning files on local disk.
Initiating update.
Email: some_user@gmail.com
Password for some_user@gmail.com:
Saving authentication cookies to /Users/you/.appcfg_cookies
Cloning 21 application files.
Uploading 5 files.
Closing update.
Uploading index definitions

У вас спросят параметры учетной записи Google, после чего приложение загрузится на серверы Google. LXF

Персональные инструменты
купить
подписаться
Яндекс.Метрика