Skip to content

Commit ac763d9

Browse files
authored
Allow prefetched version objects for page contents (#418)
1 parent 9b8abd5 commit ac763d9

File tree

5 files changed

+52
-30
lines changed

5 files changed

+52
-30
lines changed

djangocms_versioning/cms_config.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from cms.app_base import CMSAppConfig, CMSAppExtension
44
from cms.extensions.models import BaseExtension
55
from cms.models import PageContent, Placeholder
6-
from cms.utils import get_language_from_request
76
from cms.utils.i18n import get_language_list, get_language_tuple
87
from cms.utils.plugins import copy_plugins_to_placeholder
98
from cms.utils.urlutils import admin_reverse
@@ -14,6 +13,7 @@
1413
ObjectDoesNotExist,
1514
PermissionDenied,
1615
)
16+
from django.db.models import Prefetch
1717
from django.http import (
1818
HttpResponse,
1919
HttpResponseBadRequest,
@@ -23,7 +23,7 @@
2323
from django.utils.functional import cached_property
2424
from django.utils.translation import gettext_lazy as _
2525

26-
from . import indicators, versionables
26+
from . import indicators
2727
from .admin import VersioningAdminMixin
2828
from .constants import INDICATOR_DESCRIPTIONS
2929
from .datastructures import BaseVersionableItem, VersionableItem
@@ -284,18 +284,8 @@ def get_readonly_fields(self, request, obj=None):
284284
return fields
285285

286286
def get_queryset(self, request):
287-
urls = ("cms_pagecontent_get_tree",)
288-
queryset = super().get_queryset(request)
289-
if request.resolver_match.url_name in urls:
290-
versionable = versionables.for_content(queryset.model)
291-
292-
# TODO: Improve the grouping filters to use anything defined in the
293-
# apps versioning config extra_grouping_fields
294-
grouping_filters = {}
295-
if "language" in versionable.extra_grouping_fields:
296-
grouping_filters["language"] = get_language_from_request(request)
297-
298-
return queryset.filter(pk__in=versionable.distinct_groupers(**grouping_filters))
287+
queryset = super().get_queryset(request)\
288+
.prefetch_related(Prefetch("versions", to_attr="prefetched_versions"))
299289
return queryset
300290

301291
# CAVEAT:
@@ -361,7 +351,18 @@ def get_indicator_menu(cls, request, page_content):
361351
"""Get the indicator menu for PageContent object taking into account the
362352
currently available versions"""
363353
menu_template = "admin/cms/page/tree/indicator_menu.html"
364-
status = page_content.content_indicator()
354+
if hasattr(page_content.page, "filtered_translations") and hasattr(page_content, "prefetched_versions"):
355+
# get_tree has prefetched versions
356+
versions = sorted(
357+
[content.prefetched_versions[0] for content in page_content.page.filtered_translations],
358+
key=lambda version: -version.pk,
359+
)
360+
for content in page_content.page.filtered_translations:
361+
content.__dict__["content"] = content
362+
status = page_content.content_indicator(versions)
363+
else:
364+
# No prefetched versions available, get them ourselves
365+
status = page_content.content_indicator()
365366
if not status or status == "empty": # pragma: no cover
366367
return super().get_indicator_menu(request, page_content)
367368
versions = page_content._version # Cache from .content_indicator()

djangocms_versioning/helpers.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,11 @@ def content_is_unlocked_for_user(content: models.Model, user: settings.AUTH_USER
387387
"""Check if lock doesn't exist or object is locked to provided user.
388388
"""
389389
try:
390-
return version_is_unlocked_for_user(content.versions.first(), user)
390+
if hasattr(content, "prefetched_versions"):
391+
version = content.prefetched_versions[0]
392+
else:
393+
version = content.versions.first()
394+
return version_is_unlocked_for_user(version, user)
391395
except AttributeError:
392396
return True
393397

@@ -425,16 +429,16 @@ def send_email(
425429

426430

427431
def get_latest_draft_version(version):
428-
"""Get latest draft version of version object and caches it
429-
"""
432+
"""Get latest draft version of version object and caches it in the
433+
content object"""
430434
from djangocms_versioning.constants import DRAFT
431435
from djangocms_versioning.models import Version
432436

433-
if not hasattr(version, "_latest_draft_version"):
437+
if not hasattr(version.content, "_latest_draft_version"):
434438
drafts = (
435439
Version.objects
436440
.filter_by_content_grouping_values(version.content)
437441
.filter(state=DRAFT)
438442
)
439-
version._latest_draft_version = drafts.first()
440-
return version._latest_draft_version
443+
version.content._latest_draft_version = drafts.first()
444+
return version.content._latest_draft_version

djangocms_versioning/indicators.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import typing
2+
13
from cms.utils.urlutils import admin_reverse
24
from django.contrib.auth import get_permission_codename
5+
from django.db import models
36
from django.utils.http import urlencode
47
from django.utils.translation import gettext_lazy as _
58

@@ -87,16 +90,21 @@ def content_indicator_menu(request, status, versions, back=""):
8790
return menu
8891

8992

90-
def content_indicator(content_obj):
93+
def content_indicator(
94+
content_obj: models.Model,
95+
versions: typing.Optional[list[Version]] = None
96+
) -> typing.Optional[str]:
9197
"""Translates available versions into status to be reflected by the indicator.
9298
Function caches the result in the page_content object"""
9399

94100
if not content_obj:
95101
return None # pragma: no cover
96102
elif not hasattr(content_obj, "_indicator_status"):
97-
versions = Version.objects.filter_by_content_grouping_values(
98-
content_obj
99-
).order_by("-pk")
103+
if versions is None:
104+
# Get all versions for the content object if not available
105+
versions = Version.objects.filter_by_content_grouping_values(
106+
content_obj
107+
).order_by("-pk")
100108
version_states = dict(VERSION_STATES)
101109
signature = {
102110
version.state: version

djangocms_versioning/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ def filter_by_grouping_values(self, versionable, **kwargs):
7474

7575
def filter_by_content_grouping_values(self, content):
7676
"""Returns a list of Version objects for grouping values taken
77-
from provided content object. In other words:
78-
it uses the content instance property values as filter parameters
77+
from provided content object. In other words:
78+
it uses the content instance property values as filter parameters
7979
"""
8080
versionable = versionables.for_content(content)
8181
content_objects = versionable.for_content_grouping_values(content)

djangocms_versioning/templatetags/djangocms_versioning.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ def url_version_list(content):
1313

1414
@register.filter
1515
def url_publish_version(content, user):
16-
version = content.versions.first()
16+
if hasattr(content, "prefetched_versions"):
17+
version = content.prefetched_versions[0]
18+
else:
19+
version = content.versions.first()
1720
if version:
1821
if version.check_publish.as_bool(user) and version.can_be_published():
1922
proxy_model = versionables.for_content(content).version_model_proxy
@@ -25,7 +28,10 @@ def url_publish_version(content, user):
2528

2629
@register.filter
2730
def url_new_draft(content, user):
28-
version = content.versions.first()
31+
if hasattr(content, "prefetched_versions"):
32+
version = content.prefetched_versions[0]
33+
else:
34+
version = content.versions.first()
2935
if version:
3036
if version.state == constants.PUBLISHED:
3137
proxy_model = versionables.for_content(content).version_model_proxy
@@ -37,7 +43,10 @@ def url_new_draft(content, user):
3743

3844
@register.filter
3945
def url_revert_version(content, user):
40-
version = content.versions.first()
46+
if hasattr(content, "prefetched_versions"):
47+
version = content.prefetched_versions[0]
48+
else:
49+
version = content.versions.first()
4150
if version:
4251
if version.check_revert.as_bool(user):
4352
proxy_model = versionables.for_content(content).version_model_proxy

0 commit comments

Comments
 (0)