django-planet
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.
π Table of Contents
- β¨ Features
- π¦ Installation & Configuration
- π Usage
- Adding Feeds
- Updating Feeds
- Built-in Views
- Templates
- Using Template Tags
- Admin Interface
- Management Commands
- πΈ Screenshots
- π§ͺ Testing
- π€ Contributing
- π License
- π Acknowledgements
- π¬ Support
β¨ Features
- 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
π¦ Installation & Configuration
Via pip
pip install django-planet
From source
git clone https://github.com/matagus/django-planet.git
cd django-planet
pip install -e .
Configure your Django project
- 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"))
]
π Usage
Adding Feeds
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
Updating Feeds
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
Built-in Views
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
Templates
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
Using Template Tags
Django-planet includes custom template tags for common operations. Load them in your templates:
{% load planet_tags %}
Available Template Tags
Filters
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
Simple Tags
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
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)
Admin Interface
All models are registered in Django admin with sensible defaults:
- BlogAdmin
- FeedAdmin
- PostAdmin
- AuthorAdmin
All admin interfaces include search and filtering capabilities.
Management Commands
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
πΈ Screenshots
Post List
Blog View
Full Post View
Live Demo
Check out the live demo: django-planet.matagus.dev
Demo source code is available in the project/
directory.
π§ͺ Testing
You can run tests either with Hatch (recommended for testing multiple Python/Django versions) or directly.
With Hatch (recommended)
Django-planet uses Hatch for testing across multiple Python and Django versions.
Run all tests
Test across all Python/Django version combinations:
hatch run test:test
Run tests for specific versions
# 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
Run with coverage
hatch run test:cov
This will: 1. Run tests with coverage tracking 2. Generate a coverage report 3. Output results to the terminal
View test matrix
See all available Python/Django test combinations:
hatch env show test
Without Hatch
If you prefer to run tests directly without Hatch:
-
Install test dependencies:
bash pip install coverage factory_boy
-
Run tests using Django's test runner:
bash python -m django test --settings tests.settings
-
Run tests with coverage:
bash coverage run -m django test --settings tests.settings coverage report
-
Generate coverage JSON:
bash coverage json
π€ Contributing
Contributions are welcome! β€οΈ
Development Setup
- Fork the repository
-
Clone your fork:
bash git clone https://github.com/YOUR_USERNAME/django-planet.git cd django-planet
-
Install development dependencies:
bash pip install -e . pip install pre-commit
-
Set up pre-commit hooks:
bash 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:
bash pre-commit run --all-files
Quick Contribution Guide
- 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
π License
django-planet
is released under the BSD 3-Clause License - see the LICENSE file for more information.
π Acknowledgements
Developed and built using:
Inspired by: - Feedjack - Original Django feed aggregator - Mark Pilgrim's Feedparser - Universal feed parser library
π¬ Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- PyPI: pypi.org/project/django-planet