Möglicherweise ein `in`` lookup_type` durch den Django-Filter-URL-Parser?
-
21-12-2019 - |
Frage
Ich verwende django-filter mit Django-Rest-Framework Und ich versuche, einen Filter zu instanziieren, der die Nummernlisten akzeptiert, um das Abfragen festzulegen
generasacodicetagpre.Wenn ich eine durch Kommas getrennte Liste der Ganzzahlen weiterleite, wird der Filter vollständig ignoriert.
Wenn ich eine einzelne Ganzzahl passiere, wird es durch den Django-Filter in Django-Formular-Validator gelangen und klagt:
generasacodicetagpre.Gibt es eine Möglichkeit, ein Django-Filter-Objekt zu erstellen, das eine Liste der Ganzzahlen verarbeiten kann, und filtern Sie den AbfrageSet richtig herunter?
Lösung
Zum Besseren oder schlechter habe ich einen benutzerdefinierten Filter erstellt:
generasacodicetagpre.das verwendet wird wie:
generasacodicetagpre.Jetzt akzeptiert meine Schnittstelle Kommas getrennte Listen von Ganzzahlen.
Andere Tipps
Ich weiß, dass dies ein alter Posten ist, aber es gibt jetzt eine bessere Lösung.Die Änderung, die es richtig macht, ist gepostet hier .
Sie fügten einen generationspflichtigen, einem generationspflichten und einem BaseInFilter
hinzu.Die Dokumentation ist hier .
Big Picture, BaseFilter prüft für CSV, und wenn Sie mit einem anderen Filter gemischt werden, tut es, was Sie fragen.Ihr Code kann jetzt geschrieben werden wie:
generasacodicetagpre.Hier ist eine komplette Lösung:
generasacodicetagpre.According to a post in the django-filter issues:
from django_filters import Filter
from django_filters.fields import Lookup
class ListFilter(Filter):
def filter(self, qs, value):
return super(ListFilter, self).filter(qs, Lookup(value.split(u","), "in"))
I have personally used this without any issue in my projects, and it works without having to create a per-type filter.
Based on @yndolok answer I have come to a general solution. I think filtering by a list of ids is a very common task and therefore should be included in the FilterBackend:
class ListFilter(django_filters.Filter):
"""Class to filter from list of integers."""
def filter(self, qs, value):
"""Filter function."""
if not value:
return qs
self.lookup_type = 'in'
try:
map(int, value.split(','))
return super(ListFilter, self).filter(qs, value.split(','))
except ValueError:
return super(ListFilter, self).filter(qs, [None])
class FilterBackend(filters.DjangoFilterBackend):
"""A filter backend that includes ListFilter."""
def get_filter_class(self, view, queryset=None):
"""Append ListFilter to AutoFilterSet."""
filter_fields = getattr(view, 'filter_fields', None)
if filter_fields:
class AutoFilterSet(self.default_filter_set):
ids = ListFilter(name='id')
class Meta:
model = queryset.model
fields = list(filter_fields) + ["ids"]
return AutoFilterSet
else:
return super(FilterBackend, self).get_filter_class(view, queryset)
Uptodate solution:
from django_filters import rest_framework as filters
name-->field_name
lookup_type-->lookup_expr
class IntegerListFilter(filters.Filter):
def filter(self,qs,value):
if value not in (None,''):
integers = [int(v) for v in value.split(',')]
return qs.filter(**{'%s__%s'%(self.field_name, self.lookup_expr):integers})
return qs
class MyFilter(filters.FilterSet):
ids = IntegerListFilter(field_name='id',lookup_expr='in')
class Meta:
model = MyModel
fields = ('ids',)
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_class = MyFilter
As I have answered here DjangoFilterBackend with multiple ids, it is now pretty easy to make a filter that accepts list and validates the contents
For Example:
from django_filters import rest_framework as filters
class NumberInFilter(filters.BaseInFilter, filters.NumberFilter):
pass
class MyFilter(filters.FilterSet):
id_in = NumberInFilter(field_name='id', lookup_expr='in')
class Meta:
model = MyModel
fields = ['id_in', ]
This will accept a list of integers from a get parameter. For example /endpoint/?id_in=1,2,3