I'm struggling to implement a search bar and could really do with a few suggestions on how it could be done. I'm quite a novice, so please bear with me. My difficulties lie more with the general understanding of what needs to be built than with a specific line of code and somehow that's making it even harder for me to find an answer.
In summary, I have:
Django Models:
I've written Graphene schemas to query the database (Postgres) by Tags, Categories and numerous Recipe attributes (e.g.: Recipe name). You can filter the recipes displayed on the frontend with those queries, by clicking on e.g. a certain category name.
What I'd however also like to have, is a search box where a user can enter a keyword of their choice on the frontend, and get back all the recipes that have something matching that keyword.
I don't know what or how to build something like that. To my novice mind, it seems like a search box of that sort would essentially be a query where I don't know what the filter is in advance, i.e. "fresh" as an input could be a tag, category, part of a recipe name, etc... and I'd want all those matching results back - ideally without the search taking an exaggerated amount of time.
How should I go about building something like this? I've built the search box (React/Tailwind), so it's really all about what the backend needs to provide when a user types a keyword and clicks search.
Thank you for your help! :)
The following code shows my models -> The Recipe model is however quite large (not all code included), so any tips on how to keep the search speed down are also very appreciated.
class Recipe(models.Model):
..
..
..
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=50)
description = models.TextField(max_length=512, default='')
tags = models.ManyToManyField('tag.Tag')
category = models.ForeignKey(
'tag.Category',
related_name='recipe_category',
on_delete=models.SET_NULL,
null=True,
)
..
..
..
class Tag(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Category(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
Edit: Code added
So, based on the search term, you are trying to query the category table, tags table, and recipes table. here icontains is a Django-related ORM utility that is equivalent to ILIKE in SQL.
from django.db.models import Q
# in your mutation
search_term = "from your graphene mutation"
categories = Category.objects.filter(name__icontains=search_term).values_list(
"id", flat=True
)
tags = Tag.objects.filter(name__icontains=search_term).values_list("id", flat=True)
# here the Q object is used to build multiple or conditions
# the final query as response to your frontend
recipies = Recipe.objects.filter(Q(name__icontains=search_term) | Q(description__icontains=search_term) | Q(tags__in=tags) | Q(category__in=categories))
Notice the number of queries here, since we are querying multiple tables, the response could be slow depending on the size of the data in the database. By proper indexing on the database, you can easily overcome this, or you can even use something like full-text search engines like elastic search, etc.