VikR
VikR

Reputation: 5142

Dynamically Build Q Filter in Django, with AND and OR Operators?

I have a database table of articles which includes a field link, which is the link to the article.

I'd like to filter for articles in a given date range, that come from domains in a given list.

I've got a string array like this:

domain_names = [
    'domain_name_1',
    'domain_name_2',
    'domain_name_3',
    'domain_name_4',
]

...and I have a filter like this which works:

data = (myArticles.objects
    .filter(Q(creation_datetime__range=[from_date, to_date]) & (Q(link__contains=domain_names[0]) | Q(link__contains=domain_names[1]) | Q(link__contains=domain_names[2]) | Q(link__contains=domain_names[3])))
    )

I'd like to dynamically build the filter, so that if an object is added to or removed from the domain_names list, the filter will dynamically update.

I've tried this:

q_object = Q()
    for name in domain_names:
        q_object.add(Q(link__contains=name), Q.OR)

    q_object = q_object.add(Q(creation_datetime__range=[from_date, to_date]), Q.AND)

...but I'm getting back all the objects in the date range, and the filter that's supposed to be filtering on domain_names isn't doing anything yet.

What's the correct way to dynamically build a Q filter in this case?

Upvotes: 2

Views: 188

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

You can work with:

q_object = Q(
    *[Q(link__contains=name) for name in domain_names],
    _connector=Q.OR
)

and then retrieve data with:

data = myArticles.objects.filter(
    q_object,
    creation_datetime__range=(from_date, to_date)
)

Upvotes: 5

Related Questions