8000 Remove placeholder content fallbacks by Aiky30 · Pull Request #6456 · django-cms/django-cms · GitHub
[go: up one dir, main page]

Skip to content

Remove placeholder content fallbacks #6456

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion cms/plugin_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,6 @@ def _preload_placeholders_for_page(self, page, slots=None, inherit=False):
placeholders=placeholders_to_fetch,
template=page.get_template(),
lang=self.request_language,
is_fallback=inherit,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is ok

)

parent_page = page.parent_page
Expand Down
2 changes: 1 addition & 1 deletion cms/tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_no_cache_plugin(self):
request = self.get_request(page1_url)
request.current_page = Page.objects.get(pk=page1.pk)
request.toolbar = CMSToolbar(request)
with self.assertNumQueries(FuzzyInt(18, 25)):
with self.assertNumQueries(FuzzyInt(16, 23)):
response1 = self.client.get(page1_url)
content1 = response1.content

10000 Expand Down
182 changes: 0 additions & 182 deletions cms/tests/test_placeholder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured
from django.template import TemplateSyntaxError, Template
from django.template.loader import get_template
Expand Down Expand Up @@ -29,14 +28,12 @@
from cms.test_utils.project.sampleapp.models import Category
from cms.test_utils.testcases import CMSTestCase, TransactionCMSTestCase
from cms.test_utils.util.mock import AttributeObject
from cms.toolbar.toolbar import CMSToolbar
from cms.toolbar.utils import get_toolbar_from_request
from cms.utils.compat.tests import UnittestCompatMixin
from cms.utils.conf import get_cms_setting
from cms.utils.placeholder import (PlaceholderNoAction, MLNGPlaceholderActions,
get_placeholder_conf, get_placeholders, _get_nodelist,
_scan_placeholders)
from cms.utils.plugins import assign_plugins
from cms.utils.urlutils import admin_reverse


Expand Down Expand Up @@ -471,185 +468,6 @@ def test_placeholder_field_dynamic_slot_update(self):
self.assertEqual(old_placeholder_1_plugin_count, current_placeholder_1_plugin_count)
self.assertEqual(old_placeholder_2_plugin_count, current_placeholder_2_plugin_count)

def test_plugins_language_fallback(self):
""" Tests language_fallback placeholder configuration """
page_en = create_page('page_en', 'col_two.html', 'en')
create_title("de", "page_de", page_en)
placeholder_en = page_en.get_placeholders("en").get(slot='col_left')
placeholder_de = page_en.get_placeholders("de").get(slot='col_left')
add_plugin(placeholder_en, 'TextPlugin', 'en', body='en body')

context_en = SekizaiContext()
context_en['request'] = self.get_request(language="en", page=page_en)
context_de = SekizaiContext()
context_de['request'] = self.get_request(language="de", page=page_en)

# First test the default (fallback) behavior)
## English page should have the text plugin
content_en = _render_placeholder(placeholder_en, context_en)
self.assertRegexpMatches(content_en, "^en body$")

## Deutsch page have text due to fallback
content_de = _render_placeholder(placeholder_de, context_de)
self.assertRegexpMatches(content_de, "^en body$")
self.assertEqual(len(content_de), 7)

conf = {
'col_left': {
'language_fallback': False,
},
}
# configure non fallback
with self.settings(CMS_PLACEHOLDER_CONF=conf):
## Deutsch page should have no text
del(placeholder_de._plugins_cache)
cache.clear()
content_de = _render_placeholder(placeholder_de, context_de)
## Deutsch page should inherit english content
self.assertNotRegex(content_de, "^en body$")
context_de2 = SekizaiContext()
request = self.get_request(language="de", page=page_en)
request.session['cms_edit'] = True
request.user = self.get_superuser()
request.toolbar = CMSToolbar(request)
context_de2['request'] = request
del(placeholder_de._plugins_cache)
cache.clear()
content_de2 = _render_placeholder(placeholder_de, context_de2)
self.assertFalse("en body" in content_de2)
# remove the cached plugins instances
del(placeholder_de._plugins_cache)
cache.clear()
# Then we add a plugin to check for proper rendering
add_plugin(placeholder_de, 'TextPlugin', 'de', body='de body')
content_de = _render_placeholder(placeholder_de, context_de)
self.assertRegexpMatches(content_de, "^de body$")

def test_nested_plugins_language_fallback(self):
""" Tests language_fallback placeholder configuration for nested plugins"""
page_en = create_page('page_en', 'col_two.html', 'en')
create_title("de", "page_de", page_en)
placeholder_en = page_en.get_placeholders("en").get(slot='col_left')
placeholder_de = page_en.get_placeholders("de").get(slot='col_left')
link_en = add_plugin(placeholder_en, 'LinkPlugin', 'en', name='en name', external_link='http://example.com/en')
add_plugin(placeholder_en, 'TextPlugin', 'en', target=link_en, body='en body')

