次のような複数のクエリで複数のフィールドをフィルタリングしたい:
api/listings/?subburb=Subburb1, Subburb2&property_type=House,Apartment,Townhouse,Farm .. etc
組み込みの方法はありますか、django-filtersを見ましたが、制限があるようです.APIビューで手動でこれを行う必要があると思いますが、フィルターでフィルターをフィルタリングすると、面倒です
次のような複数のクエリで複数のフィールドをフィルタリングしたい:
api/listings/?subburb=Subburb1, Subburb2&property_type=House,Apartment,Townhouse,Farm .. etc
組み込みの方法はありますか、django-filtersを見ましたが、制限があるようです.APIビューで手動でこれを行う必要があると思いますが、フィルターでフィルターをフィルタリングすると、面倒です
複雑なフィルターは、DRF や django-filter プラグインでさえサポートされていません。単純なケースでは、独自の get_queryset メソッドを定義できます
これはドキュメントから直接です
def get_queryset(self):
queryset = Purchase.objects.all()
username = self.request.query_params.get('username', None)
if username is not None:
queryset = queryset.filter(purchaser__username=username)
return queryset
ただし、複数のフィルターがサポートされていて、それらの一部が複雑である場合、これはすぐに面倒になる可能性があります。
解決策は、カスタム filterBackend クラスと ViewSet Mixin を定義することです。この mixin は、典型的なフィルター バックエンドを理解する方法をビューセットに伝えます。このバックエンドは、フィルターを適用する必要がある場合のルールを含め、すべて明示的に定義された非常に複雑なフィルターを理解できます。
サンプル フィルター バックエンドは次のようになります (複雑さの昇順で、異なるクエリ パラメーターに対して 3 つの異なるフィルターを定義しました。
class SomeFiltersBackend(FiltersBackendBase):
"""
Filter backend class to compliment GenericFilterMixin from utils/mixin.
"""
mapping = {'owner': 'filter_by_owner',
'catness': 'filter_by_catness',
'context': 'filter_by_context'}
def rule(self):
return resolve(self.request.path_info).url_name == 'pet-owners-list'
ORM ルックアップに対する単純なフィルター。
def filter_by_catness(self, value):
"""
A simple filter to display owners of pets with high catness, canines excuse.
"""
catness = self.request.query_params.get('catness')
return Q(owner__pet__catness__gt=catness)
def filter_by_owner(self, value):
if value == 'me':
return Q(owner=self.request.user.profile)
elif value.isdigit():
try:
profile = PetOwnerProfile.objects.get(user__id=value)
except PetOwnerProfile.DoesNotExist:
raise ValidationError('Owner does not exist')
return Q(owner=profile)
else:
raise ValidationError('Wrong filter applied with owner')
より複雑なフィルター:
def filter_by_context(self, value):
"""
value = {"context_type" : "context_id or context_ids separated by comma"}
"""
import json
try:
context = json.loads(value)
except json.JSONDecodeError as e:
raise ValidationError(e)
context_type, context_ids = context.items()
context_ids = [int(i) for i in context_ids]
if context_type == 'default':
ids = context_ids
else:
ids = Context.get_ids_by_unsupported_contexts(context_type, context_ids)
else:
raise ValidationError('Wrong context type found')
return Q(context_id__in=ids)
これがどのように機能するかを完全に理解するには、私の詳細なブログ投稿を読むことができます: http://iank.it/pluggable-filters-for-django-rest-framework/
すべてのコードは Gist にもあります: https://gist.github.com/ankitml/fc8f4cf30ff40e19eae6
フィルターでのフィルターのフィルタリングは面倒ではありませんchained filters
。
また、チェーン フィルターが必要なのは、そうでない場合があるためですproperty_type
。
if property_type:
qs = qs.filter(property_type=property_type)
複数のクエリがあると考えている場合でも、クエリセットは遅延しているため、1 つのクエリで実行されます。
または、dict を作成して一度だけ渡すこともできます。
d = {'property_type:': property_type, 'subburb': subburb}
qs = MyModel.objects.filter(**d)