Django поставляется со средствами высокого уровня для трансляции данных, что позволяет легко создавать потоки RSS или Atom.
Что такое 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}),
# ...
)
| Пред. | Уровень выше | След. |
| Другие возможности | Начало | Среда генерации карты сайта |
2 comments | Make a comment
В mysite.models никаких NewsItem разумеется нет. Естественно ImportError
answer to Nule
В mysite.models никаких NewsItem разумеется нет. Естественно ImportError
mysite.models это как бы подразумевает имя_приложения.models. Поэтому, естественно ImportError, если не понимая, делать копипаст в свой код.