Search code examples
djangodjango-modelsdjango-formsdjango-viewsdjango-autocomplete-light

Django-autocomplete-light filtering and displaying results based on two fields


I'm a newbie to django-autocomplete-light. I'm trying to implement something like the "global navigation autocomplete" (https://django-autocomplete-light.readthedocs.org/en/docs_rewrite/navigation.html#a-simple-view) however this shall be used to navigate between patients.

Here's the problem:

  • Let's assume there's a Patient called John Smith.
  • If I type "John" or "Smith" the right autocomplete appears and I can choose the Patient.
  • However - If I type "John S" or any other combination involving typing in both the name and surname the autocomplete becomes empty...
  • I tried to filter the model differently, e.g. splitting q into "name" and "surname" and filtering the model with Q on the relevant field but that also doesn't help...

Which part am I missing? Is is the filtering or autocomplete which cannot cope with filtering based on two fields from a given model?

Here's a part of my simple model (please note that the url 'patient_detail' exists and works fine, just not pasting it here):

class Patient(models.Model):
    name = models.CharField(max_length = 30, blank=False)
    surname = models.CharField(max_length = 70, blank=False)

    def __unicode__(self):
        return '%s %s' % (self.name, self.surname)

    def get_absolute_url(self):
        return reverse('patient_detail', kwargs = {'pk':self.pk})

Than, I'm doing this (similar to what's described in the docs) in my view, where q get's all I'm typing into the field:

def pacjent_autocomplete(request, template_name = 'reception_autocomplete.html'):
   q = request.GET.get('q','').strip()
   queries = {}
   queries['patients'] = Patient.objects.filter(Q(name__icontains=q) | Q(surname__icontains = q))
   return render(request, template_name, queries)

The reception_autocomplete.html file looks like this:

<span class="separator">Patients</span>
{% for patient in patients %}
<a class="block choice" href="{{patient.get_absolute_url}}">{{patient}}</a>
{% endfor %}

In my main view I have a field which is the target of this script:

   <script type="text/javascript">
    $(document).ready(function() {
        $('#id_new_patient').yourlabsAutocomplete({
            url: "{% url 'reception_autocomplete' %}",
            choiceSelector: 'a',
        }).input.bind('selectChoice', function(e, choice, autocomplete) {
            document.location.href = choice.attr('href');
        });
    });
    </script>

Your help on how to show the right patient for input like "John Sm" is much appreciated!


Solution

  • That's not a problem with autocomplete_light, but with your Django query:

    Patient.objects.filter(Q(name__icontains=q) | Q(surname__icontains = q))
    

    That would select all Patient which have surname__icontains="John S" or name__icontains="John S". That's why you get no result. Check how django-cities-light does search: https://github.com/yourlabs/django-cities-light/blob/stable/3.x.x/cities_light/abstract_models.py

    Or use django-haystack and implement a haystack backend, or redis...

    Or, fallback to raw sql in choices_for_request to filter against a concatenation of name and surname.