1

I want to retrieve data filtered by user and category.

I'm using 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),
]

In my database I have 3 practice data as below :

[
  {
    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,
  }
]

If the above code is executed to get practice data by user id = 1, the result is as below :

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,
  }
]

I want to retrieve data filtered by all user with id 1 and all Math category like below :

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,
  }
]

The results as above are what I want when retrieving practice data that is filtered by user and category.

I've tried using django-filter on this link but the error appears.

I added a class to views.py

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

I added url to urls.py

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

And I try to retrieve data filtered by all user with id 1 and all Math category like below :

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

But I failed and got the error as above.

Is it possible to filter all user by id 1 and all Math category?

Update the Traceback error I got :

Environment:


Request Method: GET
Request URL: http://192.168.1.2:8080/api/practice-filter-subcategory-user?user_id=1&category=Math

Django Version: 3.2.5
Python Version: 3.7.9
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'rest_framework_bulk',
 'yasn.apps.yasnConfig',
 'corsheaders',
 'django_filters']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.middleware.common.CommonMiddleware']



Traceback (most recent call last):
  File "C:\Users\Me\Documents\Python\env\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Me\Documents\Python\env\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)

Exception Type: TypeError at /api/practice-filter-subcategory-user
Exception Value: __init__() takes 1 positional argument but 2 were given

Update urls.py :

from django.conf.urls import url 
from yasn import views 
 
urlpatterns = [ 
        url(r'^api/practice-filter-user$', views.practiceFilter_User),
        url(r'^api/practice-filter-subcategory-user$', views.practiceFilter_Subcategory_User),
]
3
  • Verify your url in the get_queryset() the parameters retrieved are user_id, category your url contains user and category. Try to correct it and let us know Commented Sep 5, 2021 at 21:53
  • I've tried changing my url parameter from user to user_id and running the program but still showing the same error, I've updated the error in the question above using user_id in the url. Commented Sep 5, 2021 at 22:39
  • Sorry... You need always call the .as_view() method on class based view in Django. I have updated the url pattern in the answer. Commented Sep 6, 2021 at 9:42

1 Answer 1

2

Yes it is possible to filter with many parameters. Django Rest Framework provide us many options to achieve this goal. I'll show you one of them : Filtering against query parameters. You can override .get_queryset() of your class based view to deal with URLs such as 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

Here is the DRF documentation

VERY IMPORTANT : You need call .as_view() on your url views like this :

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()),
]
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the response, i have tried to follow your instructions but i get an error. I included the error at the end of my question above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.