Reputation: 5502
In wagtail, it's possible to add a button to a page, using the register_page_listing_buttons
hook.
However, those examples simply take you to a url of your choosing.
In my case, I have a ProjectPage
model, and I have a function regenerate_project_geo_features()
(presently a management command, although it doesn't need to be).
I want a button, either in the page listing or in the page edit view itself, which can be used to trigger an action in python.
Is it possible to adapt that hook, or use another that I'm not aware of, to simply call a function in python? (preferably with some parameter like a ProjectPage
id
to tell the function what page it was called on)?
Upvotes: 2
Views: 1019
Reputation: 5196
A way to do this would be with Javascript, essentially adding a listener to the link/button being clicked. This would then trigger a POST request of some kind to a URL you manage which would do the 'work' of the regeneration.
Essentially as this is a web framework (Django), everything should be considered as a bunch of views (pages) with request/response handling.
POST
requests and when called with the id of the page, it will do the work you require.fetch
(happens in the background)wagtail_hooks.py
filefrom 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>
""",
)
Upvotes: 2