Фильтрация в фреймворке django rest

В моем проекте я использую django rest framework. Для фильтрации результатов я использую бэкэнд django_filters. Вот мой код:

models.py

from django.db import models


class Region(models.Model):
    name = models.CharField(max_length=100, blank=True, null=False)


class Town(models.Model):
    region = models.ForeignKey(Region)
    name = models.CharField(max_length=100, blank=True, null=False')

filters.py

import django_filters
from models import Town


class TownFilter(django_filters.FilterSet):
    region = django_filters.CharFilter(name="region__name", lookup_type="contains")
    town = django_filters.CharFilter(name="name", lookup_type="contains")

    class Meta:
        model = Town
        fields = ['region', 'town']

views.py

from models import Town
from rest_framework import generics
from serializers import TownSerializer
from filters import TownFilter


class TownList(generics.ListAPIView):
    queryset = Town.objects.all()
    serializer_class = TownSerializer
    filter_class = TownFilter

Итак, я могу написать ?region=Region_name&town=Town_name в конце URL-адреса запроса, и результат будет отфильтрован.

Но я хочу использовать только один параметр get в URL-адресе запроса, который может иметь значение регион или название города. Например, ?search=Region_name и ?search=Town_name. Как я могу это сделать?


person Albert Iskhakov    schedule 26.03.2014    source источник


Ответы (1)


Есть несколько вариантов, но самый простой способ — просто переопределить «get_queryset» в представлении API.

Пример из документов, адаптированный к вашему варианту использования:

class TownList(generics.ListAPIView):
    queryset = Town.objects.all()
    serializer_class = TownSerializer
    filter_class = TownFilter(generics.ListAPIView)
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        queryset = Town.objects.all()
        search_param = self.request.QUERY_PARAMS.get('search', None)
        if search_param is not None:
            """
            set queryset here or use your TownFilter 
            """
        return queryset

Другой способ - установить search_fields в классе представления списка API в сочетании с классом SearchFilter. Проблема в том, что если вы фильтруете несколько моделей, вам, возможно, придется выполнить здесь дополнительную реализацию, чтобы убедиться, что она смотрит именно на то, что вам нужно. Если вы не делаете ничего особенного, просто поставьте двойное подчеркивание для региона, например: region__name

person therewillbesnacks    schedule 26.03.2014
comment
Спасибо, но я привел упрощенный пример рассматриваемого кода. Модель города имеет более двух полей. И все эти поля я хочу использовать в фильтре. Например, URL-адрес может иметь вид ?search=Region/Town¶m1=...¶m2=... Вот почему ваше решение мне не очень подходит. - person Albert Iskhakov; 26.03.2014
comment
Я не понимаю, почему использование SearchFilter или просто переопределение набора запросов не дает именно этого. Я не могу знать, каково ваше намерение, потому что вы не задали этого в своем вопросе, а просто попросили 1 параметр поиска. Просто добавьте, например, второй self.request.QUERY_PARAMS.get('param1', None). Затем верните набор запросов. В качестве альтернативы просто сделайте это в SearchFilter. - person therewillbesnacks; 26.03.2014
comment
У меня есть 25 полей в модели, которые я хочу использовать в фильтре. И только поля города и региона должны быть вместе в поиске GET var в URL-адресе. 'search_fields' работает только с одной GET-переменной. И если я переопределю 'get_queryset', то я должен написать QUERY_PARAMS.get('param1', None) 23 раза. - person Albert Iskhakov; 26.03.2014
comment
Поэтому, пожалуйста, переформулируйте свой вопрос, это совсем не то, о чем вы спрашивали. Почему вы хотите фильтровать по 25 полям? Я бы сначала спросил себя - может быть, у вас есть веская причина. Однако, как правило, это очень плохая идея, потому что обычно у вас не будет 25 покрывающих индексов для этих полей, т.е. он будет работать ужасно медленно, как можно было ожидать. Если вам действительно нужно 25 полей, будьте программистом и просто напишите простую функцию, которая сопоставляет параметр запроса с полем (легко, если это 1: 1, иначе создайте dict) и создает запрос. Это классический строительный шаблон. - person therewillbesnacks; 26.03.2014
comment
Также, пожалуйста, прочитайте документы в моем ответе. В нем явно указано: обратите внимание, что вы можете использовать как переопределенный .get_queryset(), так и общую фильтрацию вместе, и все будет работать так, как ожидалось. Другими словами, опять же, я не вижу, как это вызовет у вас проблемы. У меня нет вашего кода, чтобы написать для вас, так что это зависит от вас. - person therewillbesnacks; 26.03.2014
comment
Я думаю, что он ищет способ фильтрации как по столбцу, так и по глобальной фильтрации. Фильтрация столбцов выполняется с помощью ?column_name=value, а глобальная фильтрация выполняется с помощью ?search=any_text. - person Bonnie Varghese; 22.05.2014