Opened 3 years ago

Closed 3 years ago

#32343 closed New feature (wontfix)

Chained autocomplete_fields in contrib.admin

Reported by: Roman Owned by: nobody
Component: contrib.admin Version: 3.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Roman)

Sometimes querysets for autocomplete_fields should be dependent and selection should be chained.

Imagine there is a model Address with references to Country and City models

class Country(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)


class City(models.Model):
    id = models.AutoField(primary_key=True)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)


class Address(models.Model):
    id = models.AutoField(primary_key=True)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    city = models.ForeignKey(City, on_delete=models.CASCADE, null=True, blank=True)

Also imagine admin form displays a Country drop-down with the list of all countries and a City drop-downwith. A user reasonably expects City drop-down to contain the list of all cities within previously selected country, but not all cities in the entire world.

Unfortunately, when current version of Django calls /admin/app/model/autocomplete no information about current selection in other drop-downs is sent, so there is no way to select cities of a specific country for a new unsaved model. So overriding "def get_search_results(self, request, queryset, search_term)" gives nothing, as required information is not available.

However, a small change to autocomplete.js allowed me to easily implement what I need.

'use strict';
{
    const $ = django.jQuery;
    const init = function($element, options) {
        const settings = $.extend({
            ajax: {
                data: function(params) {
                    var result = {
                        'term': params.term,
                        'page': params.page
                    };

                    $('.admin-autocomplete').each(function(index) {
                        result['selected_' + $(this).attr('name')] = $(this).val(); // Pass selections of all other select2 with request.
                    });

                    return result;
                }
            }
        }, options);
        $element.select2(settings);
    };
...
// the rest is not changed

Now, in "def get_search_results(self, request, queryset, search_term)" I can extract all required information from "request.GET"

I am not sure neither about if all autocomplete selects should be included, nor if all selects should be included. Probably it would be better to introduce some kind of opt-in configuration. Also, I am not sure about "selected_" prefix. I understand that this is not a generic code which should be included in the next version of Django. However, this small change works pretty fine for me, allowing to build much more friendly admin forms. I am ready to present pull request, if maintainers will be so kind to comment on idea in general and point at issues I have missed.

Change History (2)

comment:1 by Roman, 3 years ago

Description: modified (diff)

comment:2 by Carlton Gibson, 3 years ago

Resolution: wontfix
Status: newclosed

Hi Roman. Thanks for the report.

I think this is out-of-scope for us at the moment. It's the sort of thing I've done as a custom widget in the admin (a bit of JS and an JSON endpoint behind it) but I suspect if would involve quite a lot of extra complexity.

If you really want it a proof-of-concept showing the changes involved would help asses the feasibility.

Note: See TracTickets for help on using tickets.
Back to Top