Skip to content Skip to sidebar Skip to footer

Icontains And Getlist Django Python

We are trying to return a list of titles for the Django API, in which the title can have a few keywords. So for instance, if we use the __icontains method to search for 'money' and

Solution 1:

You can not perform an __icontains with a list, but you can for example design a function that, for a list constructs the logical or of these values. For example:

from django.db.models import Q
from functools import reduce
from operator import or_

defor_fold(list_of_qs):
    if list_of_qs:
        return reduce(or_, list_of_qs)
    else:
        return Q()

defunroll_lists_or(qs, **kwargs):
    return qs.filter([
        or_fold(Q(**{k: vi}) for vi in v)
        for k, v in kwargs.items()
    ])

You can then call the unroll_lists_or with a queryset, and each item should be an iterable (for example a list). It will then perform or-logic between the items of the list, and and-logic between different keys. In case an iterable is empty, it is ignored.

So we can then write the check as:

unroll_lists_or(queryset, news_title__icontains=title, news_source=source)

In case title contains two items (so title == [title1, title2]), and source contains three items (so source = [source1, source2, source3]), then this will result in:

qs.filter(
    Q(news_title__icontains=title1) | Q(news_title__icontains=title2),
    Q(news_source=source1) | Q(news_source=source2) | Q(news_source=source3)
)

You can however combine it with an .filter(..) for the __in check. For example:

queryset = News.objects.all()
ifsource:
    queryset = queryset.filter(news_source__in=source)
queryset = unroll_lists_or(queryset, news_title__icontains=title)

Solution 2:

I was able to solve this by creating 2 separate functions within the get_querset() function, which is called when a GET request is made.

 def get_queryset(self):
        queryset = News.objects.all()
        source_list = self.request.query_params.getlist('source')
        keyword_list = self.request.query_params.getlist('title')
        if source_list or keyword_list:
            def create_q_source(*args):
                list = [*args]
                source = Q()
                for value in list:
                    source.add(Q(news_source=value), Q.OR)
                return source
            def create_q_keyword(*args):
                list = [*args]
                keyword = Q()
                for value in list:
                    keyword.add(Q(news_title__icontains=value), Q.OR)
                return keyword
            queryset = queryset.filter(create_q_source(*source_list),create_q_keyword(*keyword_list))
        return queryset

Edit: When you go to the api link and pass in the parameters, filtering will occur based on what is passed in:

http://127.0.0.1:8000/api/notes/?keyword=trump&keyword=beyond&keyword=money&source=1

SQL Equivalent:

select*from news where news_source =1AND news_title like'%beyond%'OR news_title like'%money%'

Post a Comment for "Icontains And Getlist Django Python"