web-dev-qa-db-fra.com

Dans Django, comment filtre-t-on un QuerySet avec des recherches de champs dynamiques?

Étant donné une classe:

from Django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

Est-il possible, et si oui, comment, d'avoir un QuerySet qui filtre en fonction des arguments dynamiques? Par exemple:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.
147
Brian M. Hunt

L'expansion des arguments de Python peut être utilisée pour résoudre ce problème:

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

Ceci est un idiome Python très courant et très utile.

282
Daniel Naab

Un exemple simplifié:

Dans une application d'enquête Django, je voulais une liste de sélection HTML montrant les utilisateurs enregistrés. Mais parce que nous avons 5000 utilisateurs enregistrés, j'avais besoin d'un moyen de filtrer cette liste en fonction de critères de requête (tels que des personnes uniquement). qui a terminé un certain atelier). Pour que l'élément d'enquête soit réutilisable, j'avais besoin que la personne créant la question d'enquête puisse associer ces critères à cette question (je ne veux pas coder en dur la requête dans l'application).

La solution que j'ai trouvée n'est pas 100% conviviale (nécessite l'aide d'un technicien pour créer la requête), mais elle résout le problème. Lors de la création de la question, l'éditeur peut saisir un dictionnaire dans un champ personnalisé, par exemple:

{'is_staff':True,'last_name__startswith':'A',}

Cette chaîne est stockée dans la base de données. Dans le code d'affichage, il revient en tant que self.question.custom_query. La valeur de cela est une chaîne qui ressemble comme un dictionnaire. Nous le transformons en un dictionnaire réel avec eval (), puis nous le remplissons dans le jeu de requêtes avec ** kwargs:

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   
6
shacker

Django.db.models.Q est exactement ce que vous voulez d'une manière Django.

5
Brent81