Как фильтровать запрос по нескольким значениям, используя DRF, djagno-filters и значения HyperlinkedIdentityField
Основная цель является получение набора запросов на основе нескольких значений в запросе.
Бизнес-логика заключается в получении всех контрактов для нескольких водителей.
Пример: запрос url:
/api/contract/?driver=http://localhost:8000/api/driver/1,http://localhost:8000/api/driver/2
В ответе должны быть все контракты для этих двух водителей.
Сериализатор драйвера:
class DriverSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='driver-detail',
read_only=True
)
class Meta:
model = Driver
fields = [
'url',
'id',
'first_name',
'last_name',
]
Contract serializer:
class ContractSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='contract-detail',
read_only=True
)
driver = serializers.StringRelatedField(many=False)
class Meta:
model = Contract
fields = [
'url',
'id',
'contract_detail_fields',
'driver',
]
Просмотр договора
class ContractViewSet(viewsets.ModelViewSet):
serializer_class = serializers.ContractSerializer
queryset = Contract.objects.all()
permission_classes = (IsAuthenticated,)
filter_backends = [DjangoFilterBackend]
filterset_class = ContractFilter
ContractFilter:
class ContractFilter(FilterSet):
driver = CustomHyperlinkedIdentityFilterList('driver')
Что я пробовал, так это сделать пользовательский filterField на основе ответа by Sherpa
class CustomHyperlinkedIdentityFilterList(django_filters.BaseCSVFilter,
django_filters.CharFilter):
def filter(self, qs, value):
values = value or []
for value in values:
qs = super(CustomHyperlinkedIdentityFilterList,
self).filter(qs, value)
return qs
Ответ ValueError: Поле 'id' ожидало число, но получило 'http://localhost:8000/api/drivers/driver/3/'.
Затем я пытаюсь изменить фильтрацию по id, а не по urlField и изменяю эту строку
qs = super(CustomHyperlinkedIdentityFilterList, self).filter(qs, value)
на это:
qs = super(CustomHyperlinkedIdentityFilterList, self).filter(qs, get_id_from_url(value))
где get_id_from_url это:
def get_id_from_url(url):
return int(resolve(urlparse(unquote(url)).path).kwargs.get('pk'))
Но он возвращает мне только контракты для последнего водителя, а не для обоих.
Тогда я также попробовал конфигурации, основанные на ответе Славы
class ContractFilter(FilterSet):
class Meta:
model = Contract
fields = ['driver']
при использовании этого решения ответом будет Bad request {"driver":["Выберите правильный выбор. Этот выбор не является одним из доступных вариантов."]}
Надеюсь, есть очень простые решения, которые я упустил.