Skip to main content

django-oscar-blog

A blog app for django-oscar: posts, an Oscar dashboard section under Content, and posts that can link out to catalogue products they mention.

What this package does, and doesn't, do

  • A Post model: title/slug/excerpt/body/featured image/author/status (draft/published)/publish date, plus meta_title/meta_description for SEO, a related_products many-to-many onto catalogue.Product, and tags (via django-taggit).
  • Storefront list/detail views (oscar_blog.urls) and a PostSitemap.
  • An Oscar dashboard section (oscar_blog.dashboard) for staff to create, edit, and delete posts — list/create/update/delete views following the exact same conventions as Oscar's own dashboard.pages app (flatpages), including its permission model (is_staff by default).
  • It does not ship a newsletter integration or a "featured products" CTA anywhere in the storefront — see "Adding a CTA" below. The related-products picker defaults to a plain multi-select but has an opt-in AJAX autocomplete mode — see "Related products" below.

Installation

uv add django-oscar-blog

Add to INSTALLED_APPS, after catalogue/partner (it references catalogue.Product) and after oscar.config.Shop:

INSTALLED_APPS = [
    ...,
    "taggit",
    "oscar_blog.apps.OscarBlogConfig",
    "oscar_blog.dashboard.apps.BlogDashboardConfig",
]

Run manage.py migrate — this package ships its own migration.

Wiring the storefront URLs

# urls.py
urlpatterns = [
    path("blog/", include("oscar_blog.urls")),
    ...
]

Templates extend oscar/layout.html under oscar_blog/post_list.html and oscar_blog/post_detail.html — override them the same way you'd override any other Oscar template (a project-level templates/oscar_blog/... directory).

Wiring the dashboard in ("Content" menu)

Oscar's own dashboard.apps.DashboardConfig.get_urls() is a hardcoded list, not auto-discovered — every dashboard section Oscar ships is added there directly, and third-party sections have to fork that config the same way you'd fork any other Oscar app. This package's own test suite (tests/dashboard.py) is a working example of exactly this fork — copy its shape into your project, e.g. a dashboard/apps.py:

from django.apps import apps
from django.urls import include, path
from oscar.apps.dashboard.apps import DashboardConfig as OscarDashboardConfig


class DashboardConfig(OscarDashboardConfig):
    def ready(self):
        super().ready()
        self.blog_app = apps.get_app_config("blog_dashboard")

    def get_urls(self):
        urls = super().get_urls()
        urls.append(path("blog/", include(self.blog_app.urls[0])))
        return urls

...and swap "oscar.apps.dashboard.apps.DashboardConfig" for your project's own "yourproject.dashboard.apps.DashboardConfig" in INSTALLED_APPS.

Then add the nav entry under Content, alongside Pages/Email templates/Reviews, by overriding OSCAR_DASHBOARD_NAVIGATION (a plain Django setting — copy Oscar's default from oscar.defaults and insert):

{
    "label": _("Blog posts"),
    "url_name": "dashboard:blog-post-list",
},

into the "Content" entry's "children" list.

Post.related_products is a plain (unordered) ManyToManyField onto catalogue.Product. A published post's detail page lists them under "Mentioned products", linking to each product's own page (post_detail.html). Nothing on the Product side surfaces "posts that mention me" yet — the reverse relation is available as product.blog_posts.all() if a host project wants to add that to a product page.

Dashboard picker widget — two modes, one setting:

OSCAR_BLOG_PRODUCT_AUTOCOMPLETE = True  # default: False
  • Off (default): a plain <select multiple> with every product rendered as an <option>. Fine at a small catalogue's scale; at real scale every dashboard post-edit page load pulls in the whole catalogue.
  • On: the dashboard's related-products field switches to Oscar's own oscar.apps.dashboard.catalogue.widgets.ProductSelectMultiple — a Select2 widget backed by Oscar's already-installed dashboard:catalogue-product-lookup endpoint (oscar.apps.dashboard.catalogue.views.ProductLookupView, a real title__icontains search, already staff-permission-gated). Only the currently selected products are pre-rendered; everything else loads as the user types. No new backend endpoint needed — this project's dashboard/forms.py just wires Oscar's existing one in, plus one real fix Oscar itself doesn't apply consistently: ProductSelectMultiple needs an explicit class="select2 product-select" to actually get AJAX-backed search (confirmed against oscar/static/oscar/js/oscar/dashboard.js's initSelects() — without it, the field would still render, just silently degraded to searching only the few options already in the page).

Requires oscar.apps.dashboard.catalogue installed (it almost certainly already is — it's the products dashboard). If it isn't, turning this setting on will fail with a NoReverseMatch on dashboard:catalogue-product-lookup, not silently.

Tags

Uses django-taggit directly (BSD-licensed) rather than a hand-rolled tag model — Post.tags is a TaggableManager, editable in the dashboard as a plain comma-separated field (taggit's own default widget, no extra code needed). Tags are shared across posts (the same tag name is the same Tag row everywhere, not per-post free text), and the storefront list view supports ?tag=<slug> filtering — both oscar_blog/post_list.html and post_detail.html render each post's tags as links to that filtered list. Run manage.py migrate after adding taggit to INSTALLED_APPS — it ships its own migrations for the shared Tag/TaggedItem tables.

Adding a CTA (deliberately not built here)

This package intentionally ships no newsletter-subscribe or "promote this product" call-to-action anywhere in its templates — that's host-project UI/UX scope (placement, copy, branding), not something a reusable blog app should assume. If your project adds one, the natural places are oscar_blog/post_list.html/post_detail.html (override them) or a custom template tag included from there.

Translations

The package ships a Spanish translation (src/oscar_blog/locale/es/). Both the .po source and the compiled .mo are committed, so the wheel includes the .mo and nothing needs compiling on install. After editing a .po, recompile before releasing:

msgfmt -o src/oscar_blog/locale/es/LC_MESSAGES/django.mo \
    src/oscar_blog/locale/es/LC_MESSAGES/django.po

New strings are extracted with django-admin makemessages -l es run from src/oscar_blog/. A project can override any single string in its own LOCALE_PATHS without copying the whole catalogue.

Development

uv sync
uv run pytest

tests/settings.py boots a full (stock) Oscar app stack — this package genuinely depends on Oscar's catalogue models, unlike a framework-agnostic library, so its tests can't run against bare Django alone.

Metadata

Release files for django-oscar-blog 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-oscar-blog 0.5.0
File Size Uploaded
django_oscar_blog-0.5.0.tar.gz 72.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-oscar-blog 0.5.0
File Interpreter ABI Platform
django_oscar_blog-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 95.6 kB

Release files / django_oscar_blog-0.5.0.tar.gz

Download URL django_oscar_blog-0.5.0.tar.gz
Size 72.2 kB
Tags Source
SHA-256 checksum
How to use checksums
90e927cd1d47b15fb839590635dc992bc2c670200efe98a6893b8366a60a0acc
BLAKE2b-256 checksum
How to use checksums
38bb0494dd0d6072d9f1d99cc03624c3d1175889862de76b16574b6c5aa6cd4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / django_oscar_blog-0.5.0-py3-none-any.whl

Download URL django_oscar_blog-0.5.0-py3-none-any.whl
Size 23.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
41e2837668a2f8af66399748d39994c5b49205837442710115a55379458b3128
BLAKE2b-256 checksum
How to use checksums
f1a00056371dda1ce30e547777fe5430e372d95fe2d7ddcf2a950ce777179df9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.5.1

2 release files

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page