Skip to content

Commit

Permalink
Allow prefetched version objects for page contents
Browse files Browse the repository at this point in the history
  • Loading branch information
fsbraun committed Jul 22, 2024
1 parent 778254f commit 7d84b85
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 30 deletions.
31 changes: 16 additions & 15 deletions djangocms_versioning/cms_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from cms.app_base import CMSAppConfig, CMSAppExtension
from cms.extensions.models import BaseExtension
from cms.models import PageContent, Placeholder
from cms.utils import get_language_from_request
from cms.utils.i18n import get_language_list, get_language_tuple
from cms.utils.plugins import copy_plugins_to_placeholder
from cms.utils.urlutils import admin_reverse
Expand All @@ -14,6 +13,7 @@
ObjectDoesNotExist,
PermissionDenied,
)
from django.db.models import Prefetch
from django.http import (
HttpResponse,
HttpResponseBadRequest,
Expand All @@ -23,7 +23,7 @@
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _

from . import indicators, versionables
from . import indicators
from .admin import VersioningAdminMixin
from .constants import INDICATOR_DESCRIPTIONS
from .datastructures import BaseVersionableItem, VersionableItem
Expand Down Expand Up @@ -284,18 +284,8 @@ def get_readonly_fields(self, request, obj=None):
return fields

def get_queryset(self, request):
urls = ("cms_pagecontent_get_tree",)
queryset = super().get_queryset(request)
if request.resolver_match.url_name in urls:
versionable = versionables.for_content(queryset.model)

# TODO: Improve the grouping filters to use anything defined in the
# apps versioning config extra_grouping_fields
grouping_filters = {}
if "language" in versionable.extra_grouping_fields:
grouping_filters["language"] = get_language_from_request(request)

return queryset.filter(pk__in=versionable.distinct_groupers(**grouping_filters))
queryset = super().get_queryset(request)\
.prefetch_related(Prefetch("versions", to_attr="prefetched_versions"))
return queryset

# CAVEAT:
Expand Down Expand Up @@ -361,7 +351,18 @@ def get_indicator_menu(cls, request, page_content):
"""Get the indicator menu for PageContent object taking into account the
currently available versions"""
menu_template = "admin/cms/page/tree/indicator_menu.html"
status = page_content.content_indicator()
if hasattr(page_content.page, "filtered_translations") and hasattr(page_content, "prefetched_versions"):
# get_tree has prefetched versions
versions = sorted(
[content.prefetched_versions[0] for content in page_content.page.filtered_translations],
key=lambda version: -version.pk,
)
for content in page_content.page.filtered_translations:
content.__dict__["content"] = content
status = page_content.content_indicator(versions)
else:
# No prefetched versions available, get them ourselves
status = page_content.content_indicator()
if not status or status == "empty": # pragma: no cover
return super().get_indicator_menu(request, page_content)
versions = page_content._version # Cache from .content_indicator()
Expand Down
16 changes: 10 additions & 6 deletions djangocms_versioning/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,11 @@ def content_is_unlocked_for_user(content: models.Model, user: settings.AUTH_USER
"""Check if lock doesn't exist or object is locked to provided user.
"""
try:
return version_is_unlocked_for_user(content.versions.first(), user)
if hasattr(content, "prefetched_versions"):
version = content.prefetched_versions[0]
else:
version = content.versions.first()
return version_is_unlocked_for_user(version, user)
except AttributeError:
return True

Expand Down Expand Up @@ -425,16 +429,16 @@ def send_email(


def get_latest_draft_version(version):
"""Get latest draft version of version object and caches it
"""
"""Get latest draft version of version object and caches it in the
content object"""
from djangocms_versioning.constants import DRAFT
from djangocms_versioning.models import Version

if not hasattr(version, "_latest_draft_version"):
if not hasattr(version.content, "_latest_draft_version"):
drafts = (
Version.objects
.filter_by_content_grouping_values(version.content)
.filter(state=DRAFT)
)
version._latest_draft_version = drafts.first()
return version._latest_draft_version
version.content._latest_draft_version = drafts.first()
return version.content._latest_draft_version
16 changes: 12 additions & 4 deletions djangocms_versioning/indicators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import typing

from cms.utils.urlutils import admin_reverse
from django.contrib.auth import get_permission_codename
from django.db import models
from django.utils.http import urlencode
from django.utils.translation import gettext_lazy as _

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


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

if not content_obj:
return None # pragma: no cover
elif not hasattr(content_obj, "_indicator_status"):
versions = Version.objects.filter_by_content_grouping_values(
content_obj
).order_by("-pk")
if versions is None:
# Get all versions for the content object if not available
versions = Version.objects.filter_by_content_grouping_values(
content_obj
).order_by("-pk")
version_states = dict(VERSION_STATES)
signature = {
version.state: version
Expand Down
4 changes: 2 additions & 2 deletions djangocms_versioning/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def filter_by_grouping_values(self, versionable, **kwargs):

def filter_by_content_grouping_values(self, content):
"""Returns a list of Version objects for grouping values taken
from provided content object. In other words:
it uses the content instance property values as filter parameters
from provided content object. In other words:
it uses the content instance property values as filter parameters
"""
versionable = versionables.for_content(content)
content_objects = versionable.for_content_grouping_values(content)
Expand Down
15 changes: 12 additions & 3 deletions djangocms_versioning/templatetags/djangocms_versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def url_version_list(content):

@register.filter
def url_publish_version(content, user):
version = content.versions.first()
if hasattr(content, "prefetched_versions"):
version = content.prefetched_versions[0]
else:
version = content.versions.first()
if version:
if version.check_publish.as_bool(user) and version.can_be_published():
proxy_model = versionables.for_content(content).version_model_proxy
Expand All @@ -25,7 +28,10 @@ def url_publish_version(content, user):

@register.filter
def url_new_draft(content, user):
version = content.versions.first()
if hasattr(content, "prefetched_versions"):
version = content.prefetched_versions[0]
else:
version = content.versions.first()
if version:
if version.state == constants.PUBLISHED:
proxy_model = versionables.for_content(content).version_model_proxy
Expand All @@ -37,7 +43,10 @@ def url_new_draft(content, user):

@register.filter
def url_revert_version(content, user):
version = content.versions.first()
if hasattr(content, "prefetched_versions"):
version = content.prefetched_versions[0]
else:
version = content.versions.first()
if version:
if version.check_revert.as_bool(user):
proxy_model = versionables.for_content(content).version_model_proxy
Expand Down

0 comments on commit 7d84b85

Please sign in to comment.