Hola,
¿Cómo es posible filtrar en múltiples campos con la condición OR?
Por ejemplo:
first_name = foo OR last_name = bar
Equivalente a:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
Gracias por abrir esto, esta es exactamente la misma pregunta que tengo.
Actualmente, recibo la siguiente advertencia:
/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
Y tengo un FilterSet y ViewSet que se ve así:
# 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
¿Cómo podría crear un FilterSet para ejecutar exactamente la misma consulta?
Pude implementar parte de FilterSet, pero aún no sé cuál es la mejor manera de mover la lógica OR
de ViewSet.get_queryset()
a 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()
Parece que esto es parte de esta extensión de django-filter que se puede instalar junto con django-filter. https://github.com/philipn/django-rest-framework-filters#complex -operaciones
Hola a todos. He creado #1167, que debería proporcionar validación y filtrado a nivel de grupo. Para el OP, el uso se vería así:
class UserFilter(FilterSet):
class Meta:
model = User
field = ['username', 'first_name', 'last_name']
groups = [
CombinedGroup(filters=['first_name', 'last_name'], combine=operator.or_),
]
Cualquier comentario sobre las relaciones públicas sería muy apreciado.
Sigue siendo el mismo problema aquí, ¿hay alguna solución ya?
¡@JeromeK13 no parece nada! tengo la misma pregunta
Hice algo como lo siguiente, no estoy seguro de que funcione para todos los casos, pero resolví mi problema:
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"]
}
Creo que encontré una manera mucho más 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))
En mi caso, quería reunir todas las filas que tenían sender_id
o receiver_id
específicos. Y quería que estuvieran en un conjunto de consultas para ordenarlos por date
Hola,
¿Cómo es posible filtrar en múltiples campos con la condición OR?
Por ejemplo:
first_name = foo OR last_name = bar
Equivalente a:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))
django.db.models importar Q
Funcionó para mí.
Comentario más útil
Hice algo como lo siguiente, no estoy seguro de que funcione para todos los casos, pero resolví mi problema: