I'm trying to build several websites with DjangoCMS
with some shared pages. Is it possible to create a page which is shared across all django Site
s?
With a basic DjangoCMS
configuration, when a page is published on a Site
it does not appear on other Site
. I am wondering if this is configurable in any way.
When looking at the code I've seen that the TreeNode
is linked to a specific Site
(https://github.com/divio/django-cms/blob/develop/cms/models/pagemodel.py#L52), so I guess that if it's possible it won't be that simple.
class TreeNode(MP_Node):
# [...]
site = models.ForeignKey(
Site,
on_delete=models.CASCADE,
verbose_name=_("site"),
related_name='djangocms_nodes',
db_index=True,
)
# [...]
I'd be fine with an external module if DjangoCMS does not handle this, or even some ideas or lead of how to approach this, I really don't have a clue.
Thanks a lot!
I've solved this issue with some ugly patches in the DjangoCMS code itself.
from cms import cms_menus
from cms.templatetags import cms_tags
from cms.utils import page
# Ugly-patching DjangoCMS so that a page from another Django Site can be displayed
def new_get_page_from_path(site, path, preview=False, draft=False):
"""
Resolves a url path to a single page object.
Returns None if page does not exist
"""
from cms.models import Title
titles = Title.objects.select_related('page__node')
published_only = not draft and not preview
if draft:
titles = titles.filter(publisher_is_draft=True)
elif preview:
titles = titles.filter(publisher_is_draft=False)
else:
titles = titles.filter(published=True, publisher_is_draft=False)
titles = titles.filter(path=(path or ''))
titles = list(titles.iterator())
for title in titles:
if title.page.node.site_id != site.pk:
continue
if published_only and not page._page_is_published(title.page):
continue
title.page.title_cache = {title.language: title}
return title.page
# This is the different part from the DjangoCMS code:
# re do the same loop, but this time ignore the Site filtering
for title in titles:
if published_only and not page._page_is_published(title.page):
continue
title.page.title_cache = {title.language: title}
return title.page
return
# Ugly-patching DjangoCMS so that a page from another Django Site can fetched
# using {% pageurl %} (for example)
def new_get_page_queryset(site, draft=True, published=False):
from cms.models import Page
if draft:
pages = Page.objects.drafts().on_site(site)
if pages:
return pages
if published:
pages = Page.objects.public().published(site)
if pages:
return pages
pages = Page.objects.public().on_site(site)
if pages:
return pages
# This is the different part from the DjangoCMS code:
# re do the same logic, but this time ignore the Site filtering
if draft:
return Page.objects.drafts()
if published:
return Page.objects.public().published()
return Page.objects.public()
page.get_page_from_path = new_get_page_from_path
page.get_page_queryset = new_get_page_queryset
cms_tags.get_page_queryset = new_get_page_queryset
cms_menus.get_page_queryset = new_get_page_queryset
Then I'm importing this file before the urlpatterns
variable in the urls.py
file (warned you it was ugly).
What DjangoCMS does is that it tries to find the Page
with the Site
given in the request. If the Page
is not found, DjangoCMS would raise a 404 error, but in our case we re-do the same query but this time without the Site
filter.
This way a Page
created on one Site
is accessible on each sub-Site
.
I then needed some Page
accessible on every Site
with most of the content identical, but SOME different content. I've solved this issue by using the static_placeholder
tag which can be specified per sub-Site
. http://docs.django-cms.org/en/latest/reference/templatetags.html#static-placeholder