Skip to content

Improve PDF performance - #4425

Open
svenseeberg wants to merge 1 commit into
developfrom
fix/pdf-cache
Open

Improve PDF performance#4425
svenseeberg wants to merge 1 commit into
developfrom
fix/pdf-cache

Conversation

@svenseeberg

Copy link
Copy Markdown
Member
  • Execute compute heavy page fetches only if no PDF exists

* Execute compute heavy page fetches only if no PDF exists

@timobrembeck timobrembeck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, thanks a lot! 🚀

A minor suggestion: the existing tests guard correctness but not the performance goal. A small test using pytest-django's django_assert_num_queries (or asserting the hash-path SQL does not select content) would protect it. Optional, but cheap insurance.

# Build a lightweight queryset with the (large) translation content deferred, so that the
# cache key computation and the existence check below do not load the page contents. The
# full content is only fetched further down if the PDF actually has to be rendered.
pages = pages.prefetch_related(None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This makes GeneratePdfView.prefetch_public_translations = True in cms/views/pages/page_bulk_actions.py:50 dead config — the prefetch lookup is stripped here before the queryset is ever evaluated, so it never executes. If you want to, you could remove that flag in this PR so it doesn't mislead future readers into thinking the bulk view still prefetches translations.

for page in hash_pages:
# add translation id and last_updated to hash key list if they exist
page_translation = page.get_public_translation(language_slug)
if page_translation and not page.archived:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking, pre-existing: page.archived resolves implicitly_archivedget_cached_ancestors(), which runs one get_ancestors() query per page since nothing warms _cached_ancestors here. So the cache-hit path is still O(N) queries even with the content deferred. Also, for the whole-region branch the check is redundant — region.get_pages() already returns non_archived_pages. Might be worth a follow-up issue rather than this PR.

@jonbulz jonbulz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks nice, thanks! I think once @timobrembeck's comments are addressed this is ready to go. 👍

:return: The queryset of content objects
"""
return self.prefetch_translations(
to_attr="prefetched_public_translations",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd prefer to use a different attribute name to avoid confusion. Something like prefetched_public_translations_without_content maybe? I won't die on that hill, though.

@jonbulz jonbulz added this to the Backlog milestone Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants