Могу ли я вызвать действие в python от кнопки страницы трясогузки - PullRequest
1 голос
/ 16 января 2020

В трясогузке можно добавить кнопку на страницу, используя крючок register_page_listing_buttons.

Однако эти примеры просто приводят вас к URL по вашему выбору.

В моем случае у меня есть модель ProjectPage, и у меня есть функция regenerate_project_geo_features() (в настоящее время это команда управления, хотя это не обязательно).

Я хочу кнопка, либо в списке страниц, либо в самом представлении редактирования страницы, которое можно использовать для запуска действия в python.

Можно ли адаптировать этот хук или использовать другой, который я не в курсе, просто вызвать функцию в python? (желательно с некоторым параметром, например ProjectPage id, чтобы сообщить функции, на какой странице она была вызвана)?

1 Ответ

1 голос
/ 19 января 2020

Способ сделать это можно было бы с помощью Javascript, по существу добавив слушателя к нажатой ссылке / кнопке. После этого будет инициирован POST-запрос какого-либо URL-адреса, которым вы управляете, который будет выполнять «работу» регенерации.

По сути, поскольку это веб-фреймворк (Django), все должно рассматриваться как группа представлений (страниц) с обработкой запросов / ответов.

Подход

  • Создание настраиваемого URL-адреса администратора и представления (преднамеренно доступного только через администратора)
  • Это view будет в основном обрабатывать POST запросов, и при вызове с идентификатором страницы он будет выполнять ту работу, которая вам требуется.
  • Ссылка теперь становится только кнопкой для цели, щелкнув по ней, вы вызовете Javascript fetch (происходит в фоновом режиме)
  • Затем вы можете обновить свое представление, чтобы сделать все, что вы хотите, на странице в фоновом режиме.
  • Примечание: пример грубый и не обрабатывает ошибки и не отправляет сообщения пользователю (ie. когда они щелкают по нему, они не знают, сработало ли оно / выполнено и т. д. c).

Пример кода

  • Это woul буду в вашем 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>
        """,
    )

...