Django-filter: (2.0) FilterView siempre devuelve QuerySet vacío para FilterSet independiente.

Creado en 29 jun. 2018  ·  19Comentarios  ·  Fuente: carltongibson/django-filter

Tengo una vista, AccountList , que está intentando representar una tabla django_table2. El código fuente de la vista:

class AccountList(SingleTableMixin, FilterView):
    model = Account
    table_class = AccountTable
    template_name = 'accounts/account_list.html'
    context_table_name = 'object_list'
    ordering = ['vps']

    filterset_class = AccountFilter

Esta vista utiliza actualmente este conjunto de filtros (de django_filters):

import django_filters
from accounts.models import Account

class AccountFilter(django_filters.FilterSet):
    class Meta:
        model = Account
        fields = ['is_suspended', 'is_abandoned']

    is_suspended = django_filters.BooleanFilter(name='is_suspended', initial='False')
    is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial='False')

    def __init__(self, data=None, *args, **kwargs):
        # if filterset is bound, use initial values as defaults
        if data is not None:
            # get a mutable copy of the QueryDict
            data = data.copy()

            for name, f in self.base_filters.items():
                initial = f.extra.get('initial')

                # filter param is either missing or empty, use initial as default
                if not data.get(name) and initial:
                    data[name] = initial

        super().__init__(data, *args, **kwargs)

Usando esta plantilla:

{% if filter %}
    <form action="" method="get" class="form form-inline">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
{% endif %}

{% render_table object_list %}

{% endblock %}

Este es mi de mi urls.py

path('', login_required(AccountList.as_view())),

Cuando visito mi página, 127.0.0.1:8000 , veo que los filtros no están configurados:
enter image description here

Pero luego, si hago 127.0.0.1:8000?page=1 , veo que los filtros se inicializan correctamente:

enter image description here

¿Qué hace que mis filtros no tengan un valor predeterminado cuando no tengo page = 1 anexada a mi URL?

Bug

Comentario más útil

Sí, comencé las relaciones públicas, pero tuve que suspender mi trabajo de código abierto. Debería poder retomar donde lo dejé bastante pronto.

Todos 19 comentarios

Intente usar un valor booleano False real en lugar del valor de cadena 'False' .

Entonces, cuando probé lo siguiente:

is_suspended = django_filters.BooleanFilter(name='is_suspended', initial=False)
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial=False)

Así es como se renderizan los filtros en 127.0.0.1:8000/

image

Aunque el filtro se renderizó con los valores correctos, el filtro no tuvo ningún efecto, ya que todavía puedo ver cuentas suspendidas o abandonadas.

Además, cuando visito la página 2 presionando el botón 2 en la parte inferior, llego a http://127.0.0.1:8000/?page=2 con los filtros restableciéndose a Unknown .

image

¿Ves alguna razón por la que?

Lo siento, no se me ocurre nada obvio.

Para el primer problema, recomendaría mirar la consulta SQL resultante. Asegúrese de que los filtros suspended y abandoned se estén aplicando realmente.
Para el segundo problema, comprobaría los datos entrantes. Es posible que se proporcione un valor no válido a los filtros suspended y abandoned al cambiar de página.

Inserté algunas declaraciones impresas y encontré lo siguiente:

def __init__(self, data=None, *args, **kwargs):
    if data is not None:        # 1
        data = data.copy()

        for name, f in self.base_filters.items():
            initial = f.extra.get('initial')   

            # filter param is either missing or empty, use initial as default
            if not data.get(name) and initial:
                data[name] = initial

    super(BaseFilterSet, self).__init__(data, *args, **kwargs)

Entonces parece que data es None . ¿Sabrá por qué mi vista basada en clases no pasa data a AccountFilter ?

Hm. El argumento data siempre debe ser proporcionado por FilterView .

https://github.com/carltongibson/django-filter/blob/b1f1c6592ef64a2172ec39040607a9c0b0714140/django_filters/views.py#L39 -L46

¿Está data vacío para la primera y la segunda página?

Esto no se puede abordar como está. Cierre pendiente de suficiente información para identificar un problema.

El mismo problema aquí después de la actualización a 2.0. La página predeterminada o el filtro vacío deben estar presentes en la URL para obtener los resultados. ¿Está esto al menos documentado en alguna parte?

Todavía necesito más información para poder reproducir ...

page ? ¿No tiene esto que ver con su paginación, en lugar del filtro Django?

¿Qué información se necesita exactamente? La actualización a 2.0 conduce al comportamiento descrito. La degradación a 1.1.0 hace que todo vuelva a la normalidad. Intenté simplificar la vista y el conjunto de filtros lo más minimalista posible, el comportamiento persiste, por lo que parece que esto debería ser bastante fácil de reproducir.

@moorchegue , un caso de prueba de ejemplo mínimo o un proyecto de prueba que demuestre el problema sería útil.

También parece que el problema es con lo que sea que esté proporcionando su lógica de paginación. Sí, puede haber alguna incompatibilidad con la nueva versión, pero los problemas de depuración en otros paquetes están fuera de alcance. Necesita demostrar un error en Django Filter para que haya algo que podamos hacer aquí.

Bien, entonces el problema aquí es con el método is_valid() introducido como parte de # 788.

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/filterset.py#L202 -L206

Esto devuelve automáticamente False cuando data es None .

En la vista, estamos configurando object_list en qs.none() .

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/views.py#L80 -L83

De ahí el comportamiento observado.

La prueba para esto no falla porque la plantilla de prueba usa filter.qs lugar de object_list .

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/tests/templates/tests/book_filter.html#L3 -L5

La solución inmediata es establecer strict = False en su conjunto de filtros. Esto tiene como consecuencia que los parámetros de filtro no válidos reales conducirán a un filtrado parcial en lugar de mostrar resultados vacíos, pero debería ser viable por ahora. (Mejor es anular la vista get lógica, por supuesto ...)

Pensaremos y mejoraremos el manejo del caso sin consolidar.

Hm. La principal deficiencia aquí es la disparidad entre object_list View y .qs FilterSet. Mover el comportamiento estricto de nuevo a FilterSet.qs solucionaría eso.

Además, no existe un manejo estricto / no estricto para el backend de DRF.

Limpiaré esto.

@rpkilby ¿Hay algún progreso en este tema?

Sí, comencé las relaciones públicas, pero tuve que suspender mi trabajo de código abierto. Debería poder retomar donde lo dejé bastante pronto.

Tenga en cuenta que la solución alternativa debería ser establecer strict = False en su descendiente FilterMixin (probablemente el View .

¿No puede simplemente cambiar la condición para devolver las qs en caso de forma ilimitada?

p.ej

-        if self.filterset.is_valid() or not self.get_strict():
+        if not self.filterset.is_bound or self.filterset.is_valid() or not self.get_strict():

https://github.com/carltongibson/django-filter/pull/1007

Gracias.

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