15👍
There’s a simple solution with django_filter
now:
class BookView(viewsets.ReadOnlyModelViewSet):
serializer_class = BookSerializer()
model = Book
filter_fields = {
'id': ['exact', 'in'],
'name': ['exact']
}
And then you can use it in your query string exactly as you wanted: ?id__in=1,2,3
.
9👍
The django-filter provides BaseInFilter
to be used in conjunction with other filter classes, such as NumberFilter
, CharFilter
. This class only validates that the incoming request is comma-separated
.So if you’re using the Web Browsable API, you can send request as /book/?id__in=1%2C
3 where %2C
is comma.
filters.py
import django_filters
class NumberInFilter(django_filters.BaseInFilter, django_filters.NumberFilter):
pass
class BookFilter(django_filters.FilterSet):
id__in = NumberInFilter(field_name="id", lookup_expr="in")
views.py
from rest_framework import viewsets
from django_filters import rest_framework as filters
from book.filters import BookFilter
from book.models import Book
from book.serializers import BookSerializer
class BookViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Book.objects.all()
filter_backends = (filters.DjangoFilterBackend, )
filterset_class = BookFilter
serializer_class = BookSerializer
- How can I make SSE with Python (Django)?
- Appropriate choice of authentication class for python REST API used by web app
- TimeField format in Django template
- (gcloud.app.deploy) Error Response: [7] Access Not Configured. Cloud Build has not been used in project
- Have a url that accepts all characters
5👍
The question is discussed in this issue: https://github.com/alex/django-filter/issues/137#issuecomment-77697870
The suggested solution would be 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 the you can write the following:
products/?id=7,8,9
- Django + Forms: Dynamic choices for ChoiceField
- Subclassing Django ModelForms
- Django makemigrations not detecting project/apps/myapp
3👍
The documentation for django-filter is sparse. You could try creating a custom filter and specifying the lookup type. It’s rather convoluted:
class BookFilter(django_filters.FilterSet):
id = django_filters.NumberFilter(name="id", lookup_type="in")
class Meta:
model = Book
fields = ['id']
And then modify your view to use the filter class:
class BookView(viewsets.ReadOnlyModelViewSet):
serializer_class = BookSerializer()
model = Book
filter_fields = ('id', 'name')
filter_class = BookFilter
You’ll then be able to lookup books via their ids (note “__in” not used):
/v1/books/?id=1,2,3
/v1/books/?id=1
2👍
Customize PKsField and PKsFilter for your id field(AutoField), and then the query params will work: ‘/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 that can help. Thx.
- Django-Rest-Framework serializer class meta
- Django: Generic views based 'as_view()' method
- Django queryset __contains case sensitive?
- Celery – No module named five
- Remove padding from matplotlib plotting
1👍
I have just answered the same question in DjangoFilterBackend with multiple ids
For 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
Now you should be able to filter by a list of ids in your get parameters, such as /v1/books/?id__in=1,2,3
- Django reverse error: NoReverseMatch
- What is the difference between the create and perform_create methods in Django rest-auth
- How to have a link in label of a form field
- How can I easily convert a Django app from mySQL to PostgreSQL?
- Django redirect() with anchor (#) parameters
- Django can't access raw_post_data
- Django: WSGIRequest' object has no attribute 'user' on some pages?
- Uwsgi segmentation fault when serving a django application
0👍
Not sure if this was ever answered:
try:
id=[1, 2, 3] for numbers
name=[“name1”, “name2”] for strings
- Django: Check for related objects and whether it contains data
- Is there a way to render a html page without view model?
- Is there a command for creating an app using cookiecutter-django?
- What is the difference between the create and perform_create methods in Django rest-auth
-2👍
The django admin site only create urls under the template app_name/model_name/primary_key to edit an instance of the model. It doesn’t provide the __in
filtering through URLS.
You have 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 your URL with the parameters ?ids=1_2_3
- Django rest auth email instead of username
- How to embed matplotlib graph in Django webpage?
- Executing a Django Shell Command from the Command Line
- Is there any list of blog engines, written in Django?