Django-filter: Permitir anular la recuperación de un conjunto de consultas en un FilterSet

Creado en 21 jun. 2017  ·  4Comentarios  ·  Fuente: carltongibson/django-filter

El título puede resultar un poco confuso. Sería bueno tener un método filter genérico que se llama cada vez que se recupera el conjunto de consultas y se aplica el filtrado por campos. Sí, puedo anular la propiedad qs , primero obtener un conjunto de consultas filtrado y luego aplicar capturas previas. Pero _no está claro si esto puede tener algunos efectos secundarios y es seguro acceder a los datos que se pasan al filtro.

Ese es mi caso de uso.
Estoy filtrando un conjunto de consultas por una relación M2M (como en queryset.filter(items__field="foo") ). Sin embargo, también quiero que los elementos precargados se filtren por ese campo.

En otras palabras, mi filtro se ve así:

# In my filterset
def filter_items_by_field(self, queryset, name, value):
        queryset = queryset.all().filter(
            items__field=value,
        )
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                field=value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

# In my vieset
def get_queryset(self):
        queryset = super().get_queryset()
        # This should be applied everytime
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                another_field=some_value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

Un solo filtro como este funciona como se esperaba. Sin embargo, es posible que tenga varios filtros filter_items_by_* + Necesito aplicar el mismo filtrado para el conjunto de consultas desde la captación previa para todos los filtros. Y múltiples filtros no son un problema, porque son mutuamente excluyentes en mi caso. Pero un filtro + genérico provocará una excepción.

El punto es que puedo aplicar solo una captación previa para la misma búsqueda. Entonces, en mi caso, simplemente obtendré una excepción.

Tengo una solución temporal para este problema: todos los filter_items_by_* realizan un filtrado obligatorio en la captación previa.
Y en filter_queryset (después de aplicar el filtrado), si items no se obtienen previamente (lo que es malo ya que estoy inspeccionando los atributos protegidos de queryset), aplico la captura previa con el filtrado obligatorio. Pero debería haber una mejor manera de lidiar con situaciones como esta.

Espero que mi ejemplo sea lo suficientemente claro.

Comentario más útil

Hola @ Alexx-G. Una versión 2.0 todavía es una salida, pero habrá algunos cambios en la API que abordarán específicamente esta cuestión. En breve,

  • Querrá anular el método .filter_queryset() . El atributo .qs será básicamente responsable de llamar a .filter_queryset() y almacenar en caché su resultado.
  • Puede obtener los valores de filtro para la obtención previa de self.form.cleaned_data .

Todos 4 comentarios

Hola @ Alexx-G. Creo que esto podría ser posible con cierta coordinación entre el conjunto de filtros y las clases de filtros relevantes. Básicamente, el filtro agregaría una instancia Prefetch a su conjunto de filtros parent . FilterSet.qs simplemente llamaría prefetch_related cuando sea apropiado.

Dicho esto, ¿cuál es el caso de uso para esto? Yo diría que probablemente haya lugares más apropiados para manejar la captación previa.

Creo que esto podría ser posible con cierta coordinación entre el conjunto de filtros y las clases de filtros relevantes.

Ya resolví mi problema anulando la propiedad qs , pero nuevamente, no es obvio y no está documentado. En otras palabras, no puedo estar seguro de que algunos cambios internos en la clase base no afecten a mi conjunto de filtros (de acuerdo, he fijado la versión, pero de todos modos ...)

Dicho esto, ¿cuál es el caso de uso para esto? Yo diría que probablemente haya lugares más apropiados para manejar la captación previa.

Creo que describí arriba mi caso de uso. No tiene sentido separar el filtrado y la captación previa, porque la captación previa depende de los filtros. Y si los separo, tendré que duplicar las mismas comprobaciones para los filtros.

En otras palabras, si hubiera una descripción del contrato público de la propiedad qs o un gancho documentado para ello, esto mejoraría la personalización del conjunto de filtros.

Hola @ Alexx-G. Una versión 2.0 todavía es una salida, pero habrá algunos cambios en la API que abordarán específicamente esta cuestión. En breve,

  • Querrá anular el método .filter_queryset() . El atributo .qs será básicamente responsable de llamar a .filter_queryset() y almacenar en caché su resultado.
  • Puede obtener los valores de filtro para la obtención previa de self.form.cleaned_data .

¡Muchas gracias por su esfuerzo!

¿Fue útil esta página
0 / 5 - 0 calificaciones