You can write your search criteria in short code !!! When I learned this, I thought it was revolutionary.
django-filter official documentation
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__'
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
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.
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.
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
.
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 = sqland
api/v1/book/list/?price_gt=3200&price_lt=4000`
Data is now responded to when you make a request to.
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')
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.
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.
For more information, see By all means official documentation I hope you can check it !!!!!!!!!!!!!!!!!
Recommended Posts