简体   繁体   中英

Django rest framework viewset get_queryset() doesn't return correct queryset

I am working with Django Rest Framework Filter to access my data. I wrote a custom viewset for one of my models to handle logical 'or' operation on some specifics fields for request with url.

Here is my ViewSet Class (the printing are just for my debug)

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)

And MyModelFilter Class :

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

this code is working well and do what I want it to do. He takes the url parameters, create dynamically the request syntax and return the data i'm looking for.

The only problem is that the return at the end doesn't give the same result that what I printed in my code. He still trying to execute a GET request based on the given url and return nothing when the syntax is not following the django_filter rules.

Can anyone help me to prevent this behavior of my viewsets ?

You need to specify some filters with Django Filters. I think you just need 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')

Ok so I finally solved my problem, there were no mistake in the code. This was due to the filter_class = MyModelFilter . I just commented on this line and everything started to work. I honestly don't know why but i would appreciate a comment to this answer if anyone know the reason.

I also took a look on the exec that @schillingt was talking about and here is the result for those trying to do the same thing or having the same problem.

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

This post can also be helpful Filter with or condition

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM