How to filter your query with params in Django Rest - Part II
Tags: django, djangorestframework, queryset
Published: 2021-12-17 13:32:01

---
title: How to filter your query with params in Django Rest - Part II
published: true
date: 2021-11-12 00:00:00 UTC
tags: django, djangorestframework, queryset
canonical_url: https://tech.serhatteker.com/post/2021-11/django-rest-query-part-2/
---

## Intro

We saw in [previous article] how to use `query params`. Now it's time to improve it.

## Improvement I

Our overwritten `get_queryset` method will create multiple `INNER JOINS` in our `SQL` query. We can prevent that by using `prefetch_related`:

```python
# articles/views.py
from rest_framework import generics

from src.articles.models import Article
from src.articles.serializer import ArticleSerializer


class ArticleListView(generics.ListCreateAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    region_separator = ","

    def get_queryset(self):
        """
        Optionally restricts the returned articles to given regions,
        by filtering against a `regions` query parameter in the URL.
        """
        regions = self.request.query_params.get("regions", None)
        if regions:
            qs = Article.objects.prefetch_related("regions")
            for region in regions.split(self.region_separator):
                qs = qs.filter(regions__code=region)

            return qs

        # return default Article.objects.all()
        return super().get_queryset()
```

## Improvement II

Writing business logic or query decisions in `Views` is usually considered anti-pattern for Django.  Query methods should be in `models` or better in `models.Manager`;

```python
# articles/models.py
from django.db import models

from src.articles.models import Article
from src.articles.serializer import ArticleSerializer


class ArticleManager(models.Manager):
    def by_regions(self, regions, region_separator=","):
        """
        Restricts the returned articles to given regions
        """
        if regions:
            qs = self.prefetch_related("regions")
            for region in regions.split(region_separator):
                qs = qs.filter(regions__code=region)

            return qs

        return self.all()


class Article(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField(blank=True)
    regions = models.ManyToManyField(
        "Region", related_name="articles", blank=True
    )

    objects = ArticleManager()

    def __str__(self):
        return self.title

    ...
```


```python
# articles/views.py 
from rest_framework import generics

from src.articles.models import Article
from src.articles.serializer import ArticleSerializer


class ArticleListView(generics.ListCreateAPIView):
    serializer_class = ArticleSerializer

    def get_queryset(self):
        """
        Optionally restricts the returned articles to given regions,
        by filtering against a `regions` query parameter in the URL.
        """
        regions = self.request.query_params.get("regions", None)

        return Article.objects.by_regions(regions=regions)
```

If you have more complex queris you can use [third party packages].


All done!




[third party packages]: https://www.django-rest-framework.org/api-guide/filtering/#third-party-packages
[previous article]: https://tech.serhatteker.com/post/2021-11/django-rest-query-part-1