Django Admin - RelatedObjectLookups - 它如何刷新并设置父窗口上的选择?

发布于 2024-11-02 13:39:32 字数 2895 浏览 4 评论 0原文

我希望我的一个表单能够像管理页面一样工作,所以我想我应该查看代码并看看它是如何工作的。

具体来说,我希望用户能够单击选择列表旁边的“+”图标,然后进入管理页面的弹出表单以添加新项目。

当他们在那里输入新项目时,我希望该新项目出现在选择框中并被选择(就像此功能在管理页面上的工作方式一样)。

我将管理 js 库复制到我自己的模板中,并且使链接调用相同的 JS 函数,并且弹出窗口确实正确打开,但是在保存新对象后,弹出窗口变为空白而不是关闭,并且在父页面。

这是我在页面中放入的内容:

...
<td>
    <div class="fieldWrapper">
        <select name="form-0-plasmid" id="id_form-0-plasmid">
        ...
        </select>
        <a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_plasmid" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
    </div>
</td>
...

我尝试单步执行管理表单上的 JavaScript 以查看它是如何工作的,但我没有看到任何可以关闭窗口或填充父窗口选择的内容。

预先感谢您的任何帮助。

更新3

当运行dismissAddAnotherPopup时,我收到这个javascript错误

"SelectBox is not defined"

,它指向dismissAddAnotherPopup中的这一行

SelectBox.add_to_cache(toId, o);

我以为我知道Javascript,但我不知道该变量应该来自哪里:- (

更新 2

一切似乎都正常触发。在弹出窗口上单击“保存”后,我得到一个空白页面。这是该页面的源代码:

<script type="text/javascript">opener.dismissAddAnotherPopup(window, "9", "CMV_flex_myr_GENE1_._._WPRE_BGH");</script>

所以看来这个 javascript 没有被 相关代码,所以唯一的问题是该

更新

代码没有触发,或者触发不正确。

这是 Daniel 提到的 :

...
        if request.POST.has_key("_popup"):
            return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
                # escape() calls force_unicode.
                (escape(pk_value), escapejs(obj)))
...

/media/admin/js/admin/RelatedObjectLookups.js:

function dismissAddAnotherPopup(win, newId, newRepr) {
    // newId and newRepr are expected to have previously been escaped by
    // django.utils.html.escape.
    newId = html_unescape(newId);
    newRepr = html_unescape(newRepr);
    var name = windowname_to_id(win.name);
    var elem = document.getElementById(name);
    if (elem) {
        if (elem.nodeName == 'SELECT') {
            var o = new Option(newRepr, newId);
            elem.options[elem.options.length] = o;
            o.selected = true;
        } else if (elem.nodeName == 'INPUT') {
            if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
                elem.value += ',' + newId;
            } else {
                elem.value = newId;
            }
        }
    } else {
        var toId = name + "_to";
        elem = document.getElementById(toId);
        var o = new Option(newRepr, newId);
        SelectBox.add_to_cache(toId, o);
        SelectBox.redisplay(toId);
    }
    win.close();
}

I want one of my forms to work just like the admin page does so I figured I'd look in the code and see how it works.

Specifically I want the user to be able to click a "+" icon next to a select list and be taken to the admin page's popup form to add a new item.

When they enter a new item there, I want that new item to appear in the select box, and be selected (Just like how this feature works on the admin pages).

I copied the admin js libraries into my own template, and I made my link call the same JS function and the popup windows does open correctly, but after I save a new object the popup window goes blank instead of closing, and nothing happens on the parent page.

Here's what I put in my page:

...
<td>
    <div class="fieldWrapper">
        <select name="form-0-plasmid" id="id_form-0-plasmid">
        ...
        </select>
        <a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_plasmid" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
    </div>
</td>
...

I tried stepping through the javascript on the admin form to see how it's working, but I'm not seeing anything that would close the window or populate the parent window's select.

Thanks in advance for any help.

Update 3

I'm getting this javascript error when dismissAddAnotherPopup is run

"SelectBox is not defined"

Which is pointing to this line in dismissAddAnotherPopup

SelectBox.add_to_cache(toId, o);

I thought I knew Javascript, but I don't see where that variable is supposed to come from :-(

Update 2

Everything seems to be firing properly. After I click save on the popup window I get a blank page. This is the source of that page:

