2
votes

Django-Filters Le paramètre de requête de chaîne vide provoque une erreur de validation

Lors de l'utilisation de django-filters avec le framework django rest, le formulaire de filtrage de requête par défaut ajoutera tous les paramètres de requête pour tous les champs, et les champs vides se terminent par des chaînes vides passées au backend. Les chaînes vides ne sont pas None, donc status = self.request.query_params.get ('status', None) ajoutera toujours la chaîne vide à la variable, et cela se dirigera vers l'ensemble de requêtes Fonction .filter. C'est très mauvais lorsque le champ filtré n'est pas une chaîne.

Ma question est donc: est-ce que je fais quelque chose de mal? Existe-t-il un moyen de vérifier les paramètres de chaîne vides? Je ne sais pas si je fais même le filtrage correctement (je filtre probablement deux fois sans raison, mais je voulais des filtres django là-dedans à cause de l'intégration intégrée avec l'API navigable de django-rest-frameworks.

Ma solution de contournement est l'opérateur ternaire vérifiant la chaîne vide après l'appel à query_params.get

Voici mon code de vue pour l'API:

< pré> XXX


0 commentaires

3 Réponses :


0
votes

Pourquoi ne pas définir la valeur par défaut sur une chaîne vide, et l'utiliser comme valeur de garde au lieu de Aucun?

status = self.request.query_params.get("status", "")
success = self.request.query_params.get("success", "")
# ...
if status:
    queryset = queryset.filter(status=status)
if success:
    queryset = queryset.filter(success=success)
# ...


0 commentaires

1
votes

Si vous utilisez if status: au lieu de si status n'est pas None: , les deux chaînes vides et None donnent False . Ceci est dangereux avec les entiers car 0 renverrait false, mais ce n'est pas un problème ici car tous les paramètres sont des chaînes.

Vous pouvez également définir '' par défaut, puis vérifiez les chaînes non nulles:

status = self.request.query_params.get('status', '')
# ...
if len(status):


0 commentaires

0
votes

Merci pour vos réponses, je pense que ce sont des approches valables mais elles font toutes les deux des vérifications manuelles. Je cherchais un moyen intégré de convertir les types natifs JSON fournis avec query_params en types natifs Python (false à False, null à None, etc.). En espérant éviter de vérifier et de convertir manuellement chaque paramètre query_param.

En fait, cela me stupéfie si une telle chose n'est pas disponible dans le Django Rest Framework. J'ai donc créé une fonction d'assistance qui peut effectuer une simple conversion profonde à un niveau de query_params vers Python dict. J'espère que cela aide quelqu'un d'autre, ou si quelqu'un connaît une fonction de commodité similaire dans DRF, je l'apprécierais. Ou si quelqu'un pouvait me dire pourquoi c'est une mauvaise approche, je l'apprécierais aussi!

def query_params_parser(self, fields_list):

        json_values_dict = {}

        for field in fields_list:
            value = '"' + self.request.query_params.get(field) + '"' if not self.query_params.get(field, '') == '' else 'null'
            json_values_dict['"' + field + '"'] = value

        json_string = '{'

        for idx, (key, value) in enumerate(json_values_dict.items()):
            json_string += f'{key}: {value}'

            if idx < len(json_values_dict) - 1:
                json_string += ','

        json_string += '}'

        final_dict = json.loads(json_string)

        return final_dict


def get_queryset(self):
        """
        This view should return a list of all the purchases
        for the currently authenticated user.
        """
        queryset = Job.objects.all()

        # parse json query_params
        # query_params, list of fields
        # returns dict

        params_dict = self.query_params_parser(['status',
                                                'success',
                                                'worker_id',
                                                'owner',
                                                'job_type'])

        status = params_dict['status']
        success = params_dict['success']
        worker_id = params_dict['worker_id']
        owner = params_dict['owner']
        job_type = params_dict['job_type']

        if status is not None:
            queryset = queryset.filter(status=status)
        if success is not None:
            queryset = queryset.filter(success=success)
        if worker_id is not None:
            queryset = queryset.filter(worker_id=worker_id)
        if owner is not None:
            queryset = queryset.filter(owner=owner)
        if job_type is not None:
            queryset = queryset.filter(job_type=job_type)

        return queryset

La fonction ci-dessus fonctionne sous des tests limités, donc elle a probablement beaucoup de bogues.


0 commentaires