Django-filter '__in' search

I am using django-rest-framework with https://github.com/alex/django-filter/ , but the question is mainly about django filter. I can’t figure out how to use __in search filters.

For example, I have a model:

class Book(models.Model): name = models.CharField(max_length=100) class BookView(viewsets.ReadOnlyModelViewSet): serializer_class = BookSerializer() model = Book filter_fields = ('id', 'name') 

And I can not use url like this

/ v1 / books /? Id__in = 1,2,3

find books with identifiers 1, 2 or 3

+6
source share
7 answers

The issue is discussed in this release: https://github.com/alex/django-filter/issues/137#issuecomment-77697870

The proposed solution is to create a custom filter as follows:

 from django_filters import Filter from django_filters.fields import Lookup from .models import Product class ListFilter(Filter): def filter(self, qs, value): value_list = value.split(u',') return super(ListFilter, self).filter(qs, Lookup(value_list, 'in')) class ProductFilterSet(django_filters.FilterSet): id = ListFilter(name='id') class Meta: model = Product fields = ['id'] 

And you can write the following:

products/? ID = 7.8.9

+5
source

The documentation for the django filter is sparse. You can try to create a custom filter and specify the type of search. This is pretty confusing:

 class BookFilter(django_filters.FilterSet): id = django_filters.NumberFilter(name="id", lookup_type="in") class Meta: model = Book fields = ['id'] 

And then change your view to use the filter class:

 class BookView(viewsets.ReadOnlyModelViewSet): serializer_class = BookSerializer() model = Book filter_fields = ('id', 'name') filter_class = BookFilter 

Then you can search for books through their identifiers (note "__in" is not used):

 /v1/books/?id=1,2,3 /v1/books/?id=1 
+3
source

Configure PKsField and PKsFilter for your id field (AutoField), and then query parameters will be executed: '/ v1 / books /? id__in = 1,2,3 '

 from django.forms import Field from django_filters.filters import Filter from django.db.models import AutoField class PKsField(Field): def clean(self, value): # convert '1,2,3' to {1, 2, 3} return set(int(v) for v in value.split(',') if v.isnumeric()) if value else () class PKsFilter(Filter): field_class = PKsField class BookFilter(FilterSet): # ids = PKsFilter(name='id', lookup_type="in") # another way, query string: ?ids=1,2,3 filter_overrides = { AutoField: { 'filter_class': PKsFilter, # override default NumberFilter by the PKsFilter 'extra': lambda f: { 'lookup_type': 'in', } } } class Meta: model = Book fields = { 'id': ('in',), } from rest_framework import viewsets class BookView(viewsets.ModelViewSet): queryset = ... serializer_class = ... filter_class = BookFilter 

Hope this helps. thanks.

+1
source

Instead of /v1/books/?id__in=1,2,3 you can use /v1/books/?id=1&id=2&id=3

0
source

Not sure if the answer was ever given: try: id = [1, 2, 3] for numbers name = ["name1", "name2"] for strings

0
source

I just answered the same question in DjangoFilterBackend with multiple identifiers

In your case, this should work without having to write any logic.

 from django_filters import rest_framework as filters class NumberInFilter(filters.BaseInFilter, filters.NumberFilter): pass class BookFilter(filters.FilterSet): id_in = NumberInFilter(field_name='id', lookup_expr='in') class Meta: model = Book fields = ['id_in', 'name'] class BookView(viewsets.ReadOnlyModelViewSet): serializer_class = BookSerializer() model = Book filter_class = BookFilter 

You should now be able to filter by the list of identifiers in your get options, such as /v1/books/?id__in=1,2,3

0
source

The django admin site only creates URLs under the app_name / model_name / primary_key pattern to edit the model instance. It does not provide __in filtering through URLS.

You need to create a custom view:

 def myview(request): # you can get parameters from request.GET or request.POST selected_books = None if request.method = "POST": ids = request.POST["ids"].split("_") selected_books = Book.objects.filter(id__in=ids) return render_to_response('mytemplate.html', { 'selected_books': selected_books }, context_instance = RequestContext(request) ) 

And in mytemplate.html:

 {% for entry in selected_books %} ... {{ entry }} ... {% endfor %} 

In urls.py add an entry to this view.

Then try a GET request to the url with parameters ?ids=1_2_3

-1
source

Source: https://habr.com/ru/post/950905/


All Articles