如何使用 Django-filter 过滤多个字段?

Posted

技术标签:

【中文标题】如何使用 Django-filter 过滤多个字段?【英文标题】:How to filter multiple fields using Django-filter? 【发布时间】:2021-11-02 23:24:50 【问题描述】:

我想检索按用户和类别过滤的数据。

我正在使用 Django Rest 框架。

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

如果执行上述代码通过user id = 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,
  
]

我想检索由 ID 为 1 的所有 user 和所有 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,
  
]

上面的结果是我在检索按用户和类别过滤的练习数据时想要的。

我已尝试在此 link 上使用 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

但是我失败了,得到了如上的错误。

是否可以按 id 1 过滤所有user 和所有Math category

更新我得到的 Traceback 错误:

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

更新 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),
]

【问题讨论】:

请将整个回溯作为文本发布(在错误页面上的“切换到复制粘贴视图”按钮旁边),而不仅仅是几行图片。 感谢您的回复,我已经包含了上面的错误回溯更新。 你能把你的url文件贴在这里吗? 我在上面的问题末尾包含了 urls.py。 验证你的urlget_queryset()中检索到的参数是user_idcategory你的url包含usercategory。尝试更正它并告诉我们 【参考方案1】:

是的,可以使用许多参数进行过滤。 Django Rest Framework 为我们提供了许多选项来实现这一目标。我将向您展示其中之一:Filtering against query parameters。 您可以覆盖基于类的视图的 .get_queryset() 以处理诸如 api/practice-filter-subcategory-user?user=1&category=Math

之类的 URL
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 documentation

非常重要:您需要在您的url 视图上调用.as_view(),如下所示:

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

【讨论】:

感谢您的回复,我已尝试按照您的指示进行操作,但出现错误。我在上面的问题末尾包含了错误。

以上是关于如何使用 Django-filter 过滤多个字段?的主要内容,如果未能解决你的问题,请参考以下文章

Django-Filter:外键字段上的多个 select2 选择

Django-Filter 包:如何过滤对象以创建统计信息而不是列表

你如何使用带有参数列表的 django-filter 包?

带有 DRF 的 Django-filter - 如何在使用相同查找应用多个值时执行“和”?

如何在 ListAPIView 中使用 django-filter 对过滤结果进行排序

Django-filter:按模型属性过滤