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-planet
git clone https://github.com/matagus/django-planet.git
cd django-planet
pip install -e .
- Add
planet
andpagination
to yourINSTALLED_APPS
insettings.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
MIDDLEWARE
insettings.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.xml
This 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_feeds
This 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_feeds
Django-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
style
attributes - 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:test
hatch run test:cov
This 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 test
If 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