Django ORM: Filtrer par attribut supplémentaire
Je veux filtrer certains objets de base de données par une chaîne concaténée.
La normale requête SQL serait:
SELECT concat(firstName, ' ', name) FROM person WHERE CONCAT(firstName, ' ', name) LIKE "a%";
Dans le modèle, j'ai créé un gestionnaire appelé PersonObjects:
class PersonObjects(Manager):
attrs = {
'fullName': "CONCAT(firstName, ' ', name)"
}
def get_query_set(self):
return super(PersonObjects, self).get_query_set().extra(
select=self.attrs)
J'ai aussi configuré dans mon modèle:
objects = managers.PersonObjects()
Aujourd'hui accès à l'fullName travaille pour des objets:
>>> p = models.Person.objects.get(pk=4)
>>> p.fullName
u'Fred Borminski'
Mais il ne fonctionne pas dans un filtre:
>>> p = models.Person.objects.filter(fullName__startswith='Alexei')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.7/site-packages/django/db/models/manager.py", line 141, in filter
return self.get_query_set().filter(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 550, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 568, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1128, in add_q
can_reuse=used_aliases)
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1026, in add_filter
negate=negate, process_extras=process_extras)
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1191, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'fullName' into field. Choices are: firstName, gender, name, (...)
Est-ce un bug ou une fonctionnalité? Comment puis-je résoudre ce problème?
Grâce.
source d'informationauteur Danilo Bargen
Vous devez vous connecter pour publier un commentaire.
Ce n'est pas un bug.
filter()
inspecte seulement les définitions de modèle, de sorte qu'il ne reconnaît pasfullName
comme une déclaration de champ (parce qu'il ne l'est pas - c'est un argument supplémentaire dans une requête).Vous pouvez ajouter la
fullName
àWHERE
à l'aide deextra()
:J'ai résolu ce problème en mettant en œuvre une coutume fonction d'Agrégation.
Dans ce cas, j'avais besoin de concaténer des champs individuels dans une adresse de rue pour être en mesure de filtrer/recherche de correspondances.
La suite de fonction d'agrégation permet de spécifier un champ et une ou plusieurs autres à exécuter une SQL CONCAT_WS.
Modifier 3 Août 2015:
Une meilleure mise en œuvre avec des détails glanés partir de https://stackoverflow.com/a/19529861/3230522. La précédente mise en œuvre serait un échec si le queryset a été utilisé dans une sous-requête. Les noms de table sont maintenant correct, mais je remarque que cela travaille juste pour la concaténation des colonnes de la même table.
La solution proposée a travaillé beaucoup avec postgresql et JSONB champs dans le code ci-dessous. Seuls les enregistrements qui ont le "partenaire" clé sous la " clé " jsonb champ sont retournés: