【问题标题】:Django rest framework viewset get_queryset() doesn't return correct querysetDjango 休息框架视图集 get_queryset() 不返回正确的查询集
【发布时间】:2020-01-29 18:24:56
【问题描述】:

我正在使用 Django Rest Framework Filter 来访问我的数据。我为我的一个模型编写了一个自定义视图集,以处理对某些特定字段的逻辑“或”操作,以便通过 url 请求。

这是我的 ViewSet 类(打印只是为了我的调试)

class CustomViewSet(viewsets.ModelViewSet):

    permission_classes = (IsAuthenticated,)
    queryset = appart.MyModel.objects.order_by('pk')
    serializer_class = MyModelSerializer
    filter_class = MyModelFilter

    def get_queryset(self):

        # getting param

        query = dict(self.request.query_params)


        print(query)

        ct_query = query['caracteristique_text__icontains'][0].split('|')
        cl_query = query['caracteristique__libelle__in'][0].split(',')


        # writting request syntax
        ct = 'Q(caracteristique__libelle__in=' + str(cl_query) + ')&('

        print(ct)

        for value in ct_query:
            ct += "Q(caracteristique_text__icontains='" + value + "')|"

        ct = ct[0:len(ct) - 1]
        ct += ')'

        print(ct)


        filtre_text = "global filtre; filtre = " + ct


        # creating the request
        exec(filtre_text)


        #running the request
        self.queryset = self.queryset.filter(filtre)

        print(self.queryset)

        return self.queryset # doesn't return what I see when running print(self.queryset)

还有 MyModelFilter 类:

class MyModelFilter(ModelFilterSet):

    class Meta:
        model = appart.MyModel
        fields = ('id', 'libelle', 'locataire_appart', 'bien_appart', 
                    'adresse', 'loyer_appart', 'caracteristique', 'caracteristique_text', 
                    'date_creation', 'derniere_maj')

这段代码运行良好,可以做我想做的事。他获取 url 参数,动态创建请求语法并返回我正在寻找的数据。

唯一的问题是最后的返回结果与我在代码中打印的结果不同。他仍在尝试根据给定的 url 执行 GET 请求,并且当语法不遵循 django_filter 规则时不返回任何内容。

谁能帮助我防止我的视图集出现这种行为?

【问题讨论】:

  • 可以加入MyModelFilter吗?我认为使用 django_filter 功能是一个更好的主意。另外,您当前的方法存在一个重大安全漏洞,您允许外部用户在您的系统内执行代码(exec 调用。)
  • 嗨@schillingt,感谢您的回复和建议。我刚刚添加了 MyModelFilter 并意识到 exec 的大错误。我将寻找一种更好的方法来完成这个技巧,并希望过滤器类能帮助你找到问题所在。再次感谢!

标签: python django django-rest-framework


【解决方案1】:

您需要使用 Django 过滤器指定一些过滤器。我想你只需要BaseInFilter:https://django-filter.readthedocs.io/en/master/ref/filters.html#baseinfilter

class MyModelFilter(ModelFilterSet):
    caracteristique_text = BaseInFilter(field_name='caracteristique_text', lookup_exp='icontains')
    libelle = BaseInFilter(field_name='libelle', lookup_exp='in')

    class Meta:
        model = appart.MyModel
        fields = ('id', 'libelle', 'locataire_appart', 'bien_appart', 
                    'adresse', 'loyer_appart', 'caracteristique', 'caracteristique_text', 
                    'date_creation', 'derniere_maj')

【讨论】:

    【解决方案2】:

    好的,我终于解决了我的问题,代码没有错误。这是由于filter_class = MyModelFilter。我刚刚评论了这条线,一切都开始起作用了。老实说,我不知道为什么,但如果有人知道原因,我将不胜感激。

    我还查看了@schillingt 所说的exec,这是那些尝试做同样事情或遇到同样问题的人的结果。

    class CustomViewSet(viewsets.ModelViewSet):
    
        permission_classes = (IsAuthenticated,)
        queryset = models.MyModel.objects.order_by('pk')
        serializer_class = MyModelSerializer
        filter_class = MyModelFilter
    
        def get_queryset(self):
    
            query = dict(self.request.query_params)
    
            ct = self.request.query_params.get('caracteristique_text__icontains', None)
            cl = self.request.query_params.get('caracteristique__libelle__in', None)
    
            if ct is not None and cl is not None:
    
                self.filter_class = None
    
                ct_query = query['caracteristique_text__icontains'][0].split(',')
                cl_query = query['caracteristique__libelle__in'][0].split(',')
    
                full_query = Q(caracteristique__libelle__in=cl_query)
    
                ct = Q()
    
                for value in ct_query:
                    ct_part = Q(caracteristique_text__icontains=value)
                    ct |= ct_part
    
                full_query &= ct
    
                self.queryset = self.queryset.filter(full_query)
    
                return self.queryset
    
        return models.MyModel.objects.order_by('pk')
    
    

    这篇文章也可以提供帮助Filter with or condition

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-28
      • 2021-11-06
      • 2019-04-08
      • 2018-09-10
      • 2020-01-21
      • 2023-03-12
      • 2020-10-11
      • 2022-01-17
      相关资源
      最近更新 更多