Как использовать Django FilterSet с MultiSelectField? - PullRequest
0 голосов
/ 05 февраля 2019

Я создал FilterSet, используя django_filters, чтобы пользователи могли фильтровать через профили других пользователей, используя фильтры, такие как city, age и gender.

Эти 3 поля вFilterSet работает нормально, однако я также хочу отфильтровать по interest, что является MultiSelectField на основе INTEREST_CHOICES.

Пользователь должен иметь возможность проверять несколько интересов и фильтровать по ним, в дополнение к3 поля, перечисленные выше.

Мне не удалось заставить это работать.

Мне удалось отобразить поле фильтра интересов, однако, когда пользователь выбирает одно из 4 интересов в раскрывающемся списке, страница не возвращает совпадений, даже если совпадает одно из этих интересов.

Я подозреваю, что это потому, что пользователи выбирают более одного интереса, поэтому интересы сохраняются в списке, а не по отдельности, поэтому FilterSet не может найти отдельный интерес.

Если кто-то может просмотретьмой код и укажите мне правильное направление, я был бы очень признателен.

models.py

class Profile(models.Model):

    INTEREST_CHOICES = (
                ('FITNESS', 'Fitness'),
                ('CHURCH', 'Church'),
                ('VEGANISM', 'Veganism'),
                ('MOVIES', 'Movies'),
    )

    GENDER_CHOICES = (
            ('M', 'Male'),
            ('F', 'Female'),
            ('X', 'Neither')
    )

    user            = models.OneToOneField(User, on_delete=models.CASCADE)
    interests       = MultiSelectField(choices = INTEREST_CHOICES)
    city            = models.CharField(max_length=30)
    age             = models.CharField(max_length=2)
    gender          = models.CharField(max_length=1, choices=GENDER_CHOICES)

filters.py

import django_filters
from .models import Profile

class ProfileFilter(django_filters.FilterSet):
    class Meta:
        model = Profile
        fields = {
            'city': ['iexact'],
            'interests': ['exact'],
            'age': ['iexact'],
            'gender': ['exact'],
        }

views.py

@login_required
def profile_filter(request):
    f = ProfileFilter(request.GET, queryset=Profile.objects.all())
    return render(request, 'profile/profile_filter.html', {'filter': f})

urls.py

path('filter', user_views.profile_filter, name='profile_filter'),

profile_filter.html

<h1>Filter people.</h1>
      <form method="GET">
          {{ filter.form|crispy }}
          <button type="submit" class="small">Search.</button>
      </form>

1 Ответ

0 голосов
/ 06 февраля 2019

Вы не хотите фильтровать по точному соответствию, скорее вы хотите фильтровать, проверяя, содержится ли параметр фильтра в списке интересов.Поэтому вы должны изменить свой фильтр следующим образом:

class ProfileFilter(django_filters.FilterSet):
    class Meta:
        model = Profile
        fields = {
            'city': ['iexact'],
            'interests': ['icontains'],
            'age': ['iexact'],
            'gender': ['exact'],
        }

EDIT : чтобы разрешить фильтрацию по нескольким интересам.

Здесь вам нужно написать собственный метод для анализаинтересы и конвертировать их в массивы перед фильтрацией.Обычно они представляются в виде строки со значениями, разделенными запятыми.

Добавьте метод в класс фильтра следующим образом:

class ProfileFilter(django_filters.FilterSet):
    interests = django_filters.CharFilter(field_name='interests', method='filter_interests')
    city = django_filters.CharFilter(field_name='city', lookup_expr='iexact')
    age = django_filters.NumberFilter(field_name='age', lookup_expr='iexact')
    gender = django_filters.CharFilter(field_name='gender', lookup_expr='iexact')

    class Meta:
        model = Profile
        fields = ['age', 'city', 'gender', 'interests']

    def filter_interests(self, queryset, name, interests):
        return queryset.filter(interests__contains=interests.split(','))
...