Save method of custom WagtailAdminPageForm called multiple times, even on page load: How to trigger custom save action only once on save?

huangapple go评论59阅读模式
英文:

Save method of custom WagtailAdminPageForm called multiple times, even on page load: How to trigger custom save action only once on save?

问题

I want to automatically generate field content based on another, editor-filled field for a wagtail page model on page save.

我想在页面保存时根据另一个由编辑器填充的字段自动生成字段内容。

英文:

I want to automatically generate field content based on another, editor-filled field for a wagtail page model on page save.

I followed the wagtail docs and I am able to populate and save a field programmatically on page save/publish:

from wagtail.models import Page
from wagtail.admin.forms import WagtailAdminPageForm

class TestPageForm(WagtailAdminPageForm):
    def clean(self):
        cleaned_data = super().clean()
        print("-> called TestPageForm.clean()")
        return cleaned_data

    def save(self, commit=True):
        print(f"1 {commit=}")
        page = super().save(commit=False)
        print(f"2 {commit=}")
        print("-> called TestPageForm.save()")
        # process something, save result to instance field, e.g.:
        # page.pdf_cover_image = get_cover_image(self.cleaned_data["pdf"])

        if commit:
            print(f"{commit=}: calling page.save()")
            page.save()

        return page


class TestPage(Page):
    base_form_class = TestPageForm

But the forms clean() and save() methods are called multiple times, even when I did not expect them to be called at all:

Edit page

Requesting the page instance via wagtail backend ("Edit page"):

http://127.0.0.1:8000/admin/pages/139/edit/

[10/May/2023 10:35:37] "GET /admin/pages/139/edit/ HTTP/1.1" 200 71082
[...assets...]
-> called TestPageForm.clean()
1 commit=False
2 commit=False
-> called TestPageForm.save()
[10/May/2023 10:35:37] "GET /admin/pages/139/edit/preview/?in_preview_panel=true&mode= HTTP/1.1" 200 0
[10/May/2023 10:35:37] "DELETE /admin/pages/139/edit/preview/ HTTP/1.1" 200 17
-> called TestPageForm.clean()
[10/May/2023 10:35:37] "POST /admin/pages/139/edit/preview/ HTTP/1.1" 200 40
-> called TestPageForm.clean()
1 commit=False
-> called TestPageForm.clean()
2 commit=False
-> called TestPageForm.save()
1 commit=False
2 commit=False
-> called TestPageForm.save()
[10/May/2023 10:35:37] "GET /admin/pages/139/edit/preview/?in_preview_panel=true&mode= HTTP/1.1" 200 0

Save page

[10/May/2023 10:35:37] "GET /admin/pages/139/edit/preview/?in_preview_panel=true&mode= HTTP/1.1" 200 0
-> called TestPageForm.clean()
1 commit=False
2 commit=False
-> called TestPageForm.save()
[10/May/2023 10:38:10] "POST /admin/pages/139/edit/ HTTP/1.1" 302 0
[10/May/2023 10:38:10] "GET /admin/pages/8/ HTTP/1.1" 200 45356

So on page save the forms clean() and save() methods are called only once - but as commit is always False I'm not able to differentiate between all these clean-and-save-calls...

So how do I trigger a custom save()-action which will only be called once and only on page save()?

答案1

得分: 0

如果您使用的是 Wagtail 4+,那么无论预览面板是否可见,都会调用clean/save(这在我看来不应该发生,但目前是这样的)。

由于这个原因,我不得不将一些繁重的字段计算代码从clean中移出,当我升级时。我选择使用创建/编辑后的钩子

@hooks.register("after_edit_page")
@hooks.register("after_create_page")
def get_something(request, page):
    if page.specific_class == SomePage:
        try:
            page.something = calculate_something()
            if page.has_unpublished_changes:
                page.save_revision()
            else:
                page.save()
        except Exception as e:
            print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")       
            messages.error(request, _('There was a problem generating the something'))

这仅在编辑器点击保存/保存草稿时触发,并且他们需要这样做才能查看对此计算产生影响的更改的任何渲染效果。

英文:

If you're on Wagtail 4+ then the clean/save is being called by the preview panel regardless of whether it's visible (this shouldn't happen IMO but that's how it is for now).

I have some heavy field calculating code I needed to shift out of clean when I upgraded due to this. I went with the after create/edit hooks:

@hooks.register("after_edit_page")
@hooks.register("after_create_page")
def get_something(request, page):
    if page.specific_class == SomePage:
        try:
            page.something = calculate_something()
            if page.has_unpublished_changes:
                page.save_revision()
            else:
                page.save()
        except Exception as e:
            print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")       
            messages.error(request, _('There was a problem generating the something'))

This will only get triggered when the editor clicks on save/save draft, and they will need to do this to see any rendered effect of changes made affecting this calculation in the live preview.

huangapple
  • 本文由 发表于 2023年5月10日 15:10:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76215780.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定