Django-filter: Gerar uma exceção se os campos não forem fornecidos no FilterSet

Criado em 28 set. 2016  ·  11Comentários  ·  Fonte: carltongibson/django-filter

class BooksFilter(filters.FilterSet):
    class Meta:
        model = Books

Ao omitir a opção fields em uma classe de conjunto de filtros (como acima), todos os campos do modelo serão incluídos no conjunto de filtros. Isso pode levar ao vazamento de informações quando usado em conjunto com DRF, onde o formulário é renderizado na API navegável.

Tanto o Django quanto o DRF exigem que os campos sejam especificados explicitamente em formulários/serializadores devido aos possíveis problemas de segurança. Isso também deve ser necessário em conjuntos de filtros django-filter.
http://www.django-rest-framework.org/api-guide/serializers/#specifying -which-fields-to-include
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#selecting -the-fields-to-use

Fico feliz em contribuir com um PR ou explicar mais sobre em quais situações isso pode levar ao vazamento de informações, se necessário.

ImprovemenFeature

Comentários muito úteis

btw - o vazamento de dados foi parcialmente resolvido pelo #451. No momento, você deve ver avisos de descontinuação sobre comportamento indefinido/alterado. Na versão 1.0, o novo comportamento é que um ausente Meta.fields ou Meta.fields = None não faz nada.

Todos 11 comentários

@nip3o Sim. Feliz em ver isso.

Eu também gostaria que os campos exigissem filtros declarados, conforme DRF, enquanto você está nisso... 😉

btw - o vazamento de dados foi parcialmente resolvido pelo #451. No momento, você deve ver avisos de descontinuação sobre comportamento indefinido/alterado. Na versão 1.0, o novo comportamento é que um ausente Meta.fields ou Meta.fields = None não faz nada.

Eu também gostaria que os campos exigissem filtros declarados, conforme DRF, enquanto você está nisso

Não tenho certeza de como isso funcionaria com a sintaxe dict para Meta.fields . por exemplo:

class UserFilter(filters.FilterSet):
    username = filters.CharFilter()

    class Meta:
        model = User
        fields = {
            'name': ['contains', 'startswith', 'endswith', ...'],
            ???
        }

Não tenho certeza de como isso funcionaria com a sintaxe dict

De fato.

Ainda estou meio :-1: nisso. Não vejo uma maneira de resolver a sintaxe dict Meta.fields com filtros declarados. Pelo menos, não de uma maneira que não seja estranha:

class UserFilter(filters.FilterSet):
    username = filters.CharFilter(name='username', lookup_expr='exact')
    username_like = filters.CharFilter(name='username', lookup_expr='icontains')
    relevance = filters.CharFilter(method='filter_relevance')

    class Meta:
        model = User
        fields = {
            'name': ['contains', 'startswith', 'endswith', ...'],
            'username': ['exact'],  # match w/ the lookup_expr? 
            'username_like': ['icontains'],
            'relevance': [???]  # What about method filters?
        }

Além disso, esse requisito gera problemas para campos de modelo personalizados que não herdam uma classe de campo encontrada no FilterSet.FILTER_DEFAULTS . Os campos personalizados exigiriam o seguinte:

class NetworkSettingFilter(FilterSet):
    mask = MaskFilter(...)

    class Meta:
        model = NetworkSetting
        fields = ['mask']
        filter_overrides = {
            SubnetMaskField: {'filter_class': MaskFilter},
        }

# vs.

class NetworkSettingFilter(FilterSet):
    mask = MaskFilter(...)

    class Meta:
        model = NetworkSetting

Nota lateral: este ponto posterior é algo que _poderíamos_ corrigir. Teríamos que reescrever a geração automática para se comportar como os serializadores do DRF em vez de como os formulários de modelo do Django. De qualquer forma, minha principal preocupação é o conflito de sintaxe.

OK. Vamos deixar por enquanto.

Gosto da proposta original. Estou inclinado a definir o escopo para _Se fields for uma lista..._ Mas preciso pensar um pouco mais.

Um pouco de idas e vindas, mas vou refazer este marco apenas para a edição original .

Ou fields ou exclude devem ser declarados. fields = '__all__' deve ser o mínimo.

(Não impor que as listas correspondam é algo a que podemos voltar.)

O código DRF relevante está aqui :

        assert not (fields is None and exclude is None), (
            "Creating a ModelSerializer without either the 'fields' attribute "
            "or the 'exclude' attribute has been deprecated since 3.3.0, "
            "and is now disallowed. Add an explicit fields = '__all__' to the "
            "{serializer_class} serializer.".format(
                serializer_class=self.__class__.__name__
            ),
        )

Precisamos de uma adição semelhante em filters_for_model :

    # Setting exclude with no fields implies all other fields.
    if exclude is not None and fields is None:
        fields = ALL_FIELDS

Ele precisará ser preterido para começar.

Ou fields ou exclude devem ser declarados. fields = '__all__' deve ser o mínimo.

Eu definitivamente posso ficar por trás disso. Atualmente trabalhando em um PR.

Frio.

Pensando nisso, não se preocupe com a depreciação. É uma pequena mudança, em uma grande mudança de versão. Apenas certifique-se de chamá-lo nas notas de alteração. 👍🏽

Pensando nisso, não se preocupe com a depreciação. É uma pequena mudança, em uma grande mudança de versão. Apenas certifique-se de chamá-lo nas notas de alteração.

A intenção é um pouco diferente, mas na verdade abordamos isso aqui .

Além disso, atualmente refatorando filters_for_model para não tentar a geração de filtros para filtros declarados. (Isso é relevante para o exemplo de sub-rede/máscara em que fields = ['mask'] geraria uma exceção desnecessária.

Fechado por #550

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