Select it with the mouse and hit Enter
| на поддержку перевода |
|
|
ЯМ:41001223475816
Django поставляется со средствами высокого уровня для трансляции данных, что позволяет легко создавать потоки RSS или Atom.
RSS и Atom оба являются форматами, базирующимися на XML, которые вы можете использовать для рассылки автоматически обновляемого «содержания» для вашего сайта. Более подробно об RSS можно узнать на http://www.whatisrss.com/, об Atom — на http://www.atomenabled.org/.
Здесь и далее мы будем использовать термин «трансляция» для английской фразы «syndication feed».
Для создания любой трансляции вам понадобится только написать короткий класс на языке Python. Вы можете создавать столько трансляций, сколько требуется.
Средой высокого уровня для генерации трансляций является представление, которое по договорённости подключено к /feeds/. Django использует хвостовую часть URL (то, что идёт после /feeds/) для определения того, какую именно трансляцию следует вернуть.
Для создания трансляции, вам потребуется написать класс
Feed и указать на него в вашем файле
привязок URL (обратитесь к главам «Представления и привязки URL» и «Усовершенствованные представления и схемы URL» для подробностей).
Чтобы активировать трансляции на вашем сайте, добавьте следующее в файл привязок:
(r'^feeds/(?P<url>.*)/$',
'django.contrib.syndication.views.feed',
{'feed_dict': feeds}
),
Этот код указывает Django, что следует использовать RSS среду для обработки всех URL, которые начинаются с feeds/. (Вы можете изменить этот префикс feeds/ на любой необходимый.)
Следует отметить, что параметр feed_dict
должен быть словарём, который совпадает с сокращением для
трансляции (метка для короткого URL). Вы можете определить
этот параметр в файле привязок. Ниже дан полный пример:
from django.conf.urls.defaults import *
from myproject.feeds import LatestEntries, LatestEntriesByCategory
feeds = {
'latest': LatestEntries,
'categories': LatestEntriesByCategory,
}
urlpatterns = patterns('',
# ...
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
# ...
)
Вышеприведённый пример регистрирует две трансляции:
Трансляция, представленная LatestEntries, будет жить на feeds/latest/.
Трансляция, представленная LatestEntriesByCategory, будет жить на feeds/categories/.
Теперь надо определить сами классы
Feed.
Класс Feed является обычным классом
Python и представляет собой класс трансляции. Трансляция может
быть простой (т.е. отображающей новости сайта или последние
записи блога) или более сложной (т.е. отображающей все записи
блога в определённой категории, где категория является
переменной).
Вы должны подключать в код представления класс
django.contrib.syndication.feeds.Feed. Классы
Feed могут располагаться в любой точке
вашего кода.
Этот простой пример, взятый с http://chicagocrime.org/, описывает трансляцию, которая возвращает пять свежих новостей:
from django.contrib.syndication.feeds import Feed
from chicagocrime.models import NewsItem
class LatestEntries(Feed):
title = "Chicagocrime.org site news"
link = "/sitenews/"
description = "Updates on changes and additions to chicagocrime.org."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
Отметим важные аспекты этого кода:
Класс подключает django.contrib.syndication.feeds.Feed.
Атрибуты title, link и description соответствуют стандартным элементам RSS: <title>, <link> и <description>.
Метод items() возвращает список
объектов, которые должны быть включены в трансляцию в
виде элементов <item>. Несмотря на то, что
этот пример возвращает объекты
NewsItem с помощью API для работы
с базой данных, метод items() не
обязан возвращать экземпляры модели.
Вы «бесплатно» получаете некоторую
функциональность, используя модели Django, но метод
items() может вернуть любой тип
объекта.
Надо сделать ещё кое-что. В RSS-потоке каждый элемент <item> имеет элементы <title>, <link> и <description>. Необходимо указать среде какие именно данные следует помещать в эти элементы.
Чтобы указать содержимое для <title> и
<description>, создайте шаблоны (см. главу
«Шаблоны») с именами
feeds/latest_title.html и
feeds/latest_description.html, где
latest является сокращением, которое
указано в файле привязки для конкретной
трансляции. Следует отметить, что наличие расширения
.html обязательно.
Система RSS обрабатывает этот шаблон для каждого элемента, передавая ему две контекстные переменные:
obj: текущий объект (один из
объектов полученных от метода
items()).
site: Объект класса
django.models.core.sites.Site,
представляющий текущий сайт. Полезен для {{ site.domain }} или {{ site.name }}.
Если вы не создадите шаблон хотя бы для одного элемента, среда будет использовать шаблон {{ obj }} по умолчанию, т.е. обычное текстовое представление объекта.
Также вы можете поменять имена этих двух шаблонов,
определив атрибуты title_template и
description_template для класса
Feed.
При определении содержимого для <link> у вас
есть две опции. Для каждого элемента, возвращённого
методом items(), Django сначала
пытается выполнить его метод
get_absolute_url(). Если такого
метода нет у объекта, Django пытается вызвать метод
item_link() для класса
Feed, передавая ему один параметр
item, который является этим объектом.
Оба метода, get_absolute_url() и
item_link(), должны возвращать URL
элемента в виде обычной строки Python.
Для показанного ранее примера LatestEntries мы можем создать очень простые шаблоны:
# latest_title.html
{{ obj.title }}
#latest_description.html
{{ obj.description }}
Это всегда слишком просто ...
Сайт http://chicagocrime.org предоставляет
RSS-потоки по последним преступлениям для каждого полицейского
участка в Чикаго. Можно устать, создавая классы
Feed для каждого участка. Это нарушит
принцип DRY и приведёт к размещению данных в логике программы.
Вместо этого, среда трансляций позволяет вам создать базовые трансляции, которые возвращают элементы в зависимости от URL.
На нашем сайте трансляции для полицейских участков доступны через URL, подобные этим:
http://www.chicagocrime.org/rss/beats/0613/: возвращает данные о последних преступлениях на участке 0613.
http://www.chicagocrime.org/rss/beats/1424/: возвращает данные о последних преступлениях на участке 1424.
Здесь сокращением является beats. Среда трансляций обнаруживает хвостовую часть URL после beats — 0613 и 1424 — и предоставляет вам возможность указать ей, что означает эта дополнительная часть URL и как она влияет на транслируемые данные.
Пример должен всё прояснить. Ниже представлен код для таких трансляций:
from django.core.exceptions import ObjectDoesNotExist
class BeatFeed(Feed):
def get_object(self, bits):
# In case of "/rss/beats/0613/foo/bar/baz/", or other such
# clutter, check that bits has only one member.
if len(bits) != 1:
raise ObjectDoesNotExist
return Beat.objects.get(beat__exact=bits[0])
def title(self, obj):
return "Chicagocrime.org: Crimes for beat %s" % obj.beat
def link(self, obj):
return obj.get_absolute_url()
def description(self, obj):
return "Crimes recently reported in police beat %s" % obj.beat
def items(self, obj):
crimes = Crime.objects.filter(beat__id__exact=obj.id)
return crimes.order_by('-crime_date')[:30]
Здесь представлен базовый алгоритм среды RSS-потоков. Берём данный класс и обрабатываем URL /rss/beats/0613/:
Среда трансляций получает URL
/rss/beats/0613/ и отмечает, что
существует дополнительная часть данных в URL. Среда
отделяет эту часть по символу / и
вызывает у класса Feed метод
get_object(), передавая ему эту
часть URL.
В данном случае, такой частью будет ['0613']. Для запроса /rss/beats/0613/foo/bar/' — ['0613', 'foo', 'bar'].
Метод get_object() отвечает за
получение соответствующего участка из полученного
набора.
В данном случае, среда трансляций использует API для
работы с базой данных для получения информации по
указанному полицейскому участку. Следует отметить, что
метод get_object() должен вызывать
исключение
django.core.exceptions.ObjectDoesNotExist
в случае получения неверного параметра. Здесь не
использована связка try / except для
вызова Beat.objects.get(), т.к. в
этом нет необходимости. В случае неудачи данный метод
вызывает исключение Beat.DoesNotExist,
которое является подклассом
ObjectDoesNotExist. Вызов исключения
ObjectDoesNotExist в
get_object() указывает Django, что
необходимы выдать страницу с ошибкой 404 на
обрабатываемый запрос.
Для генерации элементов <title>,
<link> и <description> Django
использует методы title(),
link() и
description(). В предыдущем примере
они были простыми строковыми атрибутами класса, но
данный пример иллюстрирует, что они могут быть строками
или методами. Для каждого элемента
title, link и
description Django следует
нижеприведённому алгоритму:
Производится вызов метода с передачей ему
аргумента obj, где
obj является объектом, возвращённым
методом get_object().
В случае неудачи, производится вызов метода без аргументов.
В случае неудачи, используется атрибут класса.
items() в
данном примере также принимает аргумент
obj. Алгоритм для items полностью совпадает с предыдущим пунктом — сначала
производится вызов items(obj), затем
items() и наконец используется
атрибут класса items (который должен
быть списком).
Полная документация по всем методам и атрибутам классов
Feed доступна на официальном сайте
Django (http://www.djangoproject.com/documentation/0.96/syndication_feeds/).
По умолчанию среда трансляций генерирует RSS 2.0. Для
изменения этого поведения надо добавить атрибут
feed_type в ваш класс
Feed:
from django.utils.feedgenerator import Atom1Feed
class MyFeed(Feed):
feed_type = Atom1Feed
Следует отметить то, что вы устанавливаете этот атрибут для класса, а не для экземпляра. Доступные типы трансляций показаны в таблице «Типы трансляций»:
Таблица 11.1. Типы трансляций
| Класс трансляции | Формат |
|---|---|
| django.utils.feedgenerator.Rss201rev2Feed | RSS 2.01 (по умолчанию) |
| django.utils.feedgenerator.RssUserland091Feed | RSS 0.91 |
| django.utils.feedgenerator.Atom1Feed | Atom 1.0 |
Для того, чтобы указать вложения (т.е. медиа ресурсы ассоциированные с элементами трансляции, такими как MP3 подкасты), используйте обработчики item_enclosure_url, item_enclosure_length и item_enclosure_mime_type, например:
from myproject.models import Song
class MyFeedWithEnclosures(Feed):
title = "Example feed with enclosures"
link = "/feeds/example-with-enclosures/"
def items(self):
return Song.objects.all()[:30]
def item_enclosure_url(self, item):
return item.song_url
def item_enclosure_length(self, item):
return item.song_length
item_enclosure_mime_type = "audio/mpeg"
Это предполагает, что вы уже создали объект
Song с полями song_url и
song_length (размер в байтах).
Трансляции создаваемые средой автоматически получают соответствующий тег <language> (RSS 2.0) или атрибут xml:lang (Atom). Значение этого тега зависит от параметра конфигурации LANGUAGE_CODE.
Атрибут/метод link может возвращать как абсолютный URL (т.е. /blog/), так и полный URL (т.е. http://www.example.com/blog/). Если link не возвратил домен, то среда трансляций добавит домен текущего сайта в соответствии с параметром конфигурации SITE_ID.
Трансляции Atom требуют наличия <link rel="self">, который определяет место расположения трансляции. Среда трансляций создаёт его автоматически, используя домен текущего сайта в соответствии с параметром конфигурации SITE_ID.
Некоторые разработчики предпочитают предоставлять трансляции в
обоих видах: RSS и Atom. С помощью Django это несложно
сделать: просто создайте подкласс для вашего класса
feed и установите
feed_type в что-нибудь отличное. Затем добавьте
его вызов в ваш файл привязок. Вот полный пример:
from django.contrib.syndication.feeds import Feed
from chicagocrime.models import NewsItem
from django.utils.feedgenerator import Atom1Feed
class RssSiteNewsFeed(Feed):
title = "Chicagocrime.org site news"
link = "/sitenews/"
description = "Updates on changes and additions to chicagocrime.org."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
class AtomSiteNewsFeed(RssSiteNewsFeed):
feed_type = Atom1Feed
А здесь соответствующий файл привязок:
from django.conf.urls.defaults import *
from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed
feeds = {
'rss': RssSiteNewsFeed,
'atom': AtomSiteNewsFeed,
}
urlpatterns = patterns('',
# ...
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
# ...
)