Синдикационная лента Просмотр 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, сайт используется только для записей шоу, контактных форм, информации о нас, простых вещей. Критическая инфраструктура теперь проблема облачных провайдеров.

Вернуться на верх