yeti logo icon
Close Icon
contact us
Yeti postage stamp
We'll reply within 24 hours.
Thank you! Your message has been received!
A yeti hand giving a thumb's up
Oops! Something went wrong while submitting the form.

Global Search in Django Rest Framework

November 26, 2014

My first few months of working with Django Rest Framework was a delight because so much functionality comes out of the box.

For example, let's say you have a user model and you want to search for a user via their username.

You can add this functionality by defining a filtering backend (in our case, using DRF's SearchFilter) and a search field specifying which field to search upon like this:

class UserViewSet(viewsets.ReadOnlyModelViewSet):   queryset = User.objects.all()   serializer_class = UserSerializer   filter_backends = (filters.SearchFilter,)   search_fields = ('username',)

Now if you want to search for users who’s username contains the word ‘john’ can just make GET request to the endpoint,  /users?search=john.

Easy enough. But what if you want a single endpoint that will make queries over multiple models? Because the search functionality we just introduced is applied per view level, we have to make some slight customizations in order to get global search over many models.

Global Search Over Multiple Models

In this blog post we’ll base our example off the Snippets tutorial from the Django Rest Framework website. The snippets app lets a user create and save code snippets as well as highlight them. What we want to add is a custom endpoint that will search across all our user and snippet models and return our list of model instances that matches the input query. So, if we make a GET request on the endpoint /search/?query=your_query, it will search and return serialized json data from both the user and snippet models that will match our query.

Customizing Django Rest Framework

To begin, we’ve set up a basic /search/ endpoint that will list all our search results.

urlpatterns = patterns('',   ...   url(r'^search/$', GlobalSearchList.as_view(), name="search"),)

Then we built a GobalSearchList view set that returns the appropriate data. GlobalSearchList inherits from ListAPIView, one of many of DRF’s view classes, that provides us with a read-only endpoint on a collection of model instances. We define this collection within our get_queryset method. Within this method, we capture the query parameter and make two separate queries, filtering against fields in both our snippets and users model instances, and the results are then returned in a combined list.

class GlobalSearchList(generics.ListAPIView):   serializer_class = GlobalSearchSerializer   def get_queryset(self):      query = self.request.QUERY_PARAMS.get('query', None)      snippets = Snippet.objects.filter(Q(code__icontains=query) | Q(highlighted__icontains=query) | Q(language__icontains=query))      users = User.objects.filter(username__icontains=query)      all_results = list(chain(snippets, users))       all_results.sort(key=lambda x: x.created)      return all_results

In the above example, you may have also noticed that we specified a custom serializer class called GlobalSearchSerializer. When we return our data from our GlobalSearchList viewset, it's important to apply the appropriate serializer to the model instances returned. We can customize this behavior by overriding the to_native method so that Snippet instances are serialized using a SnippetSerializer, and User instances are serialized using a UserSerializer.

Here’s an example of a global search serializer that may do this:

class GlobalSearchSerializer(serializers.ModelSerializer):   class Meta:      model = User   def to_native(self, obj):      if isinstance(obj, Snippet):          serializer = SnippetSerializer(obj)      elif isinstance(obj, User):         serializer = UserSerializer(obj)      else:         raise Exception("Neither a Snippet nor User instance!")      return

If you'd like to follow along, you can start with the snippets tutorial from the Django Rest Framework website here.

Also, special thanks to Baylee for the original code and for being an amazing mentor.

You Might also like...

Shopify Checkout Using UI Extensions

At Yeti we recently created a custom Shopify App using Checkout UI extensions to pull real-time data from a client’s Enterprise Resource Planning (ERP) system into Shopify. By the end of this article you will better understand what Shopify Checkout UI extensions are, how to approach building them, and some of the things to keep in mind during the implementation process.

colorful swirlsAn Introduction to Neural Networks

Join James McNamara in this insightful talk as he navigates the intricate world of neural networks, deep learning, and artificial intelligence. From the evolution of architectures like CNNs and RNNs to groundbreaking techniques like word embeddings and transformers, discover the transformative impact of AI in image recognition, natural language processing, and even coding assistance.

A keyboardThe Symbolicon: My Journey to an Ineffective 10-key Keyboard

Join developer Jonny in exploring the Symbolicon, a unique 10-key custom keyboard inspired by the Braille alphabet. Delve into the conceptualization, ideas, and the hands-on process of building this unique keyboard!

Browse all Blog Articles

Ready for your new product adventure?

Let's Get Started