2009-08-04 3 views
16

Je veux chercher une certaine chaîne dans plusieurs champs d'un modèle dans Django. Idéalement, il irait quelque chose de similaire à:Comment fournir dynamiquement le nom d'un champ de recherche dans une requête Django?

keyword = 'keyword' 
fields = ['foo', 'bar', 'baz'] 
results = [] 
for field in fields: 
    lookup = "%s__contains" 
    results.append(Item.objects.filter(lookup=keyword)) 

Bien sûr, cela ne fonctionnera pas, comme « rechercher » ne peut pas être résolue dans un champ. Y a-t-un autre moyen de faire ça?

+0

Merci pour le lien dupe - je cherchais mais il est difficile d'obtenir la bonne combinaison de mots-clés dans celui-ci. –

Répondre

15

Je pense qu'il pourrait y avoir une meilleure façon de le faire avec le système de requête Django. Voici comment le faire à votre façon.

Python vous permet de passer des dictionnaires à utiliser comme listes d'arguments en les préfixant avec **. Avec un peu de chance, vous devriez être en mesure de faire quelque chose comme ceci:

lookup = "%s__contains" % field 
results.append(Item.objects.filter(**{ lookup: keyword})) 
+0

Jetez un oeil à la réponse de Botondus ci-dessous. C'est la solution avec le système de requête Django auquel je me suis référé, et il devrait heureusement fonctionner plus vite puisqu'il s'exécutera en SQL. –

4

J'aime la réponse de DialZ mais pour des raisons de performances, vous devez construire la requête, puis appuyez sur la base de données une fois au lieu de concaténer tous les résultats en une liste:

keyword = 'keyword' 
fields = ['foo', 'bar', 'baz'] 

# this makes an empty queryset object which we can 
# add to later using the | operator 
results = Item.objects.none() 

for field in fields: 
    lookup = "%s__contains" % field 
    query = {lookup : keyword} 
    results = results | Item.objects.filter(**query) 

Je havn't fait l'un de ceux-ci dans un certain temps, mais je suis sûr django ne sera pas réellement touché la base de données du tout dans ce code. Il n'effectuera une requête que lorsque vous accéderez aux données contenues dans les enregistrements

23

Je préférerais utiliser l'objet Q pour quelque chose comme ça.

from django.db.models import Q 

keyword = 'keyword' 
fields = ['foo', 'bar', 'baz'] 

Qr = None 
for field in fields: 
    q = Q(**{"%s__contains" % field: keyword }) 
    if Qr: 
     Qr = Qr | q # or & for filtering 
    else: 
     Qr = q 

# this you can now combine with other filters, exclude etc.  
results = MyModel.objects.filter(Qr) 
+1

C'est une réponse absolument merveilleuse. Il a fait ma journée pour le rencontrer. Avez-vous posté à ce sujet partout? Je ne pense pas que la plupart des gens se rendent compte que cela est possible (boucle sur les noms de champs pour remplir une dictée de Q objet kwargs). – jMyles

+1

@jMyles: Merci, je suis heureux de pouvoir vous aider. Non, je ne pense pas en avoir parlé ailleurs. Mais en général, la combinaison dynamique des objets 'Q' est une méthode très puissante pour construire facilement des requêtes complexes. –

+0

Je viens de poster une question à laquelle la réponse pourrait être similaire - je peux utiliser une boucle et l'opérateur ET de Q. C'est ici: http://stackoverflow.com/questions/6783747/django-queryset-to-match-all-related-objects – jMyles

Questions connexes