Синдикационная лента Просмотр RSS в файл
Я использую django в качестве веб-фронтенда для моего подкаста. Я использую CDN для хостинга всех моих медиа, и в последнее время я хочу, чтобы тот же CDN размещал мою RSS ленту, а не напрямую django.
В текущей установке есть несколько основных хорошо известных примитивов:
path('podcast.xml', SubscribeFeed(), name='episode_feed'),
Дополнительный контекст; SubscribeFeed - это синдикационный канал (https://github.com/django/django/blob/main/django/contrib/syndication/views.py#L27), который основан на https://docs.djangoproject.com/en/4.0/ref/contrib/syndication/#custom-feed-generators
И это выглядит примерно так:
class iTunesFeed(Rss201rev2Feed):
content_type = 'application/xml; charset=utf-8'
def root_attributes(self):
attrs = super().root_attributes()
attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
return attrs
< ... Ripped right from the custom feed generators with a ton of extra elements for the specific podcast category and such ... >
class SubscribeFeed(Feed):
title = "My Cool Podcast"
description = About.objects.first().about
author_email = "podcast@gmail.com"
author_name = "John Doe"
feed_type = iTunesFeed
def item_pubdate(self, item):
return item.pub_date
< ... More stuff that isn't relevant ... >
Чтобы было понятно, это представление прекрасно работает с Django, обслуживающим RSS подкастов. Оно работает на всех основных платформах и очень красиво.
Моя проблема/вопрос заключается в следующем: Я хочу генерировать/рендерить это представление в текстовый файл, цель в том, что я размещаю медиа на CDN, мне также было бы выгодно разместить этот RSS-канал на отдельном CDN feeds.mypodcast.com. Таким образом, приложение django может выйти из строя, но лента и медиа по-прежнему будут доступны через CDN. Приложение django находится на критическом пути только для: описания эпизодов, контактных форм, веб-уи просмотра эпизодов и т.д.
Я уже запускаю celery для выпуска эпизодов с заданным интервалом, поэтому мой план следующий:
Создайте асинхронную функцию, запускаемую после функции сохранения модели save(), которая
- Генерирует новый фид в файл или строку
- Сравнивает то, что находится в CDN
- Заменяет файл RSS-канала CDN и аннулирует кэш CDN.
Шаги 2 и 3 очень просты, но у меня возникают трудности с генерацией в файл.
То, что я пробовал:
- "Издевательство" над запросами и выполнение get_feed
podcast_feed.get_feed(podcast_feed.items(), <mocked request object>)
** Это, конечно, "работает", но вызов моих собственных ресурсов REST ощущается плохо и не очень хорошо. - Создание "скрытого" диспетчера URL. Затем по расписанию celery beat я обращаюсь к этому URL из моей задачи celery. Генерирую представление через запросы, сравниваю и перераспределяю на CDN. ** Это тоже "работает", но аналогично плохо себя чувствует.
- Написание собственного
get_feed()
вида функции. ** Это не совсем сработало. Читая исходный текст, я обнаружил, что он довольно сильно зависит от правильного запроса, и я не думал, что архитектурно делаю это в правильном месте. (создание собственного генератора фидов) .
render_to_string
но для Syndication Feeds. ** Это прекратилось почти сразу. Хорошо работало на обычном представлении, но не могло разобраться с фидами.
Я уже давно бьюсь над этим вопросом. "Скрытая" отправка кажется наиболее безопасным и эффективным способом, но я бы предпочел сделать это правильным способом.
На самом деле мой вопрос требует архитектурного руководства. Каков правильный способ сделать это? Я надеялся найти что-то очевидное, как render_to_string
, но для синдицированных фидов. Реализация моего собственного feedgenerator
не дала хороших результатов.
Какой наилучший путь решения проблемы простого использования; Передача представления ленты синдикации в текстовый файл?
Спасибо.
Вы можете просто сделать это в отдельном представлении:
def rss_feed_to_file():
response = SubscribeFeed()
# response is a HttpResponse object
# response.content contains the feed content which you could then save as whatever you like
отвечает ли это на ваш вопрос?
Я выбираю свой ответ, потому что я немного больше думал над постановкой задачи. Паттерн MVT/MVC в Django действительно хорош, но я думаю, что я просил его делать то, что он не должен делать.
Создание представления из шаблона аля Django Syndication Feed было отличным решением, если я хотел обслуживать RSS канал из самого приложения Django. Но, как указано в вопросе, я хотел отсылать этот RSS-канал на какую-то удаленную CDN.
Я достиг этого, написав свою собственную обертку вокруг rfeed (примечание: та, что в pypi, является более старым форком...). Которая собирает все мои эпизоды и модели метаданных подкастов, передает их в элементы, а затем в фид.
Затем я написал простую асинхронную задачу при сохранении модели (или выпуске запланированного эпизода), которая просто генерирует RSS-канал rfeed, создает объект S3, дифференцирует то, что находится в S3, затем условно выталкивает в S3 и аннулирует CDN cloudfront.
Мне очень нравится такой подход, потому что теперь мое django-приложение, если случится что-то плохое, не будет работать в автономном режиме. Все медиа и RSS теперь находятся в CDN, сайт используется только для записей шоу, контактных форм, информации о нас, простых вещей. Критическая инфраструктура теперь проблема облачных провайдеров.