web-dev-qa-db-fra.com

Comment puis-je effectuer un filtrage non identique dans Django queryset?

Dans Django modèle QuerySets, je vois qu'il existe un __gt et __lt pour les valeurs comparatives, mais il y a un __ne/!=/<> (pas égal?)

Je veux filtrer en utilisant un pas égal:

Exemple:

Model:
    bool a;
    int x;

Je voudrais

results = Model.objects.exclude(a=true, x!=5)

Le != n'est pas une syntaxe correcte. J'ai essayé __ne, <>.

J'ai fini par utiliser:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)
587
MikeN

Peut-être que objets Q pourrait aider à résoudre ce problème. Je ne les ai jamais utilisées, mais il semble qu'elles puissent être annulées et combinées un peu comme les expressions python normales.

Mise à jour: Je viens d'essayer, cela semble assez bien fonctionner:

>>> from myapp.models import Entry
>>> from Django.db.models import Q

>>> Entry.objects.filter(~Q(id = 3))

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]
616
Dave Vogt

Votre requête semble avoir un double négatif, vous voulez exclure toutes les lignes où x n'est pas 5, donc vous voulez inclure toutes les lignes où x IS 5. Je pense que cela fera l'affaire.

results = Model.objects.filter(x=5).exclude(a=true)

Pour répondre à votre question spécifique, il n'y a pas de "différent de", mais c'est probablement parce que Django dispose des méthodes "filter" et "exclude". Vous pouvez donc toujours changer de logique pour obtenir le résultat souhaité. .

544
d4nt

la syntaxe field=value dans les requêtes est un raccourci pour field__exact=value. C'est-à-dire que Django place des opérateurs de requête sur les champs de requête dans les identifiants . Django prend en charge les opérateurs suivants:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range
year
month
day
week_day
isnull
search
regex
iregex

Je suis sûr qu'en combinant ces objets avec les objets Q comme Dave Vogt le suggère et en utilisant filter() ou exclude() comme Jason Baker suggère vous obtiendrez exactement ce dont vous avez besoin pour toutes les requêtes possibles.

118

Il est facile de créer une recherche personnalisée avec Django 1.7. Il existe un exemple de recherche __ne dans documentation officielle de Django .

Vous devez d'abord créer la recherche elle-même:

from Django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

Ensuite, vous devez l'enregistrer:

from Django.db.models.fields import Field
Field.register_lookup(NotEqual)

Et maintenant, vous pouvez utiliser la recherche __ne dans vos requêtes, comme ceci:

results = Model.objects.exclude(a=True, x__ne=5)
90
Dmitrii Mikhailov

Dans Django 1.9/1.10 , il y a trois options.

  1. Chaîne exclude et filter

    _results = Model.objects.exclude(a=true).filter(x=5)
    _
  2. Utilisez Q() objets et l'opérateur ~

    _from Django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
    _
  3. Enregistrer une fonction de recherche personnalisée

    _from Django.db.models import Lookup
    from Django.db.models.fields import Field
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params
    _

    Le décorateur _register_lookup_ a été ajouté dans Django 1.8 et permet une recherche personnalisée comme d'habitude:

    _results = Model.objects.exclude(a=True, x__ne=5)
    _
81
ilse2005

Alors qu'avec les modèles, vous pouvez filtrer avec =, __gt, __gte, __lt, __lte, vous ne pouvez pas utiliser ne, != ou <>. Cependant, vous pouvez obtenir un meilleur filtrage en utilisant l'objet Q.

Vous pouvez éviter d'enchaîner QuerySet.filter() et QuerySet.exlude(), et utilisez ceci:

from Django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')
40
Dami

En attente de la décision de conception. Pendant ce temps, utilisez exclude()

Le suivi de la question Django a le remarquable entrée # 576 , intitulé "Queryset n'a pas d'opérateur de filtre" non égal "" . Il est remarquable car (à partir d'avril 2016), il a été "ouvert il y a 9 ans" (à l'époque deDjango Pierre), "fermé il y a 4 ans" et "modifié pour la dernière fois il y a 5 mois".

Lisez la discussion, c'est intéressant. Fondamentalement, certaines personnes soutiennent que __ne devrait être ajouté, tandis que d'autres disent que exclude() est plus clair et donc __ne ne devrait pas être ajouté.

(Je suis d'accord avec le premier, parce que le dernier argument est à peu près équivalent à dire que Python ne devrait pas avoir != car il contient == et not déjà ...)

21
Lutz Prechelt

Vous devriez utiliser filter et exclude comme ceci

results = Model.objects.exclude(a=true).filter(x=5)
15
outoftime

Utiliser exclure et filtrer

results = Model.objects.filter(x=5).exclude(a=true)
14
jincy mariam

Le dernier bit de code exclura tous les objets où x! = 5 et a est True. Essaye ça:

results = Model.objects.filter(a=False, x=5)

N'oubliez pas que le signe = dans la ligne ci-dessus affecte False au paramètre a et le nombre 5 au paramètre x. Ce n'est pas vérifier l'égalité. Ainsi, il n’ya vraiment aucun moyen d’utiliser le symbole! = Dans un appel de requête.

8
Jason Baker

Ce que vous recherchez, ce sont tous les objets qui ont soit a=falseox=5. Dans Django, | sert d’opérateur OR entre les ensembles de requêtes:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)
6
Gerard
results = Model.objects.filter (a = True) .exclude (x = 5)
sélectionnez * de tablex où a! = 0 et x! = 5
6
M. Dasn

Django-model-values (divulgation: auteur) fournit une implémentation de la recherche NotEqual , comme dans cette réponse . Il fournit également un support syntaxique pour cela:

from model_values import F
Model.objects.exclude(F.x != 5, a=True)
6
A. Coady

Méfiez-vous des tas de réponses incorrectes à cette question!

La logique de Gerard est correcte, bien qu'elle renvoie une liste plutôt qu'un ensemble de requêtes (ce qui peut ne pas être important).

Si vous avez besoin d'un queryset, utilisez Q:

from Django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
0
Mark Bailey