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.
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,
.filter_queryset()
. O atributo .qs
será basicamente responsável por chamar .filter_queryset()
e armazenar em cache seu resultado.self.form.cleaned_data
.Muito obrigado pelo seu esforço!
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,
.filter_queryset()
. O atributo.qs
será basicamente responsável por chamar.filter_queryset()
e armazenar em cache seu resultado.self.form.cleaned_data
.