<script type="text/javascript">opener.dismissAddAnotherPopup(window, "9", "CMV_flex_myr_GENE1_._._WPRE_BGH");</script>

So it would seem that this javascript isn't being executed or is failing.

Update

Here is the relevant code that Daniel mentioned. So the only problem is that this code either isn't firing, or is firing incorrectly.

django/contrib/admin/options.py:

...
        if request.POST.has_key("_popup"):
            return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
                # escape() calls force_unicode.
                (escape(pk_value), escapejs(obj)))
...

/media/admin/js/admin/RelatedObjectLookups.js:

function dismissAddAnotherPopup(win, newId, newRepr) {
    // newId and newRepr are expected to have previously been escaped by
    // django.utils.html.escape.
    newId = html_unescape(newId);
    newRepr = html_unescape(newRepr);
    var name = windowname_to_id(win.name);
    var elem = document.getElementById(name);
    if (elem) {
        if (elem.nodeName == 'SELECT') {
            var o = new Option(newRepr, newId);
            elem.options[elem.options.length] = o;
            o.selected = true;
        } else if (elem.nodeName == 'INPUT') {
            if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
                elem.value += ',' + newId;
            } else {
                elem.value = newId;
            }
        }
    } else {
        var toId = name + "_to";
        elem = document.getElementById(toId);
        var o = new Option(newRepr, newId);
        SelectBox.add_to_cache(toId, o);
        SelectBox.redisplay(toId);
    }
    win.close();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黒涩兲箜 2024-11-09 13:39:32

好的,JavaScript 只是使用启动元素的 id 属性来标识要更新的选择字段。 (从开头删除“add_”后)。

所以我只是更改了链接的 id 属性以匹配模板中选择元素的 id:

<a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_{{field.html_name}}" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>

哇,我希望这已经记录在某处!我为此浪费了几个小时。

(有关其工作原理的更多技术细节,请参阅我对问题的更新。)

Ok, the javascript simply uses the id attribute of the launching element to identify the select field to update. (after removing 'add_' from the beginig).

So I simply changed the link's id attribute to match the select element's id in my template:

<a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_{{field.html_name}}" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>

Wow I wish this had been documented somewhere! I lost a few hours on this.

(See my updates to the question for more technical details on how it all works.)

赢得她心 2024-11-09 13:39:32

诀窍 - 实际上有点黑客攻击 - 是当您在管理中的弹出窗口中单击“保存”时会发生的情况。

如果您查看 django.contrib.options.ModelAdmin 中的 response_add 代码,您会发现当您在弹出窗口中保存项目时,管理员会返回一个 HttpResponse仅由一段 Javascript 组成。该 JS 调用父窗口中的 dismissAddAnotherPopup 函数,该函数关闭弹出窗口并相应地设置表单值。

将此功能复制到您自己的应用程序中相当简单。

更新后编辑 如果管理 javascript 不起作用,通常是因为它依赖于 jsi18n 代码 - 您通过 URL(不是静态路径)包含该代码:

<script type="text/javascript" src="/admin/jsi18n/"></script>

The trick - and it's a bit of a hack, actually - is what happens when you click save on the popup in the admin.

If you look at the code of response_add in django.contrib.options.ModelAdmin, you'll see that when you save an item in the popup, the admin returns an HttpResponse consisting solely of a piece of Javascript. This JS calls the dismissAddAnotherPopup function in the parent window, which closes the popup and sets the form value appropriately.

It's fairly simple to copy this functionality into your own app.

Edited after updates If admin javascript doesn't work, it's usually because it has a dependency on the jsi18n code - which you include via a URL (not a static path):

<script type="text/javascript" src="/admin/jsi18n/"></script>
一抹微笑 2024-11-09 13:39:32

我在刷新父窗口中的选择时遇到了同样的问题,我按照此解决了 doc

现在一切工作正常

编辑1:

我试图使用 Select2 使选择变得漂亮,单选工作正常,多选由于某种原因让我头疼,没有更新父级中的信息形式。

以前有人尝试过这个吗?

I was having the same problem refreshing the select in the parent window, and I solved following this doc

Everything is working fine now

Edit 1:

I was trying to use Select2 to make the select pretty, the single select works fine, the multiple select is giving me headaches for some reason is not updating the info in the parent form.

Anyone tried this before?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文