Фотогалерея на Django с использованием Google Picasa в качестве хостинга



Привет Хабралюди.

В этом посте хочу поделиться опытом организации фотогалереи на своем сайте с использованием Google Picasa как хранилища фотографий. Подобное решение для php уже было на Хабре, здесь же приводится реализация на Django. Кому интересна эта тема, добро пожаловать.



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

Для тех, кто дальше читать не хочет, сразу готовый результат.

Введение


Готовых решений галерей для Django великое множество, стоит к примеру заглянуть сюда. При этом фотографии, миниатюры, созданные кэши хранятся на нашем сервере, предлагаемый же способ использует сервера Гугла для всей черной работы, тем самым снижая нагрузки и экономя место на нашем. Сразу оговорюсь что никаких нагрузочных и других тестов не проводил, что позволяет заминусовать меня в хлам за голословные слова о повышении производительности и т.д.

Google Picasa как и многие продукты Гугла имеет свой API, подробно с которым можно ознакомиться в документации.
Что нам понадобится:


Описание приложения


Перейдем к описанию нашего приложения picasagallery. Основой приложения будут два представления(view), и шаблоны к ним.
Для начала определим две функции, возвращающие список альбомов и фотографий в альбоме соответственно:

from gdata.photos.service import PhotosService

def get_albums():
    pws = PhotosService()
    uf = pws.GetUserFeed(user = settings.PICASAGALLERY_USER)
    feed = '{uri}&thumbsize={thumbsize}'.format(
        uri = uf.GetAlbumsUri(), thumbsize = ALBUM_THUMBSIZE
    )
    print feed
    return  pws.GetFeed(feed).entry

def get_photos(album):
    feed = '{uri}&imgmax={imgmax}&thumbsize={thumbsize}'.format(
        uri = album.GetPhotosUri(), imgmax = PHOTO_IMGMAXSIZE, thumbsize = PHOTO_THUMBSIZE
    )
    return PhotosService().GetFeed(feed).entry


Тут все очень просто(как впрочем и в дальнейшем). Наверное разве что стоит прокомментировать передаваемые в запрос параметры:
  • user — имя пользователя в Picasa;
  • thumbsize — размер миниатюр запрашиваемых объектов, т.е. альбомов и фотографий в данном случае. Доступные размеры миниатюр можно узнать в документации. Миниатюры могут быть обрезанными(cropped), т.е. квадратными, и необрезанными(uncropped), например '160c' или '128u'. Также можно указать несколько значений через запятую;
  • imgmax — максимальный размер фотографии (спасибо кэпу), т.е. это размер изображений, возвращаемых нашей функцией get_photos().

Для удобства поместим эти параметры в settings.py:
# Picasagallery settings
PICASAGALLERY_USER = 'your_email'
PICASAGALLERY_PHOTO_THUMBSIZE = '128'
PICASAGALLERY_PHOTO_IMGMAXSIZE = '1024'
PICASAGALLERY_ALBUM_THUMBSIZE = '160c'


При помощи django shell можно поэкспериментировать с этим хозяйством:

>>> from picasagallery.utils import get_albums, get_photos
>>> my_first_album = get_albums()[0]
>>> print my_first_album.title.text # имя альбома
>>> print my_first_album.media.thumbnail[0].url # url первой миниатюры альбома
https://lh3.googleusercontent.com/-aWPQC60j9zQ/TwCXlTD6CtE/AAAAAAAAAJk/E90Hu9OPiyg/s160-c/FotoLife.jpg
>>> my_first_photo = get_photos(my_first_album)[0]
>>> print my_first_photo.media.thumbnail[0].url # url первой фоты в альбоме
https://lh3.googleusercontent.com/-3Hb7VwUTBNg/TwCXlXqdAQI/AAAAAAAAAH8/v8ecBJtjV6k/s128/261799.jpg
>>> print my_first_photo.content.src # url изображения первой фоты, размер изображения определяется переданным параметром imgmax


Список my_first_album.media.thumbnail содержит миниатюры фотографий, его размер равен количеству переданных через запятую значений в параметре thumbsize.

Миниатюра альбома — это миниатюра его главной фотографии, по умолчанию это первая загруженная в альбом фотография, но это можно изменить в настройках альбома на сайте Google Picasa. Возможность изменения главной фотографии через API не нашел, если кто знает, подскажите в комментариях.

Представления



Определим два представления для страниц галереи и альбома соответственно.

from django.shortcuts import render
from django.http import Http404

from picasagallery.utils import get_albums, get_photos

def gallery(request):
    albums = get_albums()
    return render(request, 'picasagallery/gallery.html', {'albums': albums})

def album_list(request, album_id):
    for album in get_albums():
        if album.gphoto_id.text == album_id:
            photos = get_photos(album)
            return render(request, 'picasagallery/album.html', {'photos': photos})
    raise Http404()


Шаблоны


Шаблон для галереи:
{% extends 'base.html' %}
{% load extras %}
{% load i18n %}

{% block head %}
    <link rel="stylesheet" href="{{ STATIC_URL }}picasagallery/css/base.css"
          type="text/css" media="screen" charset="utf-8" />
{% endblock %}

{% block content %}
    {% for album in albums %}
        <div class='album'>
            <div class='album-head'>
                <a href="{% url picasagallery.views.album_list album.GetAlbumId %}" >
                    <img class="album-preview" src="{%  thumbnail_url album %}">
                </a>
            </div>
            <div class="album-name">
                <a href="{% url picasagallery.views.album_list album.GetAlbumId %}">{{  album.title.text }}</a>
            </div>
        </div>
    {% endfor %}
	<p>
        <a href="/media/picasa_gdata.zip">{% trans 'Download source' %}</a>
    </p>
{%  endblock %}


