I was finally able to resolve the problem by using the approach laid out in this post, that is adding querystring keys to the referrer URL because select2 does not accept modification of the request URL after being initialized.
I am also adding other information about the dog being edited such as its id and birth year to further filter the queryset (A dog cannot be its own parent or have a parent younger than self, mothers can only be females...).
//this get passes to the select2:opening event listener
function expand_ajax_location_search($, fieldId) {
if (!$) {
$ = django.jQuery;
}
var pageURL = $(location).attr("href");
var match = pageURL.match(/\/.*\/(\d+)\/change/);
return `&birth_year=${$('#id_birth_year').val()}&dog_id=${match[1]}&father_cb=${$('#father-cb').prop( "checked" )}&mother_cb=${$('#mother-cb').prop( "checked" )}`
}
Finally doing the filtering on the server side was challenging because the dog admin is normally filtered by kennel so that each kennel owner can only edit their dogs, although the checkbox allows them to use dogs of other kennels as parents. The challenge in the get_search_results method was to unfilter the queryset when the box is checked, which cannot be done, so create a new one before passing it to super().get_search_results.
Also the base get_search_results method seems to traverse all the relations even if they are not needed resulting in over 100 queries, so using select_related on all relation produces just one query.
def get_search_results(self, request, queryset, search_term):
if request.is_ajax and '/autocomplete/' in request.path and request.GET.get('model_name') == 'dog':
url = urllib.parse.urlparse(request.headers['Referer'])
referer = url.path
# (parse_qs results are lists)
qs = urllib.parse.parse_qs(url.query)
if request.GET.get('field_name') == 'father':
if qs.get('father_cb')[0] == 'true':
# default is filetered by kennel so need new qs
queryset = Dog.objects.select_related(
'kenn', 'img', 'father', 'mother', 'breeder').order_by('name')
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
queryset = queryset.exclude(
sex='F').exclude(id=qs.get('dog_id')[0])
elif request.GET.get('field_name') == 'mother':
if qs.get('mother_cb')[0] == 'true':
# default is filetered by kennel so need new qs
queryset = Dog.objects.select_related(
'kenn', 'img', 'father', 'mother', 'breeder').order_by('name')
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
queryset = queryset.exclude(
sex='M').exclude(id=qs.get('dog_id')[0])
birth_year = qs.get('birth_year')[0]
if birth_year:
queryset = queryset.exclude(birth_year__gt=birth_year)
else:
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
return queryset, use_distinct