有没有办法在 Django Admin 弹出窗口(添加、更新、删除)完成时调用 Javascript 函数?

Is there way to call a Javascript function when a Django Admin Popup (Add, Update, Delete) completes?

我有这种情况,我在 Person 字段上绑定了更改事件。

每次 select 值更改时,我们都依赖一些 JavaScript 成为 运行。它当前正在侦听所述元素的更改事件,当用户直接在 select.

提议的菜单中单击一个值时,它工作正常

遗憾的是,当这个 select 通过 Admin Popup 功能填充时,似乎没有为 select 触发更改事件,因为我们的回调没有被执行,即使元素的值居然改了。

是否有其他事件我们可以监听以获得与用户直接从列表中单击值时相同的行为?

正如您在 django source code, change event is not fired when updating a related object. While it is fired on deleting and adding 中看到的那样。

我起初以为这是一个错误,但实际上它是有道理的,因为值没有 necessarily/actually 更新。

但是,如果您需要在您的用例中触发此类事件,这确实是一个问题。我能建议的最好的办法是在你自己的 JS 中覆盖这个行为(当然确保在加载 Django 的 JS 之后调用它):

window.djangoDismissChangeRelatedObjectPopup = window.dismissChangeRelatedObjectPopup;

window.dismissChangeRelatedObjectPopup = function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
    const id = win.name.replace(/^edit_/, '');
    const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
    const selects = $(selectsSelector);
    window.djangoDismissChangeRelatedObjectPopup(win, objId, newRepr, newId);
    selects.trigger('change');
}

因此,只要相关对象更新,就应该触发 change 事件。

如果有人想要添加、更新和删除的完整解决方案:

window.djangoDismissChangeRelatedObjectPopup = window.dismissChangeRelatedObjectPopup;

window.dismissChangeRelatedObjectPopup = function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
    const id = win.name.replace(/^edit_/, '');
    const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
    const selects = $(selectsSelector);
    window.djangoDismissChangeRelatedObjectPopup(win, objId, newRepr, newId);
    selects.trigger('change');
};

window.ORIGINAL_dismissAddRelatedObjectPopup = window.dismissAddRelatedObjectPopup;
window.dismissAddRelatedObjectPopup = function(win, newId, newRepr) {
    ORIGINAL_dismissAddRelatedObjectPopup(win, newId, newRepr);
    const name = win.name;
    const elem = document.getElementById(name);
    $(elem).trigger('change');
};

window.ORIGINAL_dismissDeleteRelatedObjectPopup = window.dismissDeleteRelatedObjectPopup;
window.dismissDeleteRelatedObjectPopup = function(win, objId) {
    ORIGINAL_dismissDeleteRelatedObjectPopup(win, objId);
    const id = win.name.replace(/^delete_/, '');
    const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
    const selects = $(selectsSelector);
    selects.trigger('change');
}