-
Notifications
You must be signed in to change notification settings - Fork 770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filter on multiple fields with OR condition #1134
Comments
Thanks for opening this, this is exactly the same question I have. Currently, I am getting the following warning: /usr/local/lib/python3.7/site-packages/django_filters/rest_framework/backends.py:128:
UserWarning: <class 'project.api.views.FooBarViewSet'> is not compatible with schema generation And I have a FilterSet and ViewSet that looks like this: # models
class FooBarUserAssignment(models.Model):
user = models.ForeignKey("auth.User", on_delete=models.CASCADE)
foobar = models.ForeignKey("FooBar", on_delete=models.CASCADE)
class Meta:
unique_together = (
("user", "foobar"),
)
class FooBarGroupAssignment(models.Model):
group = models.ForeignKey("auth.Group", on_delete=models.CASCADE)
foobar = models.ForeignKey("FooBar", on_delete=models.CASCADE)
class Meta:
unique_together = (
("group", "foobar"),
)
class FooBar(models.Model):
title = models.CharField(max_length=160, unique=True)
users = models.ManyToManyField(
to="auth.User",
through=FooBarUserAssignment,
)
groups = models.ManyToManyField(
to="auth.Group",
through=FooBarGroupAssignment,
)
def __str__(self):
return self.title
# filters
from django_filters import rest_framework as rest_framework_filters
class FooBarFilter(rest_framework_filters.FilterSet):
title = rest_framework_filters.CharFilter(field_name="title", lookup_expr="icontains")
class Meta:
model = FooBar
fields = ("title", )
# viewsets
class FooBarViewSet(ModelViewSet):
queryset = Foobar.objects.order_by("-title")
serializer_class = FooBarSerializer
filterset_class = FooBarFilter
def get_queryset(self):
queryset = self.queryset
q_name = Q()
rel_name = self.request.query_params.get("rel_name", None)
if rel_name:
q_name = Q(users__name=rel_name)
q_groups = Q()
rel_groups = self.request.query_params.get("rel_groups", "").split(",")
if any(rel_groups):
q_groups = Q(groups__name__in=rel_groups)
qs = queryset.filter(q_name | q_groups).distinct()
return qs How could I build a FilterSet to execute the exact same query? import django_filters
from django_filters import rest_framework as rest_framework_filters
class CharInFilter(django_filters.BaseInFilter, rest_framework_filters.CharFilter):
pass
class FooBarFilter(rest_framework_filters.FilterSet):
title = rest_framework_filters.CharFilter(field_name="title", lookup_expr="icontains")
rel_name = rest_framework_filters.CharFilter(field_name="users__name", lookup_expr="exact")
rel_groups = CharInFilter(field_name="groups__name")
class Meta:
model = FooBar
fields = ("title", )
def filter_queryset(self, queryset):
qs = super().filter_queryset(queryset)
return qs.distinct() |
It looks like this is part of this extension of django-filter that can be installed along side django-filter. https://github.com/philipn/django-rest-framework-filters#complex-operations |
Hi all. I've created #1167, which should provide group-level validation and filtering. For the OP, usage would look something like: class UserFilter(FilterSet):
class Meta:
model = User
field = ['username', 'first_name', 'last_name']
groups = [
CombinedGroup(filters=['first_name', 'last_name'], combine=operator.or_),
] Any feedback on the PR would be greatly appreciated. |
Still the same issue here, are their any solutions yet? |
@JeromeK13 looks like nothing yer! I have same question |
I've done something like the following, I'm not sure works for all cases but solved my problem: class BaseFilter(django_filters.FilterSet):
def OR(self, queryset, field_name, value):
if not hasattr(self, "groups"):
setattr(self, "groups", {})
self.groups[field_name] = value
return queryset
@property
def qs(self):
base_queryset = super().qs
if not hasattr(self, "groups"):
return base_queryset
query = Q()
for key, value in self.groups.items():
query |= Q(**{key: value})
return base_queryset.filter(query) class PlanFilter(BaseFilter):
double_visit__or = django_filters.UUIDFilter("double_visit", method="OR")
visitor__or = django_filters.UUIDFilter("visitor", method="OR")
class Meta:
model = models.Plan
fields = {
"id": ["exact"],
"date": ["exact", "gte", "lte",],
"visitor": ["exact"],
"doctor": ["exact"],
"double_visit": ["exact"]
} |
I believe I found a much much simpler way:
In my case, I wanted to gather all the rows that where have spesific |
Import Qdjango.db.models import Q It worked for me. |
it worked for me too. |
This #1134 (comment) worked for me too.
|
This comment was marked as off-topic.
This comment was marked as off-topic.
You can do one thing that is call for two query set separately and then chain them q1=QMODEL.Course.objects.all().filter(student_id=id1) |
Into FilterSet class, add: `
Additionally, can add into init method:
|
Hi, i can't import CombinedGroup from django-filter, there is problem? i use django-filter==22.1 |
@mohsnMohsni That is tied to his PR, is not part of django_filters |
@mohammadhasanzadeh I will advise you to use https://github.com/cloudblue/django-rql, it supports all kinds of complex operations which currently aren't supported in django-filter. |
Here's what I came up with to solve this, not ideal as I'd have liked class ActivityFilter(OrganisationalFilter):
class Meta:
model = Activity
fields = dict(
{
"task__project__id": [
"in",
],
"id_from_client": [
"exact",
],
"activity_type": [
"in",
],
"time": ["gte", "lte"],
},
**OrganisationalFilter.Meta.fields,
)
def filter_queryset(self, queryset):
interim_qs = queryset.filter(
(
Q(user__id__in=self.data["user__id__in"].split(","))
if "user__id__in" in self.data
else Q(user__isnull=False)
)
| (
Q(user__groups__id__in=self.data["user__groups__id__in"].split(","))
if "user__groups__id__in" in self.data
else Q(user__isnull=False)
)
| (
Q(
user__departments__id__in=self.data[
"user__departments__id__in"
].split(",")
)
if "user__departments__id__in" in self.data
else Q(user__isnull=False)
)
)
qs = super().filter_queryset(interim_qs)
return qs |
Hi,
How possible to filter on multiple fields with OR condition!?
For example:
first_name = foo OR last_name = bar
Equivalent to:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
The text was updated successfully, but these errors were encountered: