2

So I have this search form: [Doctor][Specialty][City]

This is the form in HTML:

          <form data-provide="validation" data-disable="true" class="input-glass mt-7" method='POST' action='annuaire/'>
            {% csrf_token %}
              <div class="row">
                <div class="col-md-4">
                  <div class="input-group">
                    <div class="input-group-prepend">
                      <span class="input-group-text"><i class="ti-search mt-1"></i></span>
                    </div>
                    <input type="text" class="form-control" placeholder="Doctor's Name" name="kw_name">
                  </div>
                </div>
                <div class="col-md-4">
                  <div class="input-group">
                    <div class="input-group-prepend">
                      <span class="input-group-text"><i class="ti-search mt-1"></i></span>
                    </div>
                      <select class="form-control" name="kw_specialty">
                        <option value="" disabled selected>Specialty</option>
                        {% for spec in specialties %}
                          <option>{{ spec }}</option>
                        {% endfor %}
                      </select>
                  </div>
                </div>

                <div class="col-md-4">
                  <div class="input-group">
                    <div class="input-group-prepend">
                      <span class="input-group-text"><i class="ti-search mt-1"></i></span>
                    </div>
                      <select class="form-control" name="kw_city">
                        <option value="" disabled selected>City</option>
                        {% for city in cities %}
                          <option>{{ city }}</option>
                        {% endfor %}
                      </select>
                  </div>
                </div>   
              </div>
              <div class="row mt-2">
                <div class="col-md-12">
                  <button class="btn btn-lg btn-block btn-outline-light" type="submit" name="search_btn">Search</button>
                </div>
              </div>
            </form>

Before I talk about my view.py content, I would like to mention my problem first: The search form has many cases, and the users don't have to fill all three filters. But if they leave the text input empty, the results will be ALL. I want the search function to ignore the text field if it's empty (only consider it if it has a value in it). Also, if the 2 dropdowns are Null (or None) the function gives an error. Anyways my desired outcome would be to give 3 different choices to choose from, and if someone uses more than one attributes, they all have to be true, if a selection is empty, it should be ignored.

Here is my views.py file:

def search(request):
    val_name = request.POST.get('kw_name')
    val_city = request.POST.get('kw_city')
    val_specialty = request.POST.get('kw_specialty')
    if val_city is None:
        val_city = ''
    if val_specialty is None:
        val_specialty = ''

    if 'search_btn' in request.POST:
        if val_city is None:
            if val_name is not None:
                doctors = Doctor.objects.filter(Q(user__first_name__icontains=val_name) | 
                                                Q(user__last_name__icontains=val_name) & 
                                                Q(specialty__title__icontains=val_specialty))
            else:
                doctors = Doctor.objects.filter(Q(user__first_name__icontains=val_name) | 
                                                Q(user__last_name__icontains=val_name) & 
                                                Q(specialty__title__icontains=val_specialty))
        elif val_specialty is None:
            doctors = Doctor.objects.filter(Q(user__first_name__icontains=val_name) | 
                                            Q(user__last_name__icontains=val_name) & 
                                            Q(city__title__icontains=val_city))


    elif 'closest_btn' in request.POST:
        # deleted because not related to the problem.

    context = {
        'page_title': 'Résultats des médecins',
        'doctors': doctors,
    }
    return render(request, "dashboard/results.html", context)

Thank you for your great help!

PS: I already put some ifs and elses in the view to try to solve the issue but it's still not working. Sometimes it gives me results that don't satisfy any of the search criteria.

1 Answer 1

2

I have been able to use user filters successfully by using dictionaries and then unpacking them in the filter() function. For your case, I would try something as follows:

def search(request):
    val_name = request.POST.get('kw_name', '')
    filters = {
        'city__title__icontains': request.POST.get('kw_city'),
        'specialty__title__icontains': request.POST.get('kw_specialty')
    }
    filters = {k: v for k, v in filters.items() if v}
    q = Q(user__first_name__icontains=val_name) | Q(user__last_name__icontains=val_name)
    doctors = Doctor.objects.filter(q, **filters)

    context = {
        'page_title': 'Résultats des médecins',
        'doctors': doctors,
    }
    return render(request, "dashboard/results.html", context)
7
  • The 2 dropdown menus work (except there is a missing comma after ('kw_city'). But the name field doesnt, it always gives me all results even if their name is not in the search.
    – Kaiss B.
    Commented May 4, 2020 at 3:20
  • Thanks, I missed that comma, sorry. I don't get you when you say that it's not working. If the users don't fill up the text input (doctor's name) then the result is showing all doctors that match with the other two filters. Isn't that the behavior you are expecting?
    – revliscano
    Commented May 4, 2020 at 4:21
  • Can you give me an example of why it's not working?
    – revliscano
    Commented May 4, 2020 at 4:26
  • If I don't choose any of the 2 dropdowns and put any name on the name field, it still gives me all the objects, instead of only objects that have that name.
    – Kaiss B.
    Commented May 4, 2020 at 11:56
  • It shouldn't, I have tested almost the same code in a project of mine and it works. Nevertheless I have updated my answer. Can you try it out just as it is? Try copying and pasting exactly the same code I have just gave you (I'm saying this because I see you have some other logic in that view)
    – revliscano
    Commented May 4, 2020 at 14:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.