Hallo,
Wie ist es möglich, nach mehreren Feldern mit ODER-Bedingung zu filtern!?
Beispielsweise:
first_name = foo OR last_name = bar
Gleichwertig:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
Danke für die Eröffnung, das ist genau die gleiche Frage, die ich habe.
Aktuell bekomme ich folgende Warnung:
/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
Und ich habe ein FilterSet und ein ViewSet, das so aussieht:
# 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
Wie könnte ich ein FilterSet erstellen, um genau dieselbe Abfrage auszuführen?
Ich konnte einen Teil von FilterSet implementieren, weiß aber immer noch nicht, wie ich die OR
-Logik am besten von ViewSet.get_queryset()
nach FilterSet
verschieben kann
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()
Es sieht so aus, als ob dies Teil dieser Erweiterung von django-filter ist, die zusammen mit django-filter installiert werden kann. https://github.com/philipn/django-rest-framework-filters#complex -operations
Hallo zusammen. Ich habe #1167 erstellt, das eine Validierung und Filterung auf Gruppenebene ermöglichen sollte. Für das OP würde die Verwendung in etwa so aussehen:
class UserFilter(FilterSet):
class Meta:
model = User
field = ['username', 'first_name', 'last_name']
groups = [
CombinedGroup(filters=['first_name', 'last_name'], combine=operator.or_),
]
Jedes Feedback zur PR wäre sehr willkommen.
Immer noch das gleiche Problem hier, gibt es schon Lösungen?
@JeromeK13 sieht aus wie nichts! Ich habe dieselbe Frage
Ich habe so etwas wie das Folgende getan, ich bin mir nicht sicher, ob es für alle Fälle funktioniert, aber mein Problem gelöst:
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
<strong i="6">@property</strong>
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"]
}
Ich glaube, ich habe einen viel einfacheren Weg gefunden:
from django.db.models.query_utils import Q
user_contacts = Contact.objects.order_by('-contact_date').filter(Q(sender_id=request.user.user_id)|Q(receiver_id=request.user.user_id))
In meinem Fall wollte ich alle Zeilen sammeln, die bestimmte sender_id
oder receiver_id
enthalten. Und ich wollte, dass sie in einem Abfragesatz enthalten sind, um sie nach date
zu sortieren
Hallo,
Wie ist es möglich, nach mehreren Feldern mit ODER-Bedingung zu filtern!?
Beispielsweise:
first_name = foo OR last_name = bar
Gleichwertig:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
django.db.models importiert Q
Es hat für mich funktioniert.
Hilfreichster Kommentar
Ich habe so etwas wie das Folgende getan, ich bin mir nicht sicher, ob es für alle Fälle funktioniert, aber mein Problem gelöst: