Django-filter: Permitir sobrescrever a recuperação de um queryset em um FilterSet

Criado em 21 jun. 2017  ·  4Comentários  ·  Fonte: carltongibson/django-filter

O título pode ser um pouco confuso. Seria bom ter um método filter genérico, que é chamado toda vez que queryset é recuperado e a filtragem de campos é aplicada. Sim, posso substituir a propriedade qs , primeiro obter o queryset filtrado e depois aplicar as pré-buscas. Mas _não está claro se isso pode ter alguns efeitos colaterais e os dados passados ​​para o filtro são de acesso seguro._

Esse é o meu caso de uso.
Estou filtrando um queryset por um relacionamento M2M (como em queryset.filter(items__field="foo") ). No entanto, quero obter itens pré-buscados filtrados por esse campo também.

Em outras palavras, meu filtro é parecido com este:

# 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)

Um único filtro como esse funciona conforme o esperado. No entanto, posso ter vários filtros filter_items_by_* + preciso aplicar a mesma filtragem para queryset da pré-busca para todos os filtros. E vários filtros não são um problema, porque eles são mutuamente exclusivos no meu caso. Mas um filtro + genérico causará uma exceção.

A questão é que posso aplicar apenas uma pré-busca para a mesma pesquisa. Portanto, no meu caso, simplesmente receberei uma exceção.

Eu tenho uma solução temporária para este problema: todos os filter_items_by_* executam a filtragem obrigatória na pré-busca.
E em filter_queryset (depois que a filtragem foi aplicada), se items não forem pré-buscados (o que é ruim, já que estou inspecionando atributos protegidos por queryset), eu aplico pré-busca com a filtragem obrigatória. Mas deveria haver uma maneira melhor de lidar com situações como essa.

Espero que meu exemplo seja claro o suficiente.

Comentários muito úteis

Olá, @ Alexx-G. Uma versão 2.0 ainda está longe, mas haverá algumas mudanças na API que tratam especificamente dessa questão. Resumidamente,

  • Você desejará substituir o método .filter_queryset() . O atributo .qs será basicamente responsável por chamar .filter_queryset() e armazenar em cache seu resultado.
  • Você pode obter os valores de filtro para pré-busca de self.form.cleaned_data .

Todos 4 comentários

Olá, @ Alexx-G. Acho que isso poderia ser possível com alguma coordenação entre o conjunto de filtros e as classes de filtro relevantes. Essencialmente, o filtro acrescentaria uma instância Prefetch ao seu conjunto de filtros parent . FilterSet.qs simplesmente chamaria prefetch_related quando apropriado.

Dito isso, qual é o caso de uso para isso? Eu diria que provavelmente existem lugares mais apropriados para lidar com a pré-busca.

Acho que isso poderia ser possível com alguma coordenação entre o conjunto de filtros e as classes de filtro relevantes.

Já resolvi meu problema substituindo a propriedade qs , mas, novamente, não é óbvio e não está documentado. Em outras palavras, não posso ter certeza de que algumas mudanças internas na classe base não afetarão meu conjunto de filtros (ok, fixei a versão, mas enfim ..)

Dito isso, qual é o caso de uso para isso? Eu diria que provavelmente existem lugares mais apropriados para lidar com a pré-busca.

Acredito ter descrito acima meu caso de uso. Não faz sentido separar a filtragem e a pré-busca, porque a pré-busca depende dos filtros. E se eu separá-los, terei que duplicar as mesmas verificações para filtros.

Em outras palavras, se houvesse uma descrição do contrato público da propriedade qs ou um gancho documentado para ele, isso melhoraria a personalização do conjunto de filtros.

Olá, @ Alexx-G. Uma versão 2.0 ainda está longe, mas haverá algumas mudanças na API que tratam especificamente dessa questão. Resumidamente,

  • Você desejará substituir o método .filter_queryset() . O atributo .qs será basicamente responsável por chamar .filter_queryset() e armazenar em cache seu resultado.
  • Você pode obter os valores de filtro para pré-busca de self.form.cleaned_data .

Muito obrigado pelo seu esforço!

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