0

I am building a web application that requires searching for a specific user record by entering one of two attributes: first name OR last name. Eventually there will be two more search attributes, but currently having problems with having two autocomplete-light drop-downs in the same template. The problem is that only the second drop-down is working as expected.

Below are the relevant code sections (with irrelevant code removed). This approach is not "DRY" but my priority is to have a working implementation before optimization/refactoring.

forms.py

class StudentChoiceFieldLN(forms.Form):

    students = forms.ModelChoiceField(
        queryset=Student.objects.all().order_by("last_name"),
        widget=autocomplete.ModelSelect2(url='student-ln-autocomplete'),
    )

    def __init__(self, *args, **kwargs):
        super(StudentChoiceField, self).__init__(*args, **kwargs)
        # without the next line label_from_instance does NOT work
        self.fields['students'].queryset = Student.objects.all().order_by("last_name")
        self.fields['students'].label_from_instance = lambda obj: "%s %s" % (obj.last_name, obj.first_name)

class StudentChoiceFieldFN(forms.Form):

    students = forms.ModelChoiceField(
        queryset=Student.objects.all().order_by("first_name"),
        widget=autocomplete.ModelSelect2(url='student-fn-autocomplete'),
    )

    def __init__(self, *args, **kwargs):
        super(StudentChoiceFieldFN, self).__init__(*args, **kwargs)
        # without the next line label_from_instance does NOT work
        self.fields['students'].queryset = Student.objects.all().order_by("first_name")
        self.fields['students'].label_from_instance = lambda obj: "%s %s" % (obj.last_name, obj.first_name)

views.py

class StudentLNAutoComplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):

        qs = Student.objects.all()

        if self.q:
            qs = qs.filter(last_name__istartswith=self.q)

        return qs



class StudentFNAutoComplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):

        qs = Student.objects.all()

        if self.q:
            qs = qs.filter(first_name__istartswith=self.q)

        return qs


def index(request):
    students_choice_ln = StudentChoiceFieldLN()
    students_choice_fn = StudentChoiceFieldFN()
    
    context = {
        'students_choice_ln': students_choice_ln,
        'students_choice_fn': students_choice_fn,
        'selected_student': None
    }

    return render(request, 'awards/index.html', context)

urls.py

from awards.views import StudentLNAutoComplete
from awards.views import StudentFNAutoComplete

urlpatterns = [
    ...
    path('student-ln-autocomplete/', StudentLNAutoComplete.as_view(), name='student-ln-autocomplete'),
    path('student-fn-autocomplete/', StudentFNAutoComplete.as_view(), name='student-fn-autocomplete'),
    ...
]

awards/index.html

Note below the position of the {{ students_choice_fn.media }} declaration. Based on recommendations found in other related stack overflow posts, I tried changing the location of this declaration to different parts of the template. I think the problem is related to the rendering of the relevant css/javascript for autocomplete-light, somehow causing the first field to not work correctly.

{% extends "base.html" %}

{% block content %}

<body>

{{ students_choice_fn.media }}

<div class="container">

<div class="row">
  <div class="col-md-6">

    <form method=POST action="/awards/select">
        {% csrf_token %}
        
        {{ students_choice_ln }}
        {{ students_choice_fn }}
        
        <input type="submit" value="select">
    </form>


    <br>
    <h4> {{ selected_student.first_name }} {{ selected_student.last_name }} </h4>

    {% if selected_student %}
        ....
    {% endif %}

  </div>
  <div class="col-md-6">
      ....
  </div>
</div>

</div>
</body>

{% endblock %}

The problem is that only the second autocomplete dropdown is working, and the first dropdown displays as an empty non-interactive dropdown. See screenshot here:

enter image description here

These are two threads with overlapping concepts, but I was not able to resolve my problem:

How to use django-autocomplete-light on form with multiple charfields

https://github.com/yourlabs/django-autocomplete-light/issues/814

I appreciate your help!

1 Answers1

0

Since the two forms are in the same form tag, the same id was assigned to them in the rendered html.

<form method=POST action="/awards/select">
    {% csrf_token %}
    
    {{ students_choice_ln }}
    {{ students_choice_fn }}
    
    <input type="submit" value="select">
</form>

After following the instructions documented here (https://docs.djangoproject.com/en/dev/ref/forms/api/#prefixes-for-forms), the dropdowns are working as expected. It could be that the matching ids prevented the javascript/css links from working correctly.