htmlcssdjangodjango-modelsdjango-templates

How can I make a search bar in django?


I'm learning django and I'm trying to make a online shop for learning. Currently I have a problem in how to make a search bar in django. I have model called "Car" in my models.py and it contains fields like name, price of the car and also it has a field called "tag" and I want to make a search bar using this field. I want that when user types a tag in the webpage of site, django searches and shows the items that have the same tag.

I tried to solve my problem by reading the documents but it didn't help.


Solution

  • Solution

    Here is an example of a view and some template code that would handle the search you want to execute (adapted from Bidhan Majhi's answer to this StackOverflow question):

    views.py

    class SearchView(ListView):
        model = Car
        template_name = 'search.html'
        context_object_name = 'all_search_results'
    
        def get_queryset(self):
           result = super(SearchView, self).get_queryset()
           query = self.request.GET.get('search')
           if query:
              postresult = Car.objects.filter(tag__contains=query)
              result = postresult
           else:
               result = None
           return result
    

    template

    <form method="GET" action="" >
        <input type="search" name="search"> 
        <button type="submit"> Search </button>
    </form>
    
    {% for car in all_search_results %}
       <h2>{{ car.year }}&nbsp;{{ car.make }}&nbsp;{{ car.model }}</h2>
       {% comment %} Add whatever else for each Car model returned{% endcomment %}
    {% empty %}
       <h2>add something to show no results</h2>
    {% endfor %}
    

    Caveat (if your tags field is a ManyToManyField)

    The above view would work as long as your tag is just a CharField, but if your tags field is a ManyToManyField, you would have to modify the postresult = Car.objects.filter(tag__contains=query) line so that it would work through a related Tag model (postresult = Car.objects.filter(tags__text__contains=query)).

    This is how that would look:

    app named "tag": models.py

    from django.db import models
    
    class Tag(models.Model):
        text = models.CharField(max_length=20)
    

    app named "car": models.py

    from django.db import models
    from tag.models import Tag
    
    import datetime
    
    def year_range():
        this_year = datetime.date.today().year
        return [(r, r) for r in range(
                1860, this_year+2
            )
        ]
    
    class Car(models.Model):
        """model for thoughts that come into my mind"""
        year = models.PositiveSmallIntegerField(
            choices=year_range
        )
        make = models.CharField(max_length=50)
        model = models.CharField(max_length=50)
        tags = models.ManyToManyField(
            Tag, related_name="cars"
        )
    

    views.py

    from django.views import generic
    
    from .models import Car
    
    
    # Create your views here.
    class SearchView(generic.ListView):
        model = Car
        template_name = 'search.html'
        context_object_name = 'all_search_results'
    
        def get_queryset(self):
            result = super(SearchView, self).get_queryset()
            query = self.request.GET.get('search')
            if query:
                postresult = Car.objects.filter(tags__text__contains=query)
                result = postresult
            else:
                result = None
            return result
    

    The template would be the same as above. I just tried it in a django sandbox project I have, and it worked great :)