DRF-фильтрация с несколькими параметрами запроса и внешними ключами - PullRequest
1 голос
/ 06 мая 2020

Я новичок в Django, и я пытаюсь создать маршрут, который можно вызвать для получения массива транспортных средств из моей базы данных, но я хочу, чтобы пользователь мог предоставить несколько параметров запроса в URL-адресе (что-то вроде: http://127.0.0.1:8000/vehicles/?year=2020&make=Toyota). Проблема, с которой я столкнулся, заключается в том, что моя модель автомобиля включает ссылки на внешние ключи для марки и v_model (названные так, чтобы избежать конфликта с «моделью» Django). У меня есть решение, которое не кажется изящным. Тот факт, что у меня есть три вложенных условных оператора для каждого поля поиска, вызывает у меня подозрения. Я пробовал использовать «filters.SearchFilter», но мне удалось указать только одно значение, на котором основывался поиск. Таким образом, запрос, подобный этому: http://127.0.0.1:8000/vehicles/?search=2020&search=Toyota будет искать только автомобили марки «Toyota», игнорируя параметр «год».

Есть ли другой способ сделать это более чистым или более "Django -approved "?

Вот мой код:

models.py:

class Make(models.Model):
    name = models.CharField(max_length=200, unique=True)
    def __str__(self):
        return self.name


class VModel(models.Model):
    name = models.CharField(max_length=200, unique=True)
    make = models.ForeignKey(Make, on_delete=models.CASCADE)
    def __str__(self):
        return self.name


class Vehicle(models.Model):
    make = models.ForeignKey(Make, on_delete=models.CASCADE)
    v_model = models.ForeignKey(VModel, on_delete=models.CASCADE)
    year = models.CharField(max_length=5)
    def __str__(self):
        return self.year + " " + self.v_model.name

views.py:

Вот моя попытка с фильтрами.SearchFilter:

    queryset = Vehicle.objects.all()
    serializer_class = VehicleSerializer
    filter_backends = [filters.SearchFilter]
    search_fields = ['year', 'v_model__name','make__name']

И вот мое «рабочее» решение, которое кажется хакерским: (ПРИМЕЧАНИЕ: я использую name__icontains, так что если пользователь вводит «Тойот», он все равно получит все машины с маркой Toyota).

class VehicleListViewSet(viewsets.ModelViewSet):
    serializer_class = VehicleSerializer
    queryset = Vehicle.objects.all()
    pagination_class = CustomPagination


    def get_queryset(self):
        qs = super().get_queryset()
        selected_make = self.request.query_params.get('make', None)
        if selected_make:
            try:
                found_make = Make.objects.get(name__icontains=selected_make)
            except:
                return []
            if found_make:
                if found_make.id:
                    qs = qs.filter(make=found_make.id)
        selected_v_model = self.request.query_params.get('v_model', None)
        if selected_v_model:
            try:
                found_v_model = VModel.objects.get(name__icontains=selected_v_model)
            except:
                return []
            if found_v_model:
                if found_v_model.id:
                    qs = qs.filter(v_model=found_v_model.id)
        selected_year = self.request.query_params.get('year', None)
        if selected_year:
            qs = qs.filter(year=selected_year)
        return qs

1 Ответ

0 голосов
/ 21 мая 2020

Вы не должны использовать filters.SearchFilter. Вместо этого используйте атрибут filterset_fields в вашем ViewSet, как в примере из этого раздела документации .

Ваше представление будет выглядеть так:

class VehicleListViewSet(viewsets.ModelViewSet):
    serializer_class = VehicleSerializer
    queryset = Vehicle.objects.all()
    pagination_class = CustomPagination
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['year', 'v_model__name','make__name']

(обратите внимание, что нет переопределения get_queryset). Вы сможете запрашивать свой API следующим образом:

http://127.0.0.1:8000/vehicles/?year=2020&make__name=Toyota&v_model__name=Corolla

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...