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

LXF117:google

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(викификация, оформление,)
 
(Викификация, оформление)
 
Строка 99: Строка 99:
  
 
Теперь можно добавить в CSS-файл какой-нибудь стиль – сделайте это сами.
 
Теперь можно добавить в CSS-файл какой-нибудь стиль – сделайте это сами.
 +
 +
====Сохранение моделей====
 +
 +
Масштабирование баз данных – сложная задача, но Google нашел несколько умных способов ее решения, применив новый подход к традиционным реляционным БД.
 +
 +
''BigTable'' от Google – сердце системы хранения данных ''App Engine''. Это означает, что можно создавать приложения, способные масштабироваться до миллионов пользователей и страниц. ''BigTable'' – это распределенная система хранения, созданная для управления «петабайтами данных на тысячах стандартных серверов» (http://labs.google.com/papers/bigtable.html), но начать работать с ней в ''App Engine'' очень просто. Все начинается с моделей, создание которых требует несколько строчек кода. Модели в ''App Engine'' являются классами-расширениями '''db.Model'''. Их свойства аналогичны свойствам полей в таблицах обычных баз данных. Вот пример простой модели:
 +
 +
<source lang=python>
 +
class MyNote(db.Model):
 +
  thenote = db.StringProperty(multiline=True)
 +
  date = db.DateTimeProperty(auto_now_add=True)
 +
</source>
 +
 +
В свойство '''date''' автоматически записывается текущее время благодаря методу '''auto_now_add''', свойство '''thenote''' – просто строка. Типы параметров включают логический ('''boolean'''), целые числа ('''integer'''), числа с плавающей точкой ('''float'''), двоичные данные ('''blob'''), почтовые сообщения ('''emails''') и другие.
 +
 +
Подготовка никакая не нужна – просто создайте экземпляр класса, установите его свойства и вызовите метод '''put()''':
 +
 +
<source lang=python>
 +
note = MyNote()
 +
note.thenote = ”Just a quick note”
 +
note.put()
 +
</source>
 +
 +
В нашем примере мы начнем с создания модели для хранения комментариев и назовем ее '''Comment''':
 +
<source lang=python>
 +
class Comment(db.Model):
 +
  content = db.StringProperty(multiline=True)
 +
  date = db.DateTimeProperty(auto_now_add=True)
 +
  author = db.UserProperty()
 +
</source>
 +
 +
{{Врезка|Заголовок=Ведение журнала|Содержание=Сделайте ведение журнала своей привычкой – добавьте '''‘import logging’''' в начало приложения и записывайте сообщения в журнал:
 +
 +
logging.info(”Something’s happening...”)
 +
 +
Файлы журналов можно просмотреть через панель инструментов – зайдите в пункт Logs и вникните в каждую подробность.|Ширина=200px}}
 +
 +
Теперь добавим в приложение немного данных, просмотрим их и установим им несколько интересных свойств. Чтобы добавить несколько комментариев, нужно создать форму, сохранить данные и затем отобразить их. Начнем с добавления формы в файл '''index.html''':
 +
<source lang=xml>
 +
<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>
 +
</source>
 +
 +
Затем добавим метод '''post()''' в контроллер.
 +
 +
<source lang=python>
 +
def post(self):
 +
  c = Comment()
 +
  c.content = self.request.get(‘comment’)
 +
  c.author = users.get_current_user()
 +
  c.put()
 +
  self.redirect(‘/’)
 +
</source>
 +
 +
Для извлечения данных из хранилища используется ''GQL'', и по большей части он похож на ''SQL''.
 +
Вам нужно заменить содержимое метода '''get()''' вызовом метода ''GQL'' класса '''Comment''', который
 +
затем передать в шаблон:
 +
<source lang=python>
 +
comments = Comment.gql(“ORDER BY date DESC“)
 +
template_vars =
 +
  { ‘comments’: comments
 +
}
 +
self.response.out.write(template.render(‘index.html’,template_vars))
 +
</source>
 +
 +
Наконец, можно пройтись по комментариям и отобразить их:
 +
<source lang=xml>
 +
{% for comment in comments %}
 +
<p>{{ comment.content }}</p>
 +
{% endfor %}
 +
</source>
 +
 +
{{Врезка|Заголовок=Скорая помощь|Содержание=Через ''Google Data Services'' можно получить данные Google для своих приложений. Начните с установки модуля '''gdata''' в каталог вашего приложения по инструкциям
 +
на http://code.google.com/appengine/docs/usinggdataservi-ces.html и затем импортируйте его командой ''import gdata''. | Ширина=200px}}
 +
 +
Для ясности и простоты добавления нового функционала переместите строку с обработкой комментариев в другой файл. Замените вторую строку из последнего примера на '''{ % include ‘comment.html’ %}'''
 +
и создайте файл '''comment.html''' со следующим содержимым:
 +
 +
<source lang=xml>
 +
<div class=“comment row1”>
 +
<p><strong�Posted on
 +
  {{ comment.date }}</strong><br /> {{ comment.content }} </p>
 +
</div>
 +
</source>
 +
 +
===Использование пользователей===
 +
 +
''App Engine'' позволяет аутентифицировать пользователей по существующим учетным записям Google, и вашим посетителям нет нужды регистрироваться заново ради очередного web-приложения. Для всего этого используется пакет '''users''':
 +
 +
<source lang=python>
 +
from google.appengine.api import users
 +
</source>
 +
 +
Теперь можно получить доступ к имени пользователя и его email-адресу с помощью функции '''users.get_current_user()'''. Если пользователь еще не вошел в систему, можно перенаправить его
 +
на форму входа:
 +
<source lang=python>
 +
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”))
 +
</source>
 +
 +
Параметр '''/home''' – это URL, на который вы направляете пользователя после входа в систему.
 +
 +
В приложении обработки комментариев можно заставить пользователей регистрироваться, прежде чем начинать что-либо писать; перенаправим их на страницу входа:
 +
<source lang=python>
 +
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)
 +
