如何将Django FilterSet与MultiSelectField结合使用?

时间:2019-02-05 17:55:40

标签: python django django-models

我已经使用FilterSet创建了一个django_filters,因此用户可以使用cityagegender等过滤器来过滤其他用户的个人资料。 / p>

FilterSet中的这3个字段可以正常工作,但是我也想通过interest进行过滤,该MultiSelectField是基于INTEREST_CHOICES的{​​{1}}。

除了上面列出的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 :(得分:1)

您不想按完全匹配进行过滤,而是希望通过检查兴趣列表中是否包含过滤器参数来进行过滤。因此,您应该这样更改过滤器:

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

编辑:允许按多个兴趣进行过滤。

在这里,您必须编写一个自定义方法来解析兴趣并将其转换为数组,然后再进行过滤。它们通常以带有逗号分隔值的字符串形式出现。

将方法添加到过滤器类中,如下所示:

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(','))