Django-filter: (2.0) FilterView sempre retornando QuerySet vazio para FilterSet não ligado.

Criado em 29 jun. 2018  ·  19Comentários  ·  Fonte: carltongibson/django-filter

Eu tenho um modo de exibição, AccountList , que está tentando renderizar uma tabela django_table2. O código-fonte da visualização:

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 visualização está usando 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 este modelo:

{% 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 é meu de meu urls.py

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

Quando visito minha página, 127.0.0.1:8000 , vejo que os filtros não estão definidos:
enter image description here

Mas então, se eu fizer 127.0.0.1:8000?page=1 , vejo que os filtros foram inicializados corretamente:

enter image description here

O que está fazendo com que meus filtros não tenham o valor padrão quando não tenho page = 1 anexado ao meu url?

Bug

Comentários muito úteis

Sim - comecei o PR, mas tive que colocar meu trabalho de código aberto em espera. Devo ser capaz de retomar de onde parei em breve.

Todos 19 comentários

Tente usar um valor booleano False real em vez do valor da string 'False' .

Então, quando tentei o seguinte:

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

É assim que os filtros são renderizados em 127.0.0.1:8000/

image

Embora o filtro tenha sido renderizado com os valores corretos, o filtro não teve efeito, pois ainda posso ver contas suspensas ou abandonadas.

Além disso, quando visito a página 2 pressionando o botão 2 na parte inferior, chego a http://127.0.0.1:8000/?page=2 com os filtros redefinidos para Unknown .

image

Você vê alguma razão para isso?

Desculpe - nada óbvio vem à mente.

Para o primeiro problema, eu recomendo olhar a consulta SQL resultante. Certifique-se de que os filtros suspended e abandoned estejam realmente sendo aplicados.
Para o segundo problema, eu verificaria os dados de entrada. É possível que um valor inválido esteja sendo fornecido aos filtros suspended e abandoned ao alterar as páginas.

Inseri algumas declarações de impressão e encontrei o seguinte:

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)

Portanto, parece que data é None . Você saberá por que minha visão baseada em classe não está passando data para AccountFilter ?

Hm. O argumento data deve sempre ser fornecido por FilterView .

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

data vazio para a primeira e a segunda página?

Isso não é endereçável como está. Fechamento pendente com informações suficientes para identificar um problema.

O mesmo problema aqui após a atualização para 2.0. A página padrão ou o filtro vazio devem estar presentes no URL para obter os resultados. Isso está pelo menos documentado em algum lugar?

Ainda preciso de mais informações para poder reproduzir ...

page ? Isso não tem a ver com sua paginação, em vez do Filtro Django?

Quais informações são necessárias exatamente? Atualizar para 2.0 leva ao comportamento descrito. O downgrade para 1.1.0 faz com que tudo volte ao normal. Tentei simplificar a visualização e o conjunto de filtros para o mais minimalista possível, o comportamento persiste, então parece que isso deve ser bastante fácil de reproduzir.

@moorchegue , um caso de teste de exemplo mínimo ou projeto de teste que demonstre o problema seria útil.

Também parece que o problema está em tudo o que está fornecendo sua lógica de paginação. Sim, pode haver alguma incompatibilidade com a nova versão, mas a depuração de problemas em outros pacotes está fora do escopo. Você precisa demonstrar um bug no Filtro do Django para que haja algo que possamos fazer aqui.

OK, então o problema aqui é com o método is_valid() introduzido como parte de # 788.

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

Isso retorna automaticamente False quando data for None .

Na visualização, estamos definindo object_list como qs.none() .

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

Daí o comportamento observado.

O teste para isso não está falhando porque o modelo de teste está usando filter.qs vez de object_list .

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

A solução imediata é definir strict = False em seu conjunto de filtros. Isso tem a conseqüência de que parâmetros de filtro inválidos reais levarão à filtragem parcial em vez de mostrar resultados vazios, mas deve ser viável por enquanto. (Melhor é substituir a lógica de visão get , é claro ...)

Teremos uma reflexão e melhoraremos o manuseio do case não acoplado.

Hm. A deficiência principal aqui é a disparidade entre o Ver object_list de eo filterset .qs . Mover o comportamento estrito de volta para FilterSet.qs consertaria isso.

Além disso, não há tratamento estrito / não estrito para o back-end DRF.

Vou limpar isso.

@rpkilby Há algum progresso nessa questão?

Sim - comecei o PR, mas tive que colocar meu trabalho de código aberto em espera. Devo ser capaz de retomar de onde parei em breve.

Observe que a solução alternativa deve ser definir strict = False em seu FilterMixin descendente (provavelmente o View .

Você não pode simplesmente alterar a condição para retornar o qs no caso de forma ilimitada?

por exemplo

-        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

Obrigado.

Esta página foi útil?
0 / 5 - 0 avaliações