Skip to content

matagus/django-planet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

django-planet

Python Compatibility Django Compatibility PyPi Version CI badge codecov License

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.

Post List

πŸ“‘ Table of Contents

✨ 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

  1. Add planet and pagination to your INSTALLED_APPS in settings.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
]
  1. Add pagination middleware to MIDDLEWARE in settings.py:
MIDDLEWARE = [
    # ... other middleware
    "pagination.middleware.PaginationMiddleware",
]
  1. (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
}
  1. Run migrations:
python manage.py migrate
  1. 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

Post List

Blog View

Blog View

Full Post 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:

  1. Install test dependencies:

    pip install coverage factory_boy
  2. Run tests using Django's test runner:

    python -m django test --settings tests.settings
  3. Run tests with coverage:

    coverage run -m django test --settings tests.settings
    coverage report
  4. Generate coverage JSON:

    coverage json

🀝 Contributing

Contributions are welcome! ❀️

Development Setup

  1. Fork the repository

  2. Clone your fork:

    git clone https://github.com/YOUR_USERNAME/django-planet.git
    cd django-planet
  3. Install development dependencies:

    pip install -e .
    pip install pre-commit
  4. Set up pre-commit hooks:

    pre-commit install

    This will automatically run code quality checks (ruff, black, codespell, etc.) before each commit.

  5. (Optional) Run pre-commit on all files manually:

    pre-commit run --all-files

Quick Contribution Guide

  1. Create a feature branch (git checkout -b feature/new-feature)
  2. Make your changes
  3. Run tests (see above)
  4. Pre-commit hooks will run automatically when you commit
  5. Commit your changes (git commit -m 'Add new feature')
  6. Push to the branch (git push origin feature/new-feature)
  7. 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:

Hatch project linting - Ruff code style - black

Inspired by:

πŸ’¬ Support

About

🌐 A django planet and feeds (RSS and ATOM) aggregator application for Django

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

  •  

Contributors 11

Languages