我可以从 wagtail 页面按钮触发 python 中的操作吗
Can I trigger an action in python from a wagtail page button
在 wagtail 中,可以使用 register_page_listing_buttons
挂钩向页面添加按钮。
但是,这些示例只是将您带到您选择的url。
在我的例子中,我有一个 ProjectPage
模型,我有一个函数 regenerate_project_geo_features()
(目前是一个管理命令,尽管它不需要)。
我想要一个按钮,可以在页面列表中,也可以在页面编辑视图本身中,用于触发 python 中的操作。
是否可以修改那个钩子,或者使用另一个我不知道的钩子来简单地调用 python 中的函数? (最好使用一些参数,如 ProjectPage
id
来告诉函数它在哪个页面上被调用)?
实现此目的的一种方法是使用 Javascript,本质上是向被单击的 link/button 添加一个侦听器。然后,这将触发对您管理的 URL 的某种 POST 请求,这将执行 'work' 的重新生成。
本质上,由于这是一个网络框架 (Django),所有内容都应被视为一堆具有 request/response 处理的视图(页面)。
方法
- 创建自定义管理员 URL 并查看(有意仅通过管理员访问)
- 此视图基本上可以处理
POST
个请求,当使用页面 ID 调用时,它将完成您需要的工作。
- link 现在只是有意变成一个按钮,点击它会调用 Javascript
fetch
(发生在后台)
- 然后您可以更新视图以在后台对页面执行任何操作。
- 注意:示例很粗糙,没有任何错误处理或消息给用户(即当他们点击它时,他们不知道它是否有 worked/completed 等)。
示例代码
- 这将在您的
wagtail_hooks.py
文件中
from django.conf.urls import url
from django.http import HttpResponse
from django.urls import reverse
from django.utils.html import format_html
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from wagtail.admin.widgets import PageListingButton
from wagtail.core import hooks
@csrf_exempt # not recommended - but helpful to get to the POC stage
@require_http_methods(["POST"])
def regnerate_admin_features(request):
page_pk = request.GET.get('id', '')
# do whatever you need here with the PK to process the action
return HttpResponse(
"Success/Error handling goes here",
content_type="text/plain")
@hooks.register('register_admin_urls')
def urlconf_time():
return [
url(r'^regenerate_geo_features/$', regnerate_admin_features, name='regenerate_geo_features'),
]
@hooks.register('register_page_listing_buttons')
def page_listing_buttons(page, page_perms, is_parent=False):
attrs = {
'data-id': page.pk, # note - may want to html encode this for a more secure implementation
}
yield PageListingButton(
'Regenerate Geo Features',
reverse('regenerate_geo_features'),
attrs=attrs,
classes=["action-regenerate-geo-features"],
priority=100
)
@hooks.register('insert_global_admin_js')
def global_admin_js():
# note - this is very rough, no error, loading or sucess messaging
# reminder - using format_html means all `{` must be written as `{{`
return format_html(
"""
<script>
const onClickHandler = function(event) {{
event.preventDefault(); // ensure the hash does not change
const url = event.target.href + '?id=' + event.target.dataset.id;
console.log('button clicked - about to POST to URL:', url);
fetch(url, {{
method: 'POST', // or 'PUT'
}})
}};
window.addEventListener('DOMContentLoaded', function(event) {{
const actionButtons = Array.from(document.getElementsByClassName('action-regenerate-geo-features'));
actionButtons.forEach(function(element) {{
element.addEventListener('click', onClickHandler);
}});
}});
</script>
""",
)
在 wagtail 中,可以使用 register_page_listing_buttons
挂钩向页面添加按钮。
但是,这些示例只是将您带到您选择的url。
在我的例子中,我有一个 ProjectPage
模型,我有一个函数 regenerate_project_geo_features()
(目前是一个管理命令,尽管它不需要)。
我想要一个按钮,可以在页面列表中,也可以在页面编辑视图本身中,用于触发 python 中的操作。
是否可以修改那个钩子,或者使用另一个我不知道的钩子来简单地调用 python 中的函数? (最好使用一些参数,如 ProjectPage
id
来告诉函数它在哪个页面上被调用)?
实现此目的的一种方法是使用 Javascript,本质上是向被单击的 link/button 添加一个侦听器。然后,这将触发对您管理的 URL 的某种 POST 请求,这将执行 'work' 的重新生成。
本质上,由于这是一个网络框架 (Django),所有内容都应被视为一堆具有 request/response 处理的视图(页面)。
方法
- 创建自定义管理员 URL 并查看(有意仅通过管理员访问)
- 此视图基本上可以处理
POST
个请求,当使用页面 ID 调用时,它将完成您需要的工作。 - link 现在只是有意变成一个按钮,点击它会调用 Javascript
fetch
(发生在后台) - 然后您可以更新视图以在后台对页面执行任何操作。
- 注意:示例很粗糙,没有任何错误处理或消息给用户(即当他们点击它时,他们不知道它是否有 worked/completed 等)。
示例代码
- 这将在您的
wagtail_hooks.py
文件中
from django.conf.urls import url
from django.http import HttpResponse
from django.urls import reverse
from django.utils.html import format_html
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from wagtail.admin.widgets import PageListingButton
from wagtail.core import hooks
@csrf_exempt # not recommended - but helpful to get to the POC stage
@require_http_methods(["POST"])
def regnerate_admin_features(request):
page_pk = request.GET.get('id', '')
# do whatever you need here with the PK to process the action
return HttpResponse(
"Success/Error handling goes here",
content_type="text/plain")
@hooks.register('register_admin_urls')
def urlconf_time():
return [
url(r'^regenerate_geo_features/$', regnerate_admin_features, name='regenerate_geo_features'),
]
@hooks.register('register_page_listing_buttons')
def page_listing_buttons(page, page_perms, is_parent=False):
attrs = {
'data-id': page.pk, # note - may want to html encode this for a more secure implementation
}
yield PageListingButton(
'Regenerate Geo Features',
reverse('regenerate_geo_features'),
attrs=attrs,
classes=["action-regenerate-geo-features"],
priority=100
)
@hooks.register('insert_global_admin_js')
def global_admin_js():
# note - this is very rough, no error, loading or sucess messaging
# reminder - using format_html means all `{` must be written as `{{`
return format_html(
"""
<script>
const onClickHandler = function(event) {{
event.preventDefault(); // ensure the hash does not change
const url = event.target.href + '?id=' + event.target.dataset.id;
console.log('button clicked - about to POST to URL:', url);
fetch(url, {{
method: 'POST', // or 'PUT'
}})
}};
window.addEventListener('DOMContentLoaded', function(event) {{
const actionButtons = Array.from(document.getElementsByClassName('action-regenerate-geo-features'));
actionButtons.forEach(function(element) {{
element.addEventListener('click', onClickHandler);
}});
}});
</script>
""",
)