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
Postmodel: title/slug/excerpt/body/featured image/author/status (draft/published)/publish date, plusmeta_title/meta_descriptionfor SEO, arelated_productsmany-to-many ontocatalogue.Product, and tags (via django-taggit). - Storefront list/detail views (
oscar_blog.urls) and aPostSitemap. - 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 owndashboard.pagesapp (flatpages), including its permission model (is_staffby 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.
Related products
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-installeddashboard:catalogue-product-lookupendpoint (oscar.apps.dashboard.catalogue.views.ProductLookupView, a realtitle__icontainssearch, 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'sdashboard/forms.pyjust wires Oscar's existing one in, plus one real fix Oscar itself doesn't apply consistently:ProductSelectMultipleneeds an explicitclass="select2 product-select"to actually get AJAX-backed search (confirmed againstoscar/static/oscar/js/oscar/dashboard.js'sinitSelects()— 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)
| File | Size | Uploaded | |
|---|---|---|---|
| django_oscar_blog-0.5.0.tar.gz | 72.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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}
|