context_en = SekizaiContext()
context_en['request'] = self.get_request(language="en", page=page_en)
context_de = SekizaiContext()
context_de['request'] = self.get_request(language="de", page=page_en)

conf = {
'col_left': {
'language_fallback': True,
},
}
with self.settings(CMS_PLACEHOLDER_CONF=conf):
content_de = _render_placeholder(placeholder_de, context_de)
self.assertRegexpMatches(content_de, "<a href=\"http://example.com/en\"")
self.assertRegexpMatches(content_de, "en body")
context_de2 = SekizaiContext()
request = self.get_request(language="de", page=page_en)
request.session['cms_edit'] = True
request.user = self.get_superuser()
request.toolbar = CMSToolbar(request)
context_de2['request'] = request
del(placeholder_de._plugins_cache)
cache.clear()
content_de2 = _render_placeholder(placeholder_de, context_de2)
self.assertFalse("en body" in content_de2)
# remove the cached plugins instances
del(placeholder_de._plugins_cache)
cache.clear()
# Then we add a plugin to check for proper rendering
link_de = add_plugin(
placeholder_de,
'LinkPlugin',
language='de',
name='de name',
external_link='http://example.com/de',
)
add_plugin(placeholder_de, 'TextPlugin', 'de', target=link_de, body='de body')
content_de = _render_placeholder(placeholder_de, context_de)
self.assertRegexpMatches(content_de, "<a href=\"http://example.com/de\"")
self.assertRegexpMatches(content_de, "de body")

def test_plugins_non_default_language_fallback(self):
""" Tests language_fallback placeholder configuration """
page_en = create_page('page_en', 'col_two.html', 'en')
create_title("de", "page_de", page_en)
placeholder_en = page_en.get_placeholders("en").get(slot='col_left')
placeholder_de = page_en.get_placeholders("de").get(slot='col_left')
add_plugin(placeholder_de, 'TextPlugin', 'de', body='de body')

context_en = SekizaiContext()
context_en['request'] = self.get_request(language="en", page=page_en)
context_de = SekizaiContext()
context_de['request'] = self.get_request(language="de", page=page_en)

# First test the default (fallback) behavior)
## Deutsch page should have the text plugin
content_de = _render_placeholder(placeholder_de, context_de)
self.assertRegexpMatches(content_de, "^de body$")
del(placeholder_de._plugins_cache)
cache.clear()
## English page should have no text
content_en = _render_placeholder(placeholder_en, context_en)
self.assertRegexpMatches(content_en, "^de body$")
self.assertEqual(len(content_en), 7)
del(placeholder_en._plugins_cache)
cache.clear()
conf = {
'col_left': {
'language_fallback': False,
},
}
# configure non-fallback
with self.settings(CMS_PLACEHOLDER_CONF=conf):
## English page should have deutsch text
content_en = _render_placeholder(placeholder_en, context_en)
self.assertNotRegex(content_en, "^de body$")

# remove the cached plugins instances
del(placeholder_en._plugins_cache)
cache.clear()
# Then we add a plugin to check for proper rendering
add_plugin(placeholder_en, 'TextPlugin', 'en', body='en body')
content_en = _render_placeholder(placeholder_en, context_en)
self.assertRegexpMatches(content_en, "^en body$")

def test_plugins_discarded_with_language_fallback(self):
"""
Tests side effect of language fallback: if fallback enabled placeholder
existed, it discards all other existing plugins
"""
page_en = create_page('page_en', 'col_two.html', 'en')
create_title("de", "page_de", page_en)
placeholder_sidebar_en = page_en.get_placeholders("en").get(slot='col_sidebar')
placeholder_en = page_en.get_placeholders("en").get(slot='col_left')
add_plugin(placeholder_sidebar_en, 'TextPlugin', 'en', body='en body')

context_en = SekizaiContext()
context_en['request'] = self.get_request(language="en", page=page_en)

conf = {
'col_left': {
'language_fallback': True,
},
}
with self.settings(CMS_PLACEHOLDER_CONF=conf):
# call assign plugins first, as this is what is done in real cms life
# for all placeholders in a page at once
assign_plugins(context_en['request'],
[placeholder_sidebar_en, placeholder_en], 'col_two.html')
# if the normal, non fallback enabled placeholder still has content
content_en = _render_placeholder(placeholder_sidebar_en, context_en)
self.assertRegexpMatches(content_en, "^en body$")

# remove the cached plugins instances
del(placeholder_sidebar_en._plugins_cache)
cache.clear()

def test_plugins_prepopulate(self):
""" Tests prepopulate placeholder configuration """

Expand Down
2 changes: 1 addition & 1 deletion cms/tests/test_plugin_renderers.py
9E7A
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def test_preload_placeholders_for_page_with_inherit_off(self):
external_link='https://www.django-cms.org',
)
renderer = self.get_renderer(page=cms_page)
renderer._preload_placeholders_for_page(cms_page, inherit=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave inherit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inherit is False as default so I have left out adding this one unless you feel that it adds value.
_preload_placeholders_for_page(self, page, slots=None, inherit=False):

renderer._preload_placeholders_for_page(cms_page)

self.assertIn(cms_page.pk, renderer._placeholders_by_page_cache)
self.assertIn(placeholder_1.slot, renderer._placeholders_by_page_cache[cms_page.pk])
Expand Down
52 changes: 5 additions & 47 deletions cms/utils/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from cms.models.pluginmodel import CMSPlugin
from cms.plugin_pool import plugin_pool
from cms.utils import get_language_from_request
from cms.utils.i18n import get_fallback_languages
from cms.utils.moderator import get_cmsplugin_queryset
from cms.utils.permissions import has_plugin_permission
from cms.utils.placeholder import get_placeholder_conf
Expand All @@ -36,7 +35,7 @@ def get_plugins(request, placeholder, template, lang=None):
return getattr(placeholder, '_plugins_cache')


def assign_plugins(request, placeholders, template=None, lang=None, is_fallback=False):
def assign_plugins(request, placeholders, template=None, lang=None):
"""
Fetch all plugins for the given ``placeholders`` and
cast them down to the concrete instances in one query
Expand All @@ -49,62 +48,21 @@ def assign_plugins(request, placeholders, template=None, lang=None, is_fallback=
qs = get_cmsplugin_queryset(request)
qs = qs.filter(placeholder__in=placeholders, language=lang)
plugins = list(qs.order_by('placeholder', 'path'))
fallbacks = defaultdict(list)
# If no plugin is present in the current placeholder we loop in the fallback languages
# and get the first available set of plugins
if (not is_fallback and
not (hasattr(request, 'toolbar') and request.toolbar.edit_mode_active)):
disjoint_placeholders = (ph for ph in placeholders
if all(ph.pk != p.placeholder_id for p in plugins))
for placeholder in disjoint_placeholders:
if get_placeholder_conf("language_fallback", placeholder.slot, template, True):
fallback_languages = get_fallback_languages(lang)

if placeholder.page:
translations = placeholder.page.title_set.filter(language__in=fallback_languages)
placeholders_by_language = {
title.language: [pl for pl in title.placeholders.all() if pl.slot == placeholder.slot]
for title in translations.prefetch_related('placeholders')
}
else:
placeholders_by_language = {}

for fallback_language in get_fallback_languages(lang):
try:
fallback_placeholder = placeholders_by_language[fallback_language][0]
except (KeyError, IndexError):
fallback_placeholder = None

if fallback_placeholder:
assign_plugins(request, (fallback_placeholder,), template, fallback_language, is_fallback=True)
placeholder._plugins_cache = fallback_placeholder._plugins_cache
placeholder._all_plugins_cache = fallback_placeholder._all_plugins_cache
else:
assign_plugins(request, (placeholder,), template, fallback_language, is_fallback=True)

fallback_plugins = placeholder._plugins_cache
if fallback_plugins:
fallbacks[placeholder.pk] += fallback_plugins
break
# These placeholders have no fallback
non_fallback_phs = [ph for ph in placeholders if ph.pk not in fallbacks]
# If no plugin is present in non fallback placeholders, create default plugins if enabled)
# Create default plugins if enabled
if not plugins:
plugins = create_default_plugins(request, non_fallback_phs, template, lang)
plugins = downcast_plugins(plugins, non_fallback_phs, request=request)
plugins = create_default_plugins(request, placeholders, template, lang)
plugins = downcast_plugins(plugins, placeholders, request=request)
# split the plugins up by placeholder
# Plugins should still be sorted by placeholder
plugin_groups = dict((key, list(plugins)) for key, plugins in groupby(plugins, attrgetter('placeholder_id')))
all_plugins_groups = plugin_groups.copy()
for group in plugin_groups:
plugin_groups[group] = build_plugin_tree(plugin_groups[group])
groups = fallbacks.copy()
groups.update(plugin_groups)
for placeholder in placeholders:
# This is all the plugins.
setattr(placeholder, '_all_plugins_cache', all_plugins_groups.get(placeholder.pk, []))
# This one is only the root plugins.
setattr(placeholder, '_plugins_cache', groups.get(placeholder.pk, []))
setattr(placeholder, '_plugins_cache', plugin_groups.get(placeholder.pk, []))


def create_default_plugins(request, placeholders, template, lang):
Expand Down
3833
0