Skip to main content

Small Django blog/news app with multi-site support (django.contrib.sites).

Project description

django-site-blog

Tests Python Django License

Small Django blog / news app with multi-site support (django.contrib.sites).

Lets editors restrict an article to one or more Site objects, or leave the assignment empty so the article appears on every site that runs the same Django project.

Why?

Many Django projects host multiple sites — a corporate front page, a research portal, project subsites — from a single codebase using django.contrib.sites. Most blog/news apps either ignore that scenario or expect a separate deployment per site.

django-site-blog keeps one article store and lets editors say, per article, whether it should appear on every site (the default) or be restricted to a chosen subset. One schema, one query, no middleware gymnastics.

Features

  • Per-article site assignment via M2M to django.contrib.sites.models.Site.
  • "Empty M2M = visible everywhere" default — restrict only when you need to.
  • draft/published status via model_utils.StatusModel; admin-aware get_absolute_url so drafts link back into the admin.
  • Split-marker excerpts via model_utils.SplitField (marker configurable through the SPLIT_MARKER setting).
  • Multi-site-aware ArticleDetailView (slug-based, filters by SITE_ID).
  • Article.on_site CurrentSiteManager for pure "current-site only" semantics when the empty-equals-all default isn't what you want.
  • Polish translation included; rest of the UI is gettext_lazy-ready.
  • Admin with filter_horizontal, list_filter, slug prepopulation.

Supported versions

Django × Python

Django 3.10 3.11 3.12 3.13 3.14 Status
5.2 LTS Active LTS (extended support Apr 2028)
6.0 Mainstream Aug 2026, extended Apr 2027

Verified against the CI matrix in .github/workflows/tests.yml. Also requires django-model-utils >=4.5,<5 (for SplitField, TimeStampedModel, StatusModel). The 5.x release of django-model-utils changed SplitField in a way that conflicts with explicit _article_body_excerpt declarations in migrations (produces a duplicate-column error at migrate); the upper bound is deliberate until upstream resolves it.

Installation

uv add django-site-blog

or with pip:

pip install django-site-blog

Add the app and django.contrib.sites to INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    "django.contrib.sites",
    "siteblog",
]

SITE_ID = 1  # required by django.contrib.sites

Include the URLs in your project's urls.py:

urlpatterns = [
    # ...
    path("articles/", include("siteblog.urls")),
]

Run migrations:

python manage.py migrate

How site assignment works

Each Article has a sites M2M to django.contrib.sites.models.Site.

  • Empty M2M → article visible on every site (the default).
  • One or more sites set → article only visible on the listed sites.

The included ArticleDetailView enforces this with a single OR query:

Article.objects.filter(
    Q(sites__isnull=True) | Q(sites__id=settings.SITE_ID)
).distinct()

If you want pure "current-site only" semantics (drop the empty-equals-all behaviour), use the Article.on_site CurrentSiteManager instead.

Settings

Setting Default Purpose
SITE_ID Required by django.contrib.sites. Drives the per-site filtering.
SPLIT_MARKER "<!-- split -->" Marker shown in the admin help text for Article.article_body to indicate the split-point between excerpt and full article. The actual splitting is performed by model_utils.fields.SplitField per its own settings.

Templates

The package ships two minimal templates:

  • siteblog/article_detail.html — uses {% extends "siteblog/base.html" %}.
  • siteblog/base.html — a bare HTML skeleton; override it in your project by placing a siteblog/base.html ahead of the package's in your TEMPLATES DIRS.

Development

git clone https://github.com/iplweb/django-site-blog.git
cd django-site-blog
uv sync --all-extras
DJANGO_SETTINGS_MODULE=tests.settings uv run pytest

pre-commit install to wire ruff + pyupgrade + django-upgrade.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_site_blog-0.1.0.tar.gz (10.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_site_blog-0.1.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file django_site_blog-0.1.0.tar.gz.

File metadata

  • Download URL: django_site_blog-0.1.0.tar.gz
  • Upload date:
  • Size: 10.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for django_site_blog-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e8d7b045fd2515eb0b5cd59b3be41ff368550d1e105ee045b7929deb9831d5ce
MD5 2d112993688b7ad5e1782e5235234d4d
BLAKE2b-256 f2f75ac21529657e22f3bed377b56db4ffbf46c695213fc86092f333d79b9531

See more details on using hashes here.

File details

Details for the file django_site_blog-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: django_site_blog-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for django_site_blog-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0ff59ebbf4aa55343b07bfc85f7de642bab9f1858f39d4ef4aaeb4e05f25fccc
MD5 68b0909ec8f9be5e971b33c55479da56
BLAKE2b-256 0b52582993f92f77e7745ab7ad1c4781b9fa7ab892ef10680193802d5c2646bd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page