• Официальный сайт SDK
  • Сайт с примерами кода

Работа с динамическими изображениями в Google App Engine

Остин Чау, Программа Google для разработчиков
Апрель 2008

Введение

Одно изображение стоит тысячи слов. И это является правдой, так как при взаимодействии с пользователем для сегодняшних web-приложений изображения играют большую роль. Платформа Google App Engine позволяет доступным способом оперировать изображениями и помещать их в свое хранилище. Предлагаемый интерфейс для языка Python содержит функции работы с объектами данных и построения запросов через язык GQL, собственной разработки компании Google. В этой небольшой статье я покажу, как можно использовать интерфейс Datastore API для хранения и отображения картинок, используя для примеров код приложения Movie Review.

Сохраняем картинки в хранилище

Для начала мы хотим представить данные о каждом фильме в нашем приложении как объект хранилища. Это проще всего реализовать, определив класс модели для фильма. В классе Movie, который указан по тексту ниже, мы определяем все необходимые для описания атрибуты. Одним из них является picture, который и будет содержать двоичные данные изображения каждого фильма в формате jpeg. Для того, чтобы данные сохранялись корректно, мы должны их поместить в объект типа Blob, соответственно свойство которого будет экземпляром класса BlobProperty.

Class Movie(db.Model)
  title = db.StringProperty()
  picture = db.BlobProperty(default=None)
  ...

Теперь после того, как модель была определена, можно перейти к использованию ее для хранения объектов. Мы можем получить изображение фильма из удаленного источника (например, по ссылке с какого-нибудь сервера) и поместить его в наше приложение. Чтобы сделать это, воспользуемся интерфейсом URL Fetch API, который умеет загружать данные извне по URL типа HTTP и HTTPS. Метод urlfetch.Fetch() может быть использован для загрузки двоичного содержимого удаленного изображения. Для этого нам просто нужно будет указать URL изображения в качестве параметра.

Далее, создадим объект типа Blob, передав его конструктору загруженное содержимое (строковое представление бинарных данных), и присвоим полученный объект атрибуту picture экземпляру модели Movie. Затем при вызове метода put() все изменения будут помещены в хранилище.

movie = Movie()
...
movie.picture = db.Blob(urlfetch.Fetch(picture_url).content)
movie.put()

Загружаем и отображаем картинки

Теперь, когда объекты с данными фильма помещаются в наше хранилище, давайте рассмотрим пример создания обработчика, который будет динамически получать картинку из хранилища и выдавать ее в браузер пользователя.

Сначала для определения обработчика запроса типа GET мы создадим класс GetImage. Первое, что делает код этого обработчика - извлекает из URL запроса параметр title. Затем, он пытается через вызов функции getMovie() получить из хранилища объект Movie, заголовок которого будет совпадать с запросом пользователя.

Теперь мы имеем ссылку на объект и можем получить доступ к его атрибуту picture. Чтобы браузер пользователя корректно отобразил картинку, мы устанавливаем заголовку ответа HTTP Content-Type значение image/jpg.

class GetImage(webapp.RequestHandler):
  def get(self):
    title = self.request.get('title')
    movie = getMovie(title)
    if (movie and movie.picture):
      self.response.headers['Content-Type'] = 'image/jpg'
      self.response.out.write(movie.picture)
    else:
      self.redirect('/static/noimage.jpg')

Метод getMovie() содержит код, выполняющий поиск объекта с нужным заголовком с помощью простого GQL запроса к хранилищу.

def getMovie(title):
  result = db.GqlQuery("SELECT * FROM Movie WHERE title = :1 LIMIT 1", 
                       title).fetch(1)
  if (len(result) > 0):
    return result[0]
  else:
    return None

Для того, чтобы приложение вызывало наш обработчик при запросе пользователя начинающегося на URL '/image', мы должны добавить новый класс GetImage к существующей схеме URL. К примеру, для обработки GET-запросов мы используем фреймворк webapp:

apps_binding = []
...
apps_binding.append(('/image', GetImage))
application = webapp.WSGIApplication(apps_binding, debug=True)
wsgiref.handlers.CGIHandler().run(application)

Теперь, когда посетитель проследует по URL http://mydomain.com/image?title=matrix , браузер загрузит изображение фильма Матрица.

Полезные ссылки

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

  • Полный исходный код приложения Movie Review
  • Описание Datastore API
  • Форум разработчиков Google App Engine