Как отфильтровать несколько полей с помощью Django-filter?

Я хочу получить данные, отфильтрованные по пользователю и категории.

Я использую Django Rest Framework.

models.py

class Practice(models.Model):
    practice_id = models.BigAutoField(primary_key=True)
    user = models.ForeignKey('User', models.DO_NOTHING, default=None)
    subcategory = models.ForeignKey('Subcategory', models.DO_NOTHING, default=None)
    score = models.SmallIntegerField(null=True)

    def __str__(self):
        return str(self.practice_id)

class User(models.Model):
    user_id = models.BigAutoField(primary_key=True)
    fullname = models.CharField(max_length=50)

    def __str__(self):
        return self.fullname

class Subcategory(models.Model):
    subcategory_id = models.BigAutoField(primary_key=True)
    category = models.CharField(max_length=30)

    def __str__(self):
        return f"{ self.category }"

serializers.py

class PracticeSerializer(serializers.ModelSerializer):
    subcategory = SubcategorySerializer()

    class Meta:
        model = Practice
        fields = ('practice_id',
                  'user',
                  'subcategory',
                  'score',
                  )

views.py

@api_view(['GET'])
def practiceFilter_User(request):
    if request.method == 'GET':
        exercises = Practice.objects.all()
        
        user = request.GET.get('user', None)
        if user is not None:
            practice_filtered = exercises.filter(user__user_id__icontains=user)

        exercises_serializer = PracticeSerializer(practice_filtered, many=True)
        return JsonResponse(exercises_serializer.data, safe=False)

urls.py

urlpatterns = [ 
        url(r'^api/practice-filter-user$', views.practiceFilter_User),
]

В моей базе данных есть данные по 3 практикам, как показано ниже :

[
  {
    practice_id: 1,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 7,
  },
  {
    practice_id: 2,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 8,
  },
  {
    practice_id: 3,
    user: 1,
    subcategory: {
      subcategory_id: 2,
      category: "History",
    },
    score: 9,
  }
]

Если вышеприведенный код выполняется для получения данных о практике по идентификатору пользователя = 1, результат будет следующим :

api/practice-filter-user?user=1

[
  {
    practice_id: 1,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 7,
  },
  {
    practice_id: 2,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 8,
  },
  {
    practice_id: 3,
    user: 1,
    subcategory: {
      subcategory_id: 2,
      category: "History",
    },
    score: 9,
  }
]

Я хочу получить данные, отфильтрованные по всем user с идентификатором 1 и всем Math category, как показано ниже :

api/practice-filter-subcategory-user?user=1&category=Math

[
  {
    practice_id: 1,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 7,
  },
  {
    practice_id: 2,
    user: 1,
    subcategory: {
      subcategory_id: 1,
      category: "Math",
    },
    score: 8,
  }
]

Результаты, приведенные выше, - это то, что я хочу получить при извлечении данных о практике, отфильтрованных по пользователю и категории.

Я пробовал использовать django-filter на этой ссылке, но появляется ошибка.

Я добавил класс в views.py

class practiceFilter_Subcategory_User(generics.ListAPIView):
    queryset = Practice.objects.all()
    serializer_class = PracticeSerializer
    filter_fields = ('user', 'category')

Я добавил url в urls.py

urlpatterns = [ 
        url(r'^api/practice-filter-subcategory-user$', views.practiceFilter_Subcategory_User),
]

И я пытаюсь получить данные, отфильтрованные по всем user с id 1 и всем Math category, как показано ниже :

api/practice-filter-subcategory-user?user=1&category=Math

Но я потерпел неудачу и получил ошибку, как указано выше.

Можно ли отфильтровать все user по id 1 и все Math category?

Да, это возможно, фильтровать с большим количеством параметров. Django Rest Framework предоставляет нам множество вариантов для достижения этой цели. Я покажу вам одну из них: Filtering against query parameters. Вы можете переопределить .get_queryset() вашего представления на основе класса, чтобы работать с URL, такими как api/practice-filter-subcategory-user?user=1&category=Math

class practiceFilter_Subcategory_User(generics.ListAPIView):
    serializer_class = PracticeSerializer

    def get_queryset(self):
        # If they are no parameters return all objects
        queryset = Practice.objects.all()
        # Retrieve the query parameters in the url
        user_id = self.request.query_params.get('user_id')
        category = self.request.query_params.get('category')
        # If they are present
        if user_id is not None and category is not None:
            practice_filtered = exercises.filter(user__user_id=user_id)
            # Filter by category, you can chain filter of course
            practice_filtered = practice_filtered.filter(subcategory__category=category)
            queryset = practice_filtered
        return queryset

Вот документация DRF

ОЧЕНЬ ВАЖНО : Вам нужно вызвать .as_view() на ваших url представлениях вот так :

from django.conf.urls import url 
from yasn import views 

urlpatterns = [ 
    url(r'^api/practice-filter-user$', views.practiceFilter_User.as_view()),
    url(r'^api/practice-filter-subcategory-user$', views.practiceFilter_Subcategory_User.as_view()),
]
Вернуться на верх