A reusable Django app for building RSS/Atom feed aggregator websites (aka "Planet" sites).
Django-planet makes it easy to create a planet-style feed aggregator. Collect posts from multiple blogs and websites, store them in your database, and display them with built-in views and templatesβor build your own custom front-end.
- β¨ Features
- π¦ Installation & Configuration
- π Usage
- πΈ Screenshots
- π§ͺ Testing
- π€ Contributing
- π License
- π Acknowledgements
- π¬ Support
- RSS and Atom feed parsing - Supports both RSS and Atom feed formats via feedparser
- Automatic feed updates - Management commands to add feeds and update all feeds
- Blog, Feed, Post, and Author models - Complete data model with relationships
- Built-in views and templates - Ready-to-use views for blogs, feeds, posts, and authors
- Django admin integration - Manage all content through Django's admin interface
- Search functionality - Built-in search across posts, blogs, feeds, and authors
- SEO-friendly URLs - Slugified URLs with automatic redirects
- Custom managers - QuerySet methods for filtering by blog, feed, author
- Template tags - Custom template tags for common operations
- Pagination support - Uses django-pagination-py3 for easy pagination
pip install django-planetgit clone https://github.com/matagus/django-planet.git
cd django-planet
pip install -e .- Add
planetandpaginationto yourINSTALLED_APPSinsettings.py:
INSTALLED_APPS = [
# Django apps
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Third-party apps
"planet",
"pagination", # Required dependency
]- Add pagination middleware to
MIDDLEWAREinsettings.py:
MIDDLEWARE = [
# ... other middleware
"pagination.middleware.PaginationMiddleware",
]- (Optional) Configure planet settings in
settings.py:
PLANET = {
"USER_AGENT": "MyPlanet/1.0", # Customize the User-Agent for feed requests
"RECENT_POSTS_LIMIT": 10, # Number of recent posts to show
"RECENT_BLOGS_LIMIT": 10, # Number of recent blogs to show
}- Run migrations:
python manage.py migrate- Include planet URLs in your project's
urls.py:
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("planet.urls")), # or path("planet/", include("planet.urls"))
]You can add feeds using the management command:
python manage.py planet_add_feed https://example.com/feed.xmlThis will:
- Parse the feed and create a Blog entry if it doesn't exist
- Create the Feed entry
- Import all posts from the feed
- Create Author entries and link them to posts
Update all active feeds to fetch new posts:
python manage.py planet_update_all_feedsThis command:
- Iterates through all feeds
- Fetches new entries
- Creates new Post and Author entries as needed
- Updates feed metadata (last_checked, etag)
Set up periodic updates:
For production, schedule this command to run periodically:
Using cron:
# Run every hour
0 * * * * /path/to/venv/bin/python /path/to/project/manage.py planet_update_all_feedsDjango-planet provides these URL patterns:
/- Post list (index)/posts/- All posts/posts/<id>/<slug>/- Post detail/blogs/- All blogs/blogs/<id>/<slug>/- Blog detail (shows all posts from that blog)/feeds/- All feeds/feeds/<id>/<slug>/- Feed detail (shows all posts from that feed)/authors/- All authors/authors/<id>/<slug>/- Author detail (shows all posts by that author)/search/- Search form endpoint
Planet includes a complete set of templates:
planet/templates/planet/
βββ base.html # Base template
βββ posts/
β βββ list.html # Post list view
β βββ detail.html # Post detail view
β βββ blocks/
β βββ list.html # Reusable post list block
βββ blogs/
β βββ list.html # Blog list view
β βββ detail.html # Blog detail view
β βββ blocks/
β βββ list.html # Reusable blog list block
βββ feeds/
β βββ list.html # Feed list view
β βββ detail.html # Feed detail view
β βββ blocks/
β βββ list_for_author.html
βββ authors/
βββ list.html # Author list view
βββ detail.html # Author detail view
βββ blocks/
βββ list.html # Reusable author list block
βββ list_for_feed.html
Django-planet includes custom template tags for common operations. Load them in your templates:
{% load planet_tags %}clean_html - Cleans HTML content by removing inline styles, style tags, and script tags
{{ post.content|clean_html }}This filter:
- Removes inline
styleattributes - Removes
<style>and<script>tags - Replaces multiple consecutive
<br/>tags (3+) with just two - Returns safe HTML that won't be escaped
get_first_paragraph - Extracts the first paragraph or sentence from post content
{% get_first_paragraph post.content as excerpt %}
{{ excerpt }}This tag:
- Strips all HTML tags
- Normalizes whitespace
- Returns the first sentence longer than 80 characters
- Falls back to the first 80 characters if no long sentence is found
- Useful for creating post excerpts or previews
get_authors_for_blog - Returns all authors who have written posts for a specific blog
{% get_authors_for_blog blog as authors %}
{% for author in authors %}
<a href="{{ author.get_absolute_url }}">{{ author.name }}</a>
{% endfor %}blogs_for_author - Returns all blogs that an author has contributed to
{% blogs_for_author author as blogs %}
{% for blog in blogs %}
<a href="{{ blog.get_absolute_url }}">{{ blog.title }}</a>
{% endfor %}Inclusion tags render complete HTML blocks with their own templates.
authors_for_feed - Renders a list of all authors who have posts in a feed
{% authors_for_feed feed %}Uses template: planet/authors/blocks/list_for_feed.html
feeds_for_author - Renders a list of all feeds an author has contributed to
{% feeds_for_author author %}Uses template: planet/feeds/blocks/list_for_author.html
recent_posts - Renders a list of the most recent posts across all blogs
{% recent_posts %}Uses template: planet/posts/blocks/list.html
Limit controlled by PLANET["RECENT_POSTS_LIMIT"] setting (default: 10)
recent_blogs - Renders a list of the most recently added blogs
{% recent_blogs %}Uses template: planet/blogs/blocks/list.html
Limit controlled by PLANET["RECENT_BLOGS_LIMIT"] setting (default: 10)
All models are registered in Django admin with sensible defaults:
- BlogAdmin
- FeedAdmin
- PostAdmin
- AuthorAdmin
All admin interfaces include search and filtering capabilities.
planet_add_feed <feed_url>
- Adds a new feed to the database
- Creates Blog if it doesn't exist
- Imports all existing posts from the feed
- Creates Author entries for post authors
planet_update_all_feeds
- Updates all active feeds
- Fetches new posts from each feed
- Updates feed metadata (etag, last_checked)
- Creates new Post and Author entries as needed
Check out the live demo: django-planet.matagus.dev
Demo source code is available in the project/ directory.
You can run tests either with Hatch (recommended for testing multiple Python/Django versions) or directly.
Django-planet uses Hatch for testing across multiple Python and Django versions.
Test across all Python/Django version combinations:
hatch run test:test# Python 3.12 + Django 5.0
hatch run test.py3.12-5.0:test
# Python 3.11 + Django 5.1
hatch run test.py3.11-5.1:testhatch run test:covThis will:
- Run tests with coverage tracking
- Generate a coverage report
- Output results to the terminal
See all available Python/Django test combinations:
hatch env show testIf you prefer to run tests directly without Hatch:
-
Install test dependencies:
pip install coverage factory_boy
-
Run tests using Django's test runner:
python -m django test --settings tests.settings -
Run tests with coverage:
coverage run -m django test --settings tests.settings coverage report -
Generate coverage JSON:
coverage json
Contributions are welcome! β€οΈ
-
Fork the repository
-
Clone your fork:
git clone https://github.com/YOUR_USERNAME/django-planet.git cd django-planet -
Install development dependencies:
pip install -e . pip install pre-commit -
Set up pre-commit hooks:
pre-commit install
This will automatically run code quality checks (ruff, black, codespell, etc.) before each commit.
-
(Optional) Run pre-commit on all files manually:
pre-commit run --all-files
- Create a feature branch (
git checkout -b feature/new-feature) - Make your changes
- Run tests (see above)
- Pre-commit hooks will run automatically when you commit
- Commit your changes (
git commit -m 'Add new feature') - Push to the branch (
git push origin feature/new-feature) - Open a Pull Request
django-planet is released under the BSD 3-Clause License - see the LICENSE file for more information.
Developed and built using:
Inspired by:
- Feedjack - Original Django feed aggregator
- Mark Pilgrim's Feedparser - Universal feed parser library
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- PyPI: pypi.org/project/django-planet


