52
You can create querysets with the Q
constructor and combine them with the |
operator to get their union:
from django.db.models import Q
def companies_matching(merchants):
"""
Return a queryset for companies whose names contain case-insensitive
matches for any of the `merchants`.
"""
q = Q()
for merchant in merchants:
q |= Q(name__icontains = merchant)
return Companies.objects.filter(q)
(And similarly with iexact
instead of icontains
.)
5
I find it a cleaner approach using reduce
and or_
operator:
from django.db.models import Q
from functools import reduce
from operator import or_
def get_companies_from_merchants(merchant_list):
q_object = reduce(or_, (Q(name__icontains=merchant) for merchant in merchant_list))
return Companies.objects.filter(q_object)
This would create a list of Q
objects querying the name
to contain a single element in merchant list. This would happpen for all the elements in merchant_list
and all these Q
objects would be reduced to a single Q
object having mutliple ORs which can be directly applied to the filter query.
- [Django]-Handle `post_save` signal in celery
- [Django]-Django Left Outer Join
- [Django]-How do you use get_context_data with TemplateView in Django
4
This is the approach that I adopted:
class MyManager(models.Manager):
def exclusive_in(self, lookup, value_list):
return self.filter(reduce(or_, (Q(**{lookup:_}) for _ in value_list)))
Here is now to use it:
Companies.objects.exclusive_in('name__icontains', possible_merchants])
It was inspired by other answers in this thread, as well as Django filter queryset __in for *every* item in list.
- [Django]-How to get Request.User in Django-Rest-Framework serializer?
- [Django]-In django, how do I call the subcommand 'syncdb' from the initialization script?
- [Django]-How to use custom AdminSite class?
0
Another approach would be to simulate the actions that Django normally does for iexact
queries (it converts both parts of the comparison statement to the upper case via SQL Upper function.
This way, the query will look like this:
Companies.objects.annotate(
upper_name=models.Upper("name")
).filter(
upper_name__in=[rchant.upper() for merchant in possible_merchants]
)
- [Django]-How do you return 404 when resource is not found in Django REST Framework
- [Django]-Choose test database?
- [Django]-Django β The included urlconf doesn't have any patterns in it
0
The answer from Gareth Rees helped me a lot with a similar issue while using the django-filter package.
To use this with django_filters
in generic way one could create a MultipleInputs filter like this:
class MultipleInputs(filters.BaseInFilter, filters.CharFilter):
pass
Then use that in the filterset and use a custom filtering method:
from django.db.models import Q
class MyFilter(FilterSet):
search = MultipleInputs(field_name='longname', label='Text search',
method='multiplesearch',
help_text="Free text search. May be a comma separated list of strings.")
def multiplesearch(self, queryset, field_name, value):
q = Q()
for searchstring in value:
arguments = {field_name+'__icontains' : searchstring}
q |= Q(**arguments)
return queryset.filter(q)
No MultiInputs fields can have comma separated inputs.
Also works if you inherit MyFilter but overwrite search with a Filter with a different field_name.
- [Django]-Django staticfiles not found on Heroku (with whitenoise)
- [Django]-Adding custom fields to users in Django
- [Django]-Django β Reverse for '' not found. '' is not a valid view function or pattern name
0
using iregex would be:
regex = '|'.join(['match 1', 'match 2', 'match 3'])
Companies.objects.filter(name__iregex=f'({regex})')
You can even add lookaround so that matches are guaranteed to be individual words, rather than parts of other words with different meaning ie:
options = ['match 1', 'match 2', 'match 3']
regex_options = [f'(?<!\w){option}(?!\w)' for option in options] # Adds lookaround
regex = '|'.join(regex_options)
Companies.objects.filter(name__iregex=f'({regex})')
lookaround (ie lookbehind + lookahead) will not incur in character consumption therefore itβll match with substrings starting or ending strings, that wouldβt be possible with [^\w].
- [Django]-Django β How to make a variable available to all templates?
- [Django]-Django Forms and Bootstrap β CSS classes and <divs>
- [Django]-In Django 1.9, what's the convention for using JSONField (native postgres jsonb)?