0

On my homepage I have a search bar and when you search something it redirects you to a page with the results(titles and document types). On the left side of the page I want to implement a filter by document type.

After the search my url looks like this: http://127.0.0.1:8000/search/?q=something

After applying the filter: http://127.0.0.1:8000/search/?document_type=Tehnical+report

I don't know how to implement the filters to search just in the objects list filtered by the query (q) on the search page. Also, I'm not sure if the url should look like this : http://127.0.0.1:8000/search/?q=something&document_type=Tehnical+report or like this http://127.0.0.1:8000/search/?document_type=Tehnical+report after applying the filter.

models.py

DOCUMENT_TYPES = [
    ('Tehnical report','Tehnical report'),
    ('Bachelor thesis','Bachelor thesis'),
    ...
]

class Form_Data(models.Model):
    title           = models.CharField(unique=True, max_length=100, blank=False)
    author          = models.CharField(max_length=100)
    document_type   = models.CharField(choices=DOCUMENT_TYPES, max_length=255, blank=False, default=None)

views.py

def search_list(request):
    object_list = Form_Data.objects.none()
    document_types = DOCUMENT_TYPES

    query = request.GET.get('q')
    query_list = re.split("\s|(?<!\d)[,.](?!\d)", query)
    document_type_query = request.GET.get('document_type')

    for item in query_list:
        object_list |= Form_Data.objects.filter( Q(title__icontains=item) | Q(author__icontains=item))

    return render(request, "Home_Page/search_results.html")

home_page.html

<div class="Search">
    <form action="{% url 'home_page:search_results' %}" method="get">
        <input id="Search_Bar" type="text" name="q">
        <button id="Button_Search" type="submit"></button>
    </form>
</div>

search_results.html

{% for form_data in object_list %}
    <h5>{{ form_data.title }}</h5>
    <h5>{{ form_data.document_type }}</h5>
{% endfor %}

<form method="GET" action=".">
    <select class="form-control" name="document_type">
        {% for tag, label in document_types %}
            <option value="{{ tag }}">{{ tag }}</option>
        {% endfor %}
    </select>
</form>

2 Answers 2

1

In my opinion you are doing it the wrong way... I mean I didn't understand why you are looping your query for filtering. As far as I know it was looping every letters of your query.

I was doing it I would do it like this (using my own example):

<form action='{% url 'products:search' %}' method='get'>
    <input type='text' name='q' id='search' value='' >
    <select name='category' id='category'>
        <option value='' selected ></option>
        <option value='packet'>Packet</option>
        <option value='food'>Food</option>
        <option value='vegetable'>Vegetable</option>
    </select>
    <input type='button' value='submit' >
</form>

views.py:

def search(request):
    products = None
    query = request.GET.get('q')
    category = request.GET.get('category')
    
    if query:
        products = Product.objects.filter(
            Q(name__icontains=query)|
            Q(brand__icontains=query)
        )
    if category:
        # since it is a choice field in the model
        products |= Products.objects.filter(category=category) 

    context = {
        'products': products,
    }
    return render(request, 'products/search_products.html', context)

in this case if I press the submit button I would get a url like:

http://localhost:8000/products/search/?q=something&category=food

with this data I can filter products by name or any other fields I want.

I don't see any instance where someone would enter their query and search result will have all the products that has any of the letters entered in the input field.

Sign up to request clarification or add additional context in comments.

2 Comments

I was looping my query for filtering because the user can search multiple words and I want to show the results matching every word in the searched sentence. I have an variable which splits the input to extract just the words but I forgot to post it. Now I updated the code. My problem is when I check for the filter, I don't have the value for the initial query (from the seach bar) and it shows all the results filtered just by the document_type and not by the query 'q'. How can I check for both queries if the 'q' can't be saved?
i think your problem is you can't access both filters at once. Isn't it because they are in different forms. I mean if you want to pass more than one field in a single GET method you have to include them in the same form not in different form tags.
1

This would be the model filtering:

query = request.GET.get('q')
document_type_query = request.GET.get('document_type')

object_list = FormData.objects.none()

for item in query.split():
    item_qs = FormData.objects.filter(Q(title__icontains=item) | Q(author__icontains=item))
    if document_type_query:
         item_qs = item_qs.filter(document_type=document_type_query)
    object_list |= item_qs

return render(request, "Home_Page/search_results.html", {"object_list": object_list})

And this is the URL:

http://127.0.0.1:8000/search/?q=something%20with%20spaces&document_type=Tehnical+report

3 Comments

But I want to search for document type just if the user wants to apply filters. By default it should just display the results searched by 'q' query
Updated my answer @CătălinaSîrbu
When I tried this, I had this error "expected string or bytes-like object". I think my query gets deleted after it's used one time and I don't know how to save its value in order to use it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.