Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
337 views
in Technique[技术] by (71.8m points)

javascript - Django - Reverse Engineering the Admin site's "Add Foreign Key" button

TL;DR (Short synopsis):

I have recreated the admin "Add" button in my own project. However, when I hit "save" on the parent form, it is not recognizing the new select element.

Whole Story:

I have that functionality working in my own project... almost. I need help figuring out the last step. As it is now, I have a "+" button, I click it, a popup shows up, I add a new object, hit save, popup closes and that new item is now in my select box and selected - just like the admin page. However, when I hit save on this parent form, I get the error that I've selected an item not in the list. Of course, since the page has reloaded, my new item is part of the list and I just hit save again and it works. Of course, I need it to save on the first time!

The basic setup is my Parent model is called System and the foreign key model is called Zone. The Zone model lists how many zones a system has (1 zone,2 zones,10 zones, etc...)

OK, some code:

The "Add" link in the template of the parent form:

<a href="/systems/zones/new/?popup=1" id="add_id_numZones" onclick="return showAddPopup(this);">Add</a>

In my New_Zone view, after saving the new zone, I check if the popup GET variable is 1, if so, return a javascript function. Here's the view:

        ...
        if form.is_valid():
            f = form.save(commit=False)
            pk_value = f.numOfZones
            form.save()
            obj = Zone_Info.objects.get(numOfZones=pk_value)
            if isPopup == "1":
                return HttpResponse('<script>opener.closeAddPopup(window, "%s", "%s");</script>' % (escape(pk_value), escape(obj)))
        ...

And here is my Javascript (largely copied from the admin javascript:

function html_unescape(text) {
// Unescape a string that was escaped using django.utils.html.escape.
    text = text.replace(/&lt;/g, '<');
    text = text.replace(/&gt;/g, '>');
    text = text.replace(/&quot;/g, '"');
    text = text.replace(/&#39;/g, "'");
    text = text.replace(/&amp;/g, '&');
    return text;
}

function windowname_to_id(text) {
    text = text.replace(/__dot__/g, '.');
    text = text.replace(/__dash__/g, '-');
    return text;
}


function showAddPopup(triggeringLink, pWin) {
    var name = triggeringLink.id.replace(/^add_/, '');
    href = triggeringLink.href;
    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
    win.focus();
    return false;
}

function closeAddPopup(win, newID, newRepr) {
    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 took a look at this question and it seems that I am doing precisely the same thing.

Any ideas on how to get that last step of getting the form to recognize the new select element?

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I Figured it Out

The problem was what I was passing to my closeAddPopup javascript function. Essentially, I was passing garbage values.

Here's what I originally had in my New_Zone view (which didn't work):

    ...
    if form.is_valid():
        f = form.save(commit=False)
        pk_value = f.numOfZones
        form.save()
        obj = Zone_Info.objects.get(numOfZones=pk_value)
        if isPopup == "1":
            return HttpResponse('<script>opener.closeAddPopup(window, "%s", "%s");</script>' % (escape(pk_value), escape(obj)))
    ...

It's a pretty stupid mistake on my part (clearly it's late). I was assigning f to the field numOfZones which I thought was the pk and sending that to the script.

Now, the working view looks like this:

       if form.is_valid():
           obj = form.save()
           pk_value = obj.pk
           if "_popup" in request.REQUEST:
               return HttpResponse('<script>opener.closeAddPopup(window, "%s", "%s");</script>' % (escape(pk_value), escape(obj)))

Anyway... thanks to... well, Stackoverflow. I don't think I would have solved the problem without posting the question and rereading my code on stackoverflow.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...