Salut,
Comment filtrer sur plusieurs champs avec la condition OU ! ?
Par example:
first_name = foo OR last_name = bar
Équivalent à:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
Merci d'avoir ouvert ceci, c'est exactement la même question que je me pose.
Actuellement, je reçois l'avertissement suivant :
/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
Et j'ai un FilterSet et un ViewSet qui ressemble à ceci :
# 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
Comment puis-je créer un FilterSet pour exécuter exactement la même requête ?
J'ai pu implémenter une partie de FilterSet, mais je ne sais toujours pas quelle est la meilleure façon de déplacer la logique OR
de ViewSet.get_queryset()
à FilterSet
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()
Il semble que cela fasse partie de cette extension de django-filter qui peut être installée à côté de django-filter. https://github.com/philipn/django-rest-framework-filters#complex -operations
Salut tout le monde. J'ai créé #1167, qui devrait fournir une validation et un filtrage au niveau du groupe. Pour l'OP, l'utilisation ressemblerait à :
class UserFilter(FilterSet):
class Meta:
model = User
field = ['username', 'first_name', 'last_name']
groups = [
CombinedGroup(filters=['first_name', 'last_name'], combine=operator.or_),
]
Tout commentaire sur le PR serait grandement apprécié.
Toujours le même problème ici, y a-t-il encore des solutions?
@JeromeK13 ne ressemble à rien ! j'ai la même question
J'ai fait quelque chose comme ce qui suit, je ne suis pas sûr que cela fonctionne pour tous les cas, mais j'ai résolu mon problème:
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"]
}
Je crois que j'ai trouvé un moyen beaucoup plus simple:
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))
Dans mon cas, je voulais rassembler toutes les lignes qui avaient des sender_id
ou receiver_id
. Et, je voulais qu'ils soient dans un ensemble de requêtes pour les ordonner par date
Salut,
Comment filtrer sur plusieurs champs avec la condition OU ! ?
Par example:
first_name = foo OR last_name = bar
Équivalent à:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
django.db.models importer Q
Cela a fonctionné pour moi.
Commentaire le plus utile
J'ai fait quelque chose comme ce qui suit, je ne suis pas sûr que cela fonctionne pour tous les cas, mais j'ai résolu mon problème: