Issue with updating read-only fields in Django admin: flags not saving

I’m working on a Django admin interface where certain fields (specifically, review status flags such as is_pending_review_section_title_en and is_pending_review_section_title_uk) should be marked as read-only in the admin interface, but still be updated programmatically when content changes.

I’ve implemented the logic to dynamically determine the fields as read-only using the get_readonly_fields method inside an inline admin class (SectionInline). Although the fields correctly display as read-only in the interface, the problem arises when I try to update these fields in the save_model method of the PageAdmin class (or even in forms). The flags appear to be set correctly in the code, but they do not persist in the database after saving.

Here is a summary of what I’ve tried:

1.  Marked fields as read-only using get_readonly_fields — This works for the admin UI.
2.  Tried updating the fields programmatically inside save_model in the PageAdmin class and verified the values through logging. The flags are set to True, but after saving, the values in the database remain unchanged.
3.  Commented out form save logic to check if it’s interfering with saving, but the issue persists.
4.  Ensured flags are not present in forms to avoid user interaction.

What could be causing the fields to not save correctly, even though they are updated programmatically in the code? Are there any specific considerations for updating read-only fields in the admin?

class SectionInline(nested_admin.NestedStackedInline):
    model = Section
    extra = 0
    inlines = [ContentInline]
    fields = (
        "section_title_en",
        "section_title_uk",
        "is_pending_review_section_title_en",
        "is_pending_review_section_title_uk",
    )

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = super().get_readonly_fields(request, obj)
        readonly_fields += (
            "is_pending_review_section_title_en",
            "is_pending_review_section_title_uk",
        )
        return readonly_fields

class PageAdmin(nested_admin.NestedModelAdmin):
    list_display = ("menu_title", "slug", "created_at")
    list_filter = ("created_at",)
    search_fields = ("menu_title", "slug")
    inlines = [SectionInline]
    fields = ("menu_title_en", "menu_title_uk", "created_at")

    def save_model(self, request, obj, form, change):
        try:
            page_snapshot = PageSnapshot.objects.get(original_page=obj)
            logger.debug(f"Snapshot exists for Page - {obj.menu_title}")
        except PageSnapshot.DoesNotExist:
            page_snapshot = None

        if not page_snapshot:
            logger.debug(f"Snapshot DOES NOT exist for {obj.menu_title}")
            self.create_snapshot(obj)

        for section in obj.sections.all():
            section_snapshot = None
            if page_snapshot:
                try:
                    section_snapshot = SectionSnapshot.objects.get(
                        original_section=section, page_snapshot=page_snapshot
                    )
                    logger.debug(f"section_snapshot found for {section.section_title}")
                except SectionSnapshot.DoesNotExist:
                    pass

            if section_snapshot:
                if section.section_title_en != section_snapshot.section_title_en:
                    section.is_pending_review_section_title_en = True
                if section.section_title_uk != section_snapshot.section_title_uk:
                    section.is_pending_review_section_title_uk = True
            else:
                if section.section_title_en:
                    logger.debug(f"Setting section_title_en review flag")
                    section.is_pending_review_section_title_en = True
                if section.section_title_uk:
                    section.is_pending_review_section_title_uk = True

            section.save()
            logger.debug(
                f"After saving: section.is_pending_review_section_title_en for {section.section_title_en}: {section.is_pending_review_section_title_en}"
            )

        super().save_model(request, obj, form, change)

    def create_snapshot(self, page_obj):
        if PageSnapshot.objects.filter(original_page=page_obj).exists():
            return

        page_snapshot = PageSnapshot.objects.create(
            original_page=page_obj,
            menu_title_en=page_obj.menu_title_en,
            menu_title_uk=page_obj.menu_title_uk,
            slug=page_obj.slug,
        )

        for section in page_obj.sections.all():
            section_snapshot = SectionSnapshot.objects.create(
                original_section=section,
                page_snapshot=page_snapshot,
                section_title_en=section.section_title_en,
                section_title_uk=section.section_title_uk,
                is_published=section.is_published,
            )

            for content in section.contents.all():
                content_snapshot = None
                if section_snapshot:
                    try:
                        content_snapshot = ContentSnapshot.objects.get(
                            original_content=content, section_snapshot=section_snapshot
                        )
                    except ContentSnapshot.DoesNotExist:
                        pass

                if content_snapshot:
                    if content.text_en != content_snapshot.text_en:
                        content.is_pending_review_text_en = True
                    if content.text_uk != content_snapshot.text_uk:
                        content.is_pending_review_text_uk = True
                    if content.char_en != content_snapshot.char_en:
                        content.is_pending_review_char_en = True
                    if content.char_uk != content_snapshot.char_uk:
                        content.is_pending_review_char_uk = True
                    if content.url != content_snapshot.url:
                        content.is_pending_review_url = True
                    if content.image != content_snapshot.image:
                        content.is_pending_review_image = True
                    if content.file != content_snapshot.file:
                        content.is_pending_review_file = True
                else:
                    if content.text_en:
                        content.is_pending_review_text_en = True
                    if content.text_uk:
                        content.is_pending_review_text_uk = True
                    if content.char_en:
                        content.is_pending_review_char_en = True
                    if content.char_uk:
                        content.is_pending_review_char_uk = True
                    if content.url:
                        content.is_pending_review_url = True
                    if content.image:
                        content.is_pending_review_image = True
                    if content.file:
                        content.is_pending_review_file = True
                content.save()


admin.site.register(Page, PageAdmin)
Back to Top