1. Germano Gabbianelli
  2. django-autocomplete
  3. Issues
Issue #22 open

In formfield_for_dbfield, don't skip adding the RelatedFieldWrapper (add link)

Fabian Büchler
created an issue

In {{{django.contrib.admin.options.BaseModelAdmin.formfield_for_dbfield}}}, which you are overriding in {{{autocomplete.admin.AutocompleteAdmin}}}, all {{{ForeignKey}}} and {{{ManyToMany}}} field widgets are usually wrapped with the {{{django.contrib.admin.widgets.RelatedFieldWidgetWrapper}}}, which adds an "add another link" (plus icon) to such fields, if the user is has the add permission for the model in question.

Your {{{formfield_to_dbfield}}} would look like follows, to make this work again:

{{{ def formfield_for_dbfield(self, db_field, **kwargs): request = kwargs.get("request", None)

    if db_field.name in self.autocomplete_fields:
        ac_id = self.autocomplete_fields[db_field.name]
        formfield = self.autocomplete_formfield(
            ac_id, db_field.formfield, **kwargs)
    elif (self.autocomplete_autoconfigure and
          db_field in self.autocomplete_view.settings):
        formfield = self.autocomplete_formfield(db_field, **kwargs)
    else:
        formfield = super(AutocompleteAdmin, self).formfield_for_dbfield(
            db_field, **kwargs)

    if (isinstance(db_field, (models.ForeignKey, models.ManyToManyField)) and
        formfield and db_field.name not in self.raw_id_fields):
        related_modeladmin = self.admin_site._registry.get(
            db_field.rel.to)
        can_add_related = bool(related_modeladmin and
            related_modeladmin.has_add_permission(request))
        formfield.widget = admin.widgets.RelatedFieldWidgetWrapper(
            formfield.widget, db_field.rel, self.admin_site,
            can_add_related=can_add_related)

    return formfield

}}}

Regards, Fabian

Comments (9)

  1. Fabian Büchler reporter

    I just realized, that when using the add-another button, saving and closing the popup fills the autocomplete field with the ID of the newly created object. This needs to be changed so that the hidden field recieves the ID and the visible field is filled with a title/name,...

    Basically the function involved is dismissAddAnotherPopup() in contrib/admin/media/js/admin/RelatedObjectLookups.js

    Actually, I'm not quite sure what is the best way to make this work. Do you have a good idea?

    Regards, Fabian

  2. Fabian Büchler reporter

    I've researched the problem mentioned above a bit, and found it not trivial to solve. One solution would be to overwrite the dismissAddAnotherPopup JavaScript function defined in RelatedObjectLookups.js like follows in your jquery_autocomplete.js file:

    if (typeof(dismissAddAnotherPopup) != 'undefined') {
        var original_dismissAddAnotherPopup = dismissAddAnotherPopup;
        dismissAddAnotherPopup = function (win, newId, newRepr) {
            (function($){
                // 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 = $('#'+name);
                
                // append 
                if (elem.length > 0 && elem.is('input:text')) {
                    elem.val(newRepr);
                    // ### needs to handle ManyToMany fields, too
                }
                else {
                    original_dismissAddAnotherPopup(win, newId, newRepr);
                }
                
                // fake select event of autocomplete result list
                var ui = new Object();
                ui.item = new Object();
                ui.item.id = newId;
                ui.item.value = newRepr;
                elem.autocomplete('option', 'select')(
                    $.Event('autocompleteselect'), ui);
                
                win.close();
            }(django.jQuery));
        }
    }
    

    This seems a bit freaky, but it seems to work. The code above only handles foreignkey fields, no manytomany fields.

    A better solution would certainly be to rewrite te RelatedObjectLookups.js into a jQuery plugin architecture which could allow to pass a custom popup-dismiss function.

    Regards, Fabian

  3. Germano Gabbianelli repo owner

    If you make a patch (with "hg export" or "hg diff") people interested in this feature would be able to use it, and I could consider pushing it into the repo.

    Maybe rewriting RelatedObjectLookup.js with jQuery is a planned thing since they switched to jQuery in the admin site.

  4. Fabian Büchler reporter

    Hej Germano,

    it took me a while to find the time to do this, but finally I've created a patch queue to add my changes as promised: https://bitbucket.org/fabianbuechler/django-autocomplete_related-field-wrapper

    If you prefer that I fork your repository and send you a pull request, that's fine, too. Just thought using MQ would be the right way.

    There are two things missing in my implementation: the JS fix for the dismissAddAnotherPopup function lacks of handling for ManyToMany fields and I have not tested the patch, because I don't really know how to do this as I've just installed django-autocomplete in one project via PyPi...

    Guess I could use mercurialrecipe to install my own version of django-autocomplete including patches... what do you think?

  5. Germano Gabbianelli repo owner

    That's great!

    If you prefer that I fork your repository and send you a pull request, that's fine, too. Just thought using MQ would be the right way.

    Using MQ is just perfect, so you can already start using your patch.

    I had a few problems trying to qclone your repo with ssh (using regular http I succeeded). I will try your code as soon as possible, however if you could add what you think is missing it will probably be committed sooner.

    and I have not tested the patch, because I don't really know how to do this

    Running the test suite is now as simple as typing "tox" from the django-autocomplete root dir. (Writing more tests is an highest priority since there aren't so many)

    If you have anything else to ask feel free to send me a private message.

  6. Log in to comment