Шаблон для альбома:
{% extends 'base.html' %}
{% load extras %}
{% load i18n %}

{% block head %}
    {% include 'picasagallery/pphoto.html' %}
    <link rel="stylesheet" href="{{ STATIC_URL }}picasagallery/css/base.css"
          type="text/css" media="screen" charset="utf-8" />
{% endblock %}

{% block content %}
    <a href='{% url picasagallery.views.gallery %}' >{% trans "Back to gallery" %}</a>
    <p>{% trans "Album:" %} {{ album.title.text }}</p>
    <div class='gallery'>
        {% for photo in photos %}
            <div class='image-preview-div'>
                <a class='image-preview-link' style='{% thumbnail_style photo %}' 
                        rel='gallery-image[pp_gal]' href='{{ photo.content.src }}'>
                    <img class='image-preview-img' style='{% thumbnail_style photo %}'
                            src='{%  thumbnail_url photo %}'>
                </a>
            </div>
        {% endfor %}
        <p>
            <a href='{{ album.GetHtmlLink.href }}' target='_blank'>{% trans "Show in Google Picasa" %}</a>
        </p>
    </div>
{% endblock %}


Для получения url миниатюр альбомов и фотографий эти шаблоны используют тег thumbnail_url, возвращающий url первой миниатюры из списка. Также используется тег thumbnail_style, возвращающий строку вида 'width: 48; height: 48;' для использования в качестве аргумента для
<img ... />

Эти теги определим в файле extras.py папки templatetags:

from django.template import Library

register = Library()

def get_thumbnail(obj):
    return obj.media.thumbnail[0]

@register.simple_tag
def thumbnail_url(obj):
    return get_thumbnail(obj).url

@register.simple_tag
def thumbnail_style(obj):
    thumb = get_thumbnail(obj)
    return 'width: %spx; height: %spx;' % (thumb.width, thumb.height)


Шаблон для альбома содержит код для подключеня prettyPhoto:
{% include 'picasagallery/pphoto.html' %}

На этом моменте подробно останавливаться не буду, кому интересно, можно заглянуть в исходники.

Ну и в заключение, что из этого получилось, и тоже самое тут.

Спасибо за внимание.
Метки:
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 11
  • 0
    Попробуем использовать для проведения пользовательского конкурса с фотографиями, трафик сохранить. Пикаса не ставит ограничений по частоте запросов?

    PS — пользуюясь случаем, ищем django программистов — junior и seniour, пишите на andrew.novoselsky@gmail.com
    • –1
      В Питере
      • +4
        Ждал минусов.
        Если бы хх, суперджоб, itmozg, django-russian, softwaremaniacs, python.su и… давали бы результат при поиске питонистов, не стал бы без нужды тревожить.
        • 0
          дефицит реально наблюдается…
    • +4
      Небольшая просьба: старайтесь не использовать locals(), даже в примерах — кому-нибудь может это понравится.

      # album.GetPhotosUri() + '&imgmax=%s&thumbsize=%s' % (PHOTO_IMGMAXSIZE, PHOTO_THUMBSIZE)
      '%s&imgmax=%s&thumbsize=%s' % (album.GetPhotosUri(), PHOTO_IMGMAXSIZE, PHOTO_THUMBSIZE)
      

      Тут можно обойтись без конкатенции, коли все равно формируете строку.

      PhotosService().GetFeed(album.GetPhotosUri() +
                             '&imgmax=%s&thumbsize=%s' % (PHOTO_IMGMAXSIZE, PHOTO_THUMBSIZE)).entry
      

      Если разбить на строки будет лучше выглядеть, да и дебажить станет удобнее.

      if(album.gphoto_id.text == album_id):
      

      Тут скобочки не обязательны.

      return render_to_response
      

      Начиная с версии 1.3 можно использовать шорткат render — код станет чище и понятнее.

      # style = 'width: %s; height: %s;'
      # thumbnail = get_thumbnail(obj)
      # return style % ('%spx' % thumbnail.width, '%spx' % thumbnail.height)
      thumb = get_thumbnail(obj)
      return 'width: %spx; height: %spx;' % (thumb.width, thumb.height)
      

      Тут немного лишнего.

      Еще немного смущает как вы смело обращаетесь к артибутам, элементам по индексам, получаете экземпляры классов и тут же в бой. Возможно это излишняя осторожность, но я бы понапихал проверок и «затычек», еще ни разу об этом не пожалел.
      Надеюсь ничего не напутал :)
      • 0
        Спасибо за замечания. Поправил
        • 0
          спасибо за render ))
        • +2
          Для таких вещей
          > album.GetPhotosUri() + '&imgmax=%s&thumbsize=%s' % (PHOTO_IMGMAXSIZE, PHOTO_THUMBSIZE)
          создан str.format()
          • +1
            Если честно, то я не вижу смысла делать это через django. Можно же на стороне клиента например так: oss.oetiker.ch/jquery/jquery.EmbedPicasaGallery.html
            Я понимаю еще можно применить django чтобы еще и через админку django загружать или редактировать фотографии на picasa. А так только в качестве примера использования gdata.
            Странно все оформлено в архиве — лучше просто requirements.txt создать с зависимостями а не класть туда папку gdata(иначе увидев эту папку возникают мысли что gdata у вас измененная и другие версии совсем не совместимы).
            • +1
              поставьте кнопочку Мне нравится возле «Для тех, кто дальше читать не хочет, сразу готовый результат.»
              • 0
                Очень круто получилось. Спасибо.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.