</source>
 +
 +
Обновите приложение в браузере, чтобы убедиться, что аутентификация работает.
 +
 +
Теперь, когда пользователи вошли в систему, сохраняйте авторов всех комментариев, добавив следующую строку в метод '''post()''' перед командой '''c.put()''':
 +
 +
c.author = users.get_current_user()
 +
 +
Чтобы вывести имя и e-mail автора комментария, добавьте следующие строки в файл '''comment.html''':
 +
 +
<source lang=xml>
 +
<p><b>Posted by: <b>
 +
{% if comment.author.nickname %}
 +
  {{ comment.author.nickname }} ({{ comment.author.email }})
 +
{% else %}
 +
  Anonymous
 +
{% endif %}
 +
on {{ comment.date }}
 +
</p>
 +
</source>
 +
 +
====Связанные сущности====
 +
 +
Отношения между сущностями задаются внутри модели с помощью метода '''ReferenceProperty''', который ссылается на другую модель, или '''SelfReferenceProperty''', который ссылается на текущую. Связать одну модель с другой можно примерно так:
 +
 +
related_thing = db.ReferenceProperty(OtherThing)
 +
 +
Если вы хотите, чтобы пользователи могли отвечать на сообщения, оставленные на доске объявлений, у каждого комментария должен быть родитель '''_parent_''', которого мы назовем '''in_reply_to'''. Объявите это свойство, добавив в модель �omment следующую строку:
 +
 +
in_reply_to = db.SelfReferenceProperty()
 +
 +
Теперь можно добавить форму для каждого существующего комментария:
 +
 +
<source lang=xml>
 +
<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>
 +
</source>
 +
 +
…а затем изменить метод '''post()''', чтобы сохранить его:
 +
 +
<source lang=python>
 +
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
 +
</source>
 +
 +
Значение '''‘parent’''' из HTML-формы передается в метод '''post()'''. Затем для поиска объекта в хранилище данных используется метод '''db.Key()'''. Если посмотреть исходный код HTML, то вы увидите,
 +
что ключи – это длинные строки, а не целые числа.
 +
 +
При попытке ответить на комментарий легко заметить, что ответы появляются внизу страницы, поэтому следующий шаг – это структурировать комментарии иерархически. Вам понадобится обновить ''GQL'', добавить файл '''comment.html''' и добавить метод в модель '''Comment'''. Назовем его '''get_replies''':
 +
 +
<source lang=python>
 +
def get_replies(self):
 +
  comments = Comment.gql(“where in_reply_to =:1 ORDER BY date DESC LIMIT 10”, self)
 +
  return comments
 +
</source>
 +
 +
{{Врезка|Заголовок=Индексы|Содержание=Как и в любом приложении, работающем с базой данных, при увеличении объемов информации нужно добавить индексы. Для этого пригодится файл '''index.yaml''', который будет создан за нас. Индексы требуются при сортировке, фильтрации по группам сущностей
 +
и более сложных запросах. Начните отсюда: http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html.|Ширина=200px}}
 +
 +
Этот код возвращает все комментарии, являющиеся ответами на комментарий '''self'''. Комментариями верхнего уровня должны быть те, у которых поле '''in_reply_to''' не заполнено. Поэтому мы изменим ''GQL'' в методе '''get()''', воспользовавшись константой ''Python'' '''None''':
 +
 +
comments = Comment.gql(“WHERE in_reply_to =:1 ORDER BY date DESC“, None)
 +
 +
Если обновить страницу сейчас, вы увидите, что отображаются только комментарии верхнего уровня. Последний шаг – сделать '''comment.html''' иерархическим:
 +
<source lang=xml>
 +
<p>
 +
  {% for comment in comment.get_replies %}
 +
    {% include ‘comment.html’ %}
 +
  {% endfor %} </p>
 +
</source>
 +
 +
Обновите страницу, чтобы увидеть вложенные комментарии. Кликните по ссылке '''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'''

Текущая версия на 23:51, 19 февраля 2010

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

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