É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 d'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`.
python
django
django-models
Brian M. Hunt
la source
la source
Un exemple simplifié:
Dans une application de sondage Django, je voulais une liste de sélection HTML montrant les utilisateurs enregistrés. Mais comme nous avons 5000 utilisateurs enregistrés, j'avais besoin d'un moyen de filtrer cette liste en fonction de critères de requête (comme uniquement les personnes ayant terminé un certain atelier). Pour que l'élément d'enquête soit réutilisable, il fallait que la personne qui crée la question d'enquête puisse associer ces critères à cette question (ne souhaitant 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:
Cette chaîne est stockée dans la base de données. Dans le code de vue, il revient en tant que
self.question.custom_query
. La valeur de cela est une chaîne qui ressemble à un dictionnaire. Nous le transformons en un vrai dictionnaire avec eval (), puis le remplissons dans le jeu de requêtes avec ** kwargs:la source
eval()
l'importation d'utilisateurs est une mauvaise idée, même si vous faites entièrement confiance à vos utilisateurs. Un champ JSON serait une meilleure idée ici.Django.db.models.Q est exactement ce que vous voulez d'une manière Django.
la source
Q(**filters)
, si vous souhaitez créer dynamiquement des objets Q, vous pouvez les mettre dans une liste et utiliser.filter(*q_objects)
, ou utiliser les opérateurs au niveau du bit pour combiner les objets Q.Un formulaire de recherche très complexe indique généralement qu'un modèle plus simple essaie de creuser son chemin.
Comment, exactement, prévoyez-vous obtenir les valeurs pour le nom de la colonne et l'opération? D'où tirez-vous les valeurs d'
'name'
un'startswith'
?Un formulaire de «recherche»? Vous allez - quoi? - choisir le nom dans une liste de noms? Choisissez l'opération dans une liste d'opérations? Bien que ouvert, la plupart des gens trouvent cela déroutant et difficile à utiliser.
Combien de colonnes ont de tels filtres? 6? 12? 18?
Boutons de filtre spécifiques. Attendez ... C'est ainsi que fonctionne l'administrateur Django. Des filtres spécifiques sont transformés en boutons. Et la même analyse que ci-dessus s'applique. Quelques filtres ont du sens. Un grand nombre de filtres signifie généralement une sorte de première violation de forme normale.
Un grand nombre de champs similaires signifie souvent qu'il aurait dû y avoir plus de lignes et moins de champs.
la source