8000 chore: [Backport] Improve pagecontent caching in page admin (esp. pag… · django-cms/django-cms@842f347 · GitHub
[go: up one dir, main page]

Skip to content

Commit 842f347

Browse files
fsbraunGithub Release Action
andauthored
chore: [Backport] Improve pagecontent caching in page admin (esp. page tree) (#8002) (#8004)
* chore: Improve pagecontent caching in page admin (esp. page tree) (#8002) * Fix: Separate cache and access methods for page admin to hold available page contents * Fix typo * Remove `EmptyPageContent` from admin_content_cache * Optimize queryset for pagetree --------- Co-authored-by: Github Release Action <info@django-cms.org> * Add back template file * Undo permission check change (error when merging) * Undo more merge errors * Fix: missing warning import * Clarify an isort/ruff dispute * Add write permission * Add admin cache to cms_toolbars.py * fix typo in cms_toolbars.py --------- Co-authored-by: Github Release Action <info@django-cms.org>
1 parent 1719b9a commit 842f347

File tree

7 files changed

+62
-60
lines changed

7 files changed

+62
-60
lines changed

.github/workflows/releases.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
branches:
66
- release/*
77

8+
permissions:
9+
pull-requests: write
10+
811
jobs:
912
comment:
1013
runs-on: ubuntu-latest

cms/admin/pageadmin.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ def delete_model(self, request, obj):
450450

451451
# Delete all of the pages titles contents
452452
ct_page_content = ContentType.objects.get_for_model(PageContent)
453-
page_content_objs = PageContent.objects.filter(page__in=cms_pages)
453+
page_content_objs = PageContent.admin_manager.filter(page__in=cms_pages).values_list('pk', flat=True)
454454
placeholders = Placeholder.objects.filter(
455455
content_type=ct_page_content,
456456
object_id__in=page_content_objs,
@@ -720,7 +720,7 @@ def copy_page(self, request, page_id):
720720

721721
def edit_title_fields(self, request, page_id, language):
722722
page = self.get_object(request, object_id=page_id)
723-
translation = page.get_content_obj(language, fallback=False)
723+
translation = page.get_admin_content(language)
724724

725725
if not self.has_change_permission(request, obj=page):
726726
return HttpResponseForbidden(_("You do not have permission to edit this page"))
@@ -822,7 +822,7 @@ def get_object(self, request, object_id, from_field=None):
822822
obj = super().get_object(request, object_id, from_field)
823823

824824
if obj:
825-
obj.page.page_content_cache[obj.language] = obj
825+
obj.page.admin_content_cache[obj.language] = obj
826826
return obj
827827

828828
def get_admin_url(self, action, *args):
@@ -1417,13 +1417,7 @@ def get_tree_rows(self, request, pages, language, depth=1,
14171417
user_can_change_advanced = page_permissions.user_can_change_page_advanced_settings
14181418

14191419
def render_page_row(page):
1420-
page.page_content_cache = {trans.language: trans for trans in page.filtered_translations}
1421-
1422-
for _language in languages:
1423-
# EmptyPageContent is used to prevent the cms from trying
1424-
# to find a translation in the database
1425-
page.page_content_cache.setdefault(_language, EmptyPageContent(language=_language, page=page))
1426-
1420+
page.admin_content_cache = {trans.language: trans for trans in page.filtered_translations}
14271421
has_move_page_permission = page_permissions.user_can_move_page(request.user, page, site=site)
14281422

14291423
if permissions_on and not has_move_page_permission:
@@ -1437,7 +1431,7 @@ def render_page_row(page):
14371431
'opts': self.opts,
14381432
'site': site,
14391433
'page': page,
1440-
'page_content': page.get_content_obj(language, fallback=False), # Show specific language
1434+
'page_content': page.get_admin_content(language),
14411435
'node': page.node,
14421436
'ancestors': [node.item for node in page.node.get_cached_ancestors()],
14431437
'descendants': [node.item for node in page.node.get_cached_descendants()],

cms/cms_toolbars.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def get_page_content(self):
391391
# Toolbar object already set (e.g., in edit or preview mode)
392392
return self.obj
393393
# Get from db
394-
page_content = self.page.get_content_obj(language=self.current_lang, fallback=False)
394+
page_content = self.page.get_admin_content(language=self.current_lang, fallback=False)
395395
return page_content or None
396396

397397
def has_page_change_permission(self):

cms/models/pagemodel.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from logging import getLogger
23
from os.path import join
34

@@ -11,19 +12,16 @@
1112
from django.utils.encoding import force_str
1213
from django.utils.functional import cached_property
1314
from django.utils.timezone import now
14-
from django.utils.translation import (
15-
get_language,
16-
gettext_lazy as _,
17-
override as force_language,
18-
)
15+
from django.utils.translation import get_language, gettext_lazy as _, override as force_language
1916
from treebeard.mp_tree import MP_Node
2017

2118
from cms import constants
2219
from cms.exceptions import LanguageError
2320
from cms.models.managers import PageManager, PageNodeManager, PageUrlManager
2421
from cms.utils import i18n
22+
from cms.utils.compat.warnings import RemovedInDjangoCMS43Warning
2523
from cms.utils.conf import get_cms_setting
26-
from cms.utils.i18n import get_current_language
24+
from cms.utils.i18n import get_current_language, get_fallback_languages
2725
from cms.utils.page import get_clean_username
2826
from menus.menu_pool import menu_pool
2927

@@ -198,6 +196,7 @@ def __init__(self, *args, **kwargs):
198196
super().__init__(*args, **kwargs)
199197
self.urls_cache = {}
200198
self.page_content_cache = {}
199+
self.admin_content_cache = {}
201200

202201
def __str__(self):
203202
try:
@@ -222,6 +221,7 @@ def _clear_node_cache(self):
222221
def _clear_internal_cache(self):
223222
self.urls_cache = {}
224223
self.page_content_cache = {}
224+
self.admin_content_cache = {}
225225
self._clear_node_cache()
226226

227227
if hasattr(self, '_prefetched_objects_cache'):
@@ -734,9 +734,38 @@ def get_published_languages(self):
734734
return self.get_languages()
735735

736736
def set_translations_cache(self):
737+
warnings.warn(
738+
"Method `set_translations_cache` is deprecated. Use `get_content_obj` instead. "
739+
"For admin views use `set_admin_content_cache` instead.",
740+
RemovedInDjangoCMS43Warning,
741+
stacklevel=2,
742+
)
737743
for translation in self.pagecontent_set.all():
738744
self.page_content_cache.setdefault(translation.language, translation)
739745

746+
def set_admin_content_cache(self):
747+
for translation in self.pagecontent_set(manager="admin_manager").current_content().all():
748+
self.admin_content_cache.setdefault(translation.language, translation)
749+
750+
def get_admin_content(self, language, fallback=False):
751+
from cms.models.contentmodels import EmptyPageContent
752+
753+
if not self.admin_content_cache:
754+
self.set_admin_content_cache()
755+
page_content = self.admin_content_cache.get(language, EmptyPageContent(language=language, page=self))
756+
if not page_content and fallback:
757+
for lang in i18n.get_fallback_languages(language):
758+
page_content = self.admin_content_cache.get(lang)
759+
if page_content:
760+
return page_content
761+
page_content = EmptyPageContent(language=language, page=self)
762+
if fallback == "force":
763+
# Try any page content object
764+
for item in self.admin_content_cache.values():
765+
if item:
766+
return item
767+
return page_content
768+
740769
def get_path_for_slug(self, slug, language):
741770
if self.is_home:
742771
return ''
@@ -1001,9 +1030,7 @@ def has_publish_permission(self, user):
10011030
return user_can_publish_page(user, page=self)
10021031

10031032
def has_advanced_settings_permission(self, user):
1004-
from cms.utils.page_permissions import (
1005-
user_can_change_page_advanced_settings,
1006-
)
1033+
from cms.utils.page_permissions import user_can_change_page_advanced_settings
10071034
return user_can_change_page_advanced_settings(user, page=self)
10081035

10091036
def has_change_permissions_permission(self, user):

cms/templatetags/cms_admin.py

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class GetAdminUrlForLanguage(AsTag):
3535

3636
def get_value(self, context, page, language):
3737
if language in page.get_languages():
38-
page_content = page.pagecontent_set(manager="admin_manager").current_content(language=language).first()
38+
page_content = page.get_admin_content(language)
3939
if page_content:
4040
return admin_reverse('cms_pagecontent_change', args=[page_content.pk])
4141
admin_url = admin_reverse('cms_pagecontent_add')
@@ -93,38 +93,13 @@ def show_admin_menu_for_pages(context, descendants, depth=1):
9393

9494
@register.simple_tag(takes_context=False)
9595
def get_page_display_name(cms_page):
96-
from cms.models import EmptyPageContent
9796
language = get_language()
9897

99-
if not cms_page.page_content_cache:
100-
cms_page.set_translations_cache()
101-
102-
fallback_found = False
103-
if not cms_page.page_content_cache.get(language):
104-
fallback_found = True
105-
fallback_langs = i18n.get_fallback_languages(language)
106-
for lang in fallback_langs:
107-
if cms_page.page_content_cache.get(lang):
108-
language = lang
109-
break
110-
else:
111-
language = None
112-
for lang, item in cms_page.page_content_cache.items():
113-
if not isinstance(item, EmptyPageContent):
114-
language = lang
115-
break
116-
else:
117-
return _("Empty")
118-
page_content = cms_page.page_content_cache[language]
119-
if page_content.title:
120-
title = page_content.title
121-
elif page_content.page_title:
122-
title = page_content.page_title
123-
elif page_content.menu_title:
124-
title = page_content.menu_title
125-
else:
98+
page_content = cms_page.get_admin_content(language, fallback="force")
99+
title = page_content.title or page_content.page_title or page_content.menu_title
100+
if not title:
126101
title = cms_page.get_slug(language)
127-
return mark_safe(f"<em>{title} ({language})</em>") if fallback_found else title
102+
return title if page_content.language == language else mark_safe(f"<em>{title} ({page_content.language})</em>")
128103

129104

130105
class TreePublishRow(Tag):
@@ -156,7 +131,7 @@ def render_tag(self, context, page, language):
156131
)
157132
return render_to_string("admin/cms/page/tree/indicator_legend.html", context.flatten())
158133

159-
page_content = page.page_content_cache.get(language)
134+
page_content = page.get_admin_content(language)
160135
cls, text = self.get_indicator(page_content)
161136
return mark_safe(
162137
'<span class="cms-hover-tooltip cms-hover-tooltip-left cms-hover-tooltip-delay %s" '
@@ -180,7 +155,7 @@ class TreePublishRowMenu(AsTag):
180155
)
181156

182157
def get_value(self, context, page, language):
183-
page_content = page.page_content_cache.get(language)
158+
page_content = page.get_admin_content(language)
184159
if context.get("has_change_permission", False):
185160
page_content_admin_class = admin.site._registry[PageContent]
186161
template, publish_menu_items = page_content_admin_class.get_indicator_menu(

cms/tests/test_log_entries.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,15 @@ def test_log_for_delete_translation(self):
211211
When a pages translation is deleted a log entry is created.
212212
"""
213213
with self.login_user_context(self._admin_user):
214-
page = create_page("page_a", "nav_playground.html", "en")
215-
create_page_content(language='de', title="other title %s" % page.get_title('en'), page=page)
214+
title_en = "page_a"
215+
page = create_page(title_en, "nav_playground.html", "en")
216+
create_page_content(language='de', title="other title %s" % title_en, page=page)
216217
endpoint = self.get_page_delete_translation_uri('en', page)
217218
post_data = {'post': 'yes', 'language': 'en'}
218219

219220
response = self.client.post(endpoint, post_data)
221+
page.page_content_cache = {} # Reset cache of local object after translation is deleted
222+
220223
# Test that the end point is valid
221224
self.assertEqual(response.status_code, 302)
222225
# Test that the log count is correct

cms/tests/test_templatetags.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ def test_get_admin_tree_title(self):
7979
}
8080
with self.settings(CMS_LANGUAGES=languages):
8181
with force_language('fr'):
82-
page.page_content_cache = {'en': PageContent(page_title="test2", title="test2")}
82+
page.admin_content_cache = {'en': PageContent(page_title="test2", title="test2", language="en")}
8383
self.assertEqual('<em>test2 (en)</em>', force_str(get_page_display_name(page)))
84-
page.page_content_cache = {'en': PageContent(page_title="test2")}
84+
page.admin_content_cache = {'en': PageContent(page_title="test2", language="en")}
8585
self.assertEqual('<em>test2 (en)</em>', force_str(get_page_display_name(page)))
86-
page.page_content_cache = {'en': PageContent(menu_title="menu test2")}
86+
page.admin_content_cache = {'en': PageContent(menu_title="menu test2", language="en")}
8787
self.assertEqual('<em>menu test2 (en)</em>', force_str(get_page_display_name(page)))
88-
page.page_content_cache = {'en': PageContent()}
88+
page.admin_content_cache = {'en': PageContent(language="en")}
8989
page.urls_cache = {'en': PageUrl(slug='slug-test2')}
9090
self.assertEqual('<em>slug-test2 (en)</em>', force_str(get_page_display_name(page)))
91-
page.page_content_cache = {'en': PageContent(), 'fr': EmptyPageContent('fr')}
91+
page.admin_content_cache = {'en': PageContent(language="en"), 'fr': EmptyPageContent('fr')}
9292
self.assertEqual('<em>slug-test2 (en)</em>', force_str(get_page_display_name(page)))
9393

9494
def test_get_site_id_from_nothing(self):

0 commit comments

Comments
 (0)
0