Skip to content

feat: maintain placeholder order from template declaration#91

Closed
metaforx wants to merge 3 commits intodjango-cms:mainfrom
metaforx:feat/placeholder-order
Closed

feat: maintain placeholder order from template declaration#91
metaforx wants to merge 3 commits intodjango-cms:mainfrom
metaforx:feat/placeholder-order

Conversation

@metaforx
Copy link
Collaborator

@metaforx metaforx commented Dec 19, 2025

  • Keep the declaration order in the template similar to the output in the frontend.
  • When we reuse placeholders in templates and add others, the order of placeholders is mixed up, likely because of sorting by creation and not by position in the template.

I could fix this behavior with the suggested PR. There might be a cleaner solution.

Summary by Sourcery

Enhancements:

  • Adjust page content serialization to build the placeholders list based on the template-declared placeholders, ensuring consistent frontend ordering.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 19, 2025

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adjusts PageContentSerializer to preserve the placeholder order as declared in the template instead of relying on queryset ordering, by mapping existing placeholders to the template-declared placeholders and serializing them in that order.

Sequence diagram for PageContentSerializer placeholder ordering

sequenceDiagram
  actor FrontendClient
  participant APIView
  participant PageContentSerializer
  participant PageContent
  participant PlaceholderSerializer

  FrontendClient->>APIView: GET page_content
  APIView->>PageContentSerializer: instantiate with context(request)
  APIView->>PageContentSerializer: to_representation(page_content)

  PageContentSerializer->>PageContent: placeholders.all()
  PageContent-->>PageContentSerializer: placeholders_queryset
  PageContentSerializer->>PageContentSerializer: placeholder_map = {slot: placeholder}

  PageContentSerializer->>PageContentSerializer: declared_placeholders = get_declared_placeholders_for_obj(page_content)
  PageContentSerializer->>PageContentSerializer: placeholders = [placeholder_map[declared.slot] for declared in declared_placeholders if declared.slot in placeholder_map]

  PageContentSerializer->>PageContentSerializer: data = get_base_representation(page_content)
  PageContentSerializer->>PlaceholderSerializer: serialize(placeholders, many=True)
  PlaceholderSerializer-->>PageContentSerializer: placeholders_data
  PageContentSerializer-->>APIView: data with ordered placeholders
  APIView-->>FrontendClient: JSON response
Loading

Class diagram for updated PageContentSerializer placeholder handling

classDiagram

  class BasePageSerializer

  class BasePageContentMixin

  class PageContentSerializer {
    +placeholders PlaceholderSerializer[]
    +request any
    +to_representation(page_content PageContent) dict
  }

  class PageContent {
    +placeholders Placeholder[]
  }

  class Placeholder {
    +slot str
  }

  class DeclaredPlaceholder {
    +slot str
  }

  class PlaceholderSerializer {
    +many bool
  }

  PageContentSerializer --|> BasePageSerializer
  PageContentSerializer ..|> BasePageContentMixin

  PageContent "1" --> "*" Placeholder : placeholders
  PageContentSerializer --> PageContent : serializes
  PageContentSerializer --> PlaceholderSerializer : uses
  PageContentSerializer --> DeclaredPlaceholder : orders_by
Loading

File-Level Changes

Change Details Files
Preserve placeholder ordering in serialized page content to match template declaration order.
  • Add a class docstring to PageContentSerializer explaining that placeholders are serialized in template declaration order.
  • Replace collection of declared placeholder slots with full declared placeholder objects from the template.
  • Build a mapping from existing page placeholders to their slot names for efficient lookup.
  • Construct the placeholders list by iterating over declared placeholders in order and selecting corresponding existing placeholders via the map, filtering out slots without an existing placeholder.
  • Reuse PlaceholderSerializer on the reordered placeholder list so the API output reflects template order rather than database creation order.
djangocms_rest/serializers/pages.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@metaforx metaforx requested a review from fsbraun December 19, 2025 11:09
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link

codecov bot commented Dec 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.98%. Comparing base (7f76592) to head (cf83eaf).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #91   +/-   ##
=======================================
  Coverage   91.98%   91.98%           
=======================================
  Files          19       19           
  Lines         886      886           
  Branches      100      100           
=======================================
  Hits          815      815           
  Misses         44       44           
  Partials       27       27           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fsbraun
Copy link
Member

fsbraun commented Dec 21, 2025

@metaforx This PR seems to be empty?

@metaforx
Copy link
Collaborator Author

metaforx commented Dec 21, 2025

@metaforx This PR seems to be empty?

This is strange. I see 2 commits. Pages.py contains the changes. I check why containing commit is not respected.

@fsbraun
Copy link
Member

fsbraun commented Dec 21, 2025

Maybe these commits have already been merged?
image

@fsbraun
Copy link
Member

fsbraun commented Dec 21, 2025

Are these changes contained in #83 ?

@metaforx
Copy link
Collaborator Author

metaforx commented Jan 9, 2026

@

@metaforx This PR seems to be empty?

This is strange. I see 2 commits. Pages.py contains the changes. I check why containing commit is not respected.

@fsbraun Yes. This is right. I think the reason was that my fork was not in sync with djangocms-rest main branch. :(
I will close PR.

@metaforx metaforx closed this Jan 9, 2026
@metaforx metaforx deleted the feat/placeholder-order branch January 9, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments