[PYTHON] Understand how to use django-filter

What is django-filter?

You can write your search criteria in short code !!! When I learned this, I thought it was revolutionary.

django-filter official documentation

Define model and seiralizer

As a sample, let's define such a model and serializer.

models.py


class Book(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    is_deleted = models.CharField(max_length=1, default='0')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    title = models.CharField(max_length=128)
    sub_title = models.CharField(max_length=128)
    price = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    author = models.ForeignKey(Author, on_delete=models.PROTECT, blank=True, null=True)
    publisher = models.ForeignKey(Publisher, on_delete=models.PROTECT)

serializer.py


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

Basic writing

First of all, with django-filter Try to get the list without narrowing down by search conditions.

view.py


from django_filters import rest_framework as filters

class FilterBook(filters.FilterSet):
    class Meta:
        model = Book
        fields = '__all__'

class ListBook(APIView):

    def get(self, request):
        filterset = FilterBook(request.query_params, queryset=Book.objects.all())
        serializer = BookSerializer(instance=filterset.qs, many=True)
        return Response(serializer.data)

Create a class that inherits FilterSet and specify the model there. It's similar to Django's Form and Serializer.

And the URL of this created ListBook API / api / v1 / book / list / (omitted) When you make a request from a browser, such data will be returned. Of course the data is a sample lol

スクリーンショット 2020-10-21 19.38.42.png

Specify search conditions

Then, specify the search conditions and make a request. The URL you requested earlier was / api / v1 / book / list /, but specify the query parameters there. If you change to / api / v1 / book / list /? title = test and request, the response will change.

スクリーンショット 2020-10-21 19.48.30.png

No response was returned this time. This title = test returns an object whose Book model title matches test. Also change title to sub_title to / api / v1 / book / list /? sub_title = test When I make a request, no response is returned.

However, if you specify a query parameter that does not exist in the Book model Data cannot be narrowed down and data is returned in the response.

Change search conditions

Earlier, narrow down by title and sub_title The data was extracted.

However, this time, title can be a search condition, but sub_title is not required as a search condition! I wonder what happened. In such a case, you can specify only applicable in fields of Filter class.

views.py


class FilterBook(filters.FilterSet):
    class Meta:
        model = Book
        fields = ['title']

By doing this, I was able to narrow down by sub_title earlier, but now I can narrow down only by title.

Customize your search method

If you specified fields with __all__ earlier, it will be the default search method. I couldn't use the search method such as numerical search or partial match. (For example, even if you request / api / v1 / book / list /? Price = test, it will not be narrowed down.)

Therefore, we will customize the search method.

views.py


class FilterBook(filters.FilterSet):
    # UUID
    id = filters.UUIDFilter()

    #Partial Match
    title = filters.CharFilter(lookup_expr='icontains')

    #Find out the amount
    price = filters.NumberFilter()
    price__gt = filters.NumberFilter(field_name='price', lookup_expr='gt')
    price__lt = filters.NumberFilter(field_name='price', lookup_expr='lt')

    class Meta:
        model = Book
        fields = []

The content of customization. filters.UUIDFilter () is a UUID support. Even if you search by ID, it will be caught. With filters.CharFilter (lookup_expr ='icontains') I made a partial match. The argument for this lookup_expr is Django's field lookups You can specify the same as. filters.NumberFilter(field_name='price', lookup_expr='gt') Specifies the correspondence and range of numbers. field_name specifies the target field of the model. Normally, if the field name of the filter and the field name of the model match, there is no problem even if you do not specify it.


Let's make a request after customization. ʻApi / v1 / book / list /? title = sqlandapi/v1/book/list/?price_gt=3200&price_lt=4000` Data is now responded to when you make a request to.

スクリーンショット 2020-10-21 20.39.53.png

Also supports relations

If you want to use the model linked by Foreign Key as a search condition, Specify in field_name. You can specify it in django's lookup expression.

views.py


class FilterBook(filters.FilterSet):
    author_last_name = filters.CharFilter(field_name='author__last_name',lookup_expr='icontains')

Customize the default filter

With the default filter, CharFilter had to be customized for each field, such as an exact match. Instead of customizing on a field-by-field basis, we're trying to customize the CharFilter defaults.

views.py


class FilterBook(filters.FilterSet):

    class Meta:
        model = Book
        fields = ['title']
        filter_overrides = {
            models.CharField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
        }

In class Meta:, describe filter_overrrides and the content you want to set as the default. Now all fields using CharFiled in the model are partially matched by default.

Make your own customization

You can do your own search when narrowing down. I created an example that removes hyphens and makes a partial match.

views.py


class FilterBook(filters.FilterSet):
    title = filters.CharFilter(method='title_custom_filter')

    class Meta:
        model = Book
        fields = []

    @staticmethod
    def title_custom_filter(queryset, name, value):
        #name is the field name
        #value is the query parameter
        # name__icontains
        lookup = '__'.join([name, 'icontains'])
        #Erase hyphens
        replaced_value = value.replace('-', '')
        return queryset.filter(**{
            lookup: replaced_value,
        })

If you pass the name of the method as a string in the argument of CharFilter, the method will be executed at the time of search. The field name and value search parameters are passed to name. So if you change that, you can freely create search conditions.

This time, for example Same as / api / v1 / book / list /? title = g /api/v1/book/list/?title=g--- You can now get a response even if you send a request to.

スクリーンショット 2020-10-22 1.38.34.png


For more information, see By all means official documentation I hope you can check it !!!!!!!!!!!!!!!!!

Recommended Posts

Understand how to use django-filter
How to use xml.etree.ElementTree
How to use Python-shell
How to use tf.data
How to use virtualenv
How to use Seaboan
How to use image-match
How to use shogun
How to use Pandas 2
How to use Virtualenv
How to use numpy.vectorize
How to use pytest_report_header
How to use partial
How to use Bio.Phylo
How to use SymPy
How to use x-means
How to use WikiExtractor.py
How to use IPython
How to use virtualenv
How to use Matplotlib
How to use iptables
How to use numpy
How to use TokyoTechFes2015
How to use venv
How to use dictionary {}
How to use Pyenv
How to use list []
How to use python-kabusapi
[Python] Understand how to use recursive functions
How to use OptParse
How to use return
How to use dotenv
How to use pyenv-virtualenv
How to use Go.mod
How to use imutils
How to use import
How to use Qt Designer
How to use search sorted
[gensim] How to use Doc2Vec
python3: How to use bottle (2)
How to use the generator
[Python] How to use list 1
How to use FastAPI ③ OpenAPI
How to use Python argparse
How to use IPython Notebook
How to use Pandas Rolling
[Note] How to use virtualenv
How to use redis-py Dictionaries
Python: How to use pydub
[Python] How to use checkio
[Go] How to use "... (3 periods)"
How to use Django's GeoIp2
[Python] How to use input ()
How to use the decorator
[Introduction] How to use open3d
How to use Python lambda
How to use Jupyter Notebook
[Python] How to use virtualenv
python3: How to use bottle (3)
python3: How to use bottle
How to use Google Colaboratory