2014-09-08 14 views
7

La documentazione mostra here come utilizzare l'operatore IN, ma non sono riuscito a trovare come utilizzare l'operatore NOT IN.Operatore NON IN con Peewee

Se inserisco un not <<, viene visualizzato un errore di sintassi.

Se inserisco uno not <FieldName> <<, c'è un WHERE False invece di un subquery come WHERE (<FieldName> NOT IN (SELECT ....

Ecco l'output con gli esempi di documentazione. Il primo è corretto, il secondo e il terzo sono errati.

>>> Tweet.select().where(Tweet.user << a_users).sql() 
('SELECT t1."id", t1."user_id", t1."message", t1."created_date", t1."is_published" FROM "tweet" AS t1 WHERE (t1."user_id" IN (SELECT t2."id" FROM "user" AS t2 WHERE (Lower(Substr(t2."username", ?, ?)) = ?)))', [1, 1, 'a']) 
>>> Tweet.select().where(not Tweet.user << a_users).sql() 
('SELECT t1."id", t1."user_id", t1."message", t1."created_date", t1."is_published" FROM "tweet" AS t1 WHERE ?', [False]) 
>>> Tweet.select().where(Tweet.user not << a_users).sql() 
SyntaxError: invalid syntax 
+0

'not in' è letteralmente un singolo operatore denominato' not in', non significa che è possibile inserire 'not' prima di qualsiasi altro operatore. Il fatto che Peewee reinterpreti '<<' per significare un 'IN' SQL non significa che possa cambiare la sintassi di Python. – abarnert

+0

@abarnert Lo so ... quindi la mia domanda – stenci

risposta

15

Semplice:

Tweet.select().where(Tweet.user.not_in(a_users)) 

Per leggermente diverse semantiche (NOT (x in y)) al contrario di (x NOT IN y):

Tweet.select().where(~(Tweet.user << a_users)) 
+1

Sì, questo ha senso, '~' è overrideable e non ha bisogno di restituire un booleano. Tuttavia, non sembra documentato da nessuna parte. – kindall

+0

Kindall, puoi gentilmente aggiornare o rimuovere la tua risposta? Non è corretto e può causare confusione ad altri lettori. – coleifer

+0

Esiste un operatore 'exists'? Trovo strano che tu supporti le funzioni della finestra ma non 'not' e' exists' –

0

Questo non ha nulla a che fare con Peewee, davvero. Peewee sta usando alcuni operatori Python per i propri scopi. << è normalmente un operatore numerico e non ha senso prendere la sua negazione logica. Pertanto not << non è mai una sintassi Python valida.

Il secondo esempio è vicino, ma not applica solo a Tweet.user (not avente precedenza maggiore rispetto <<). Aggiungete un po 'parentesi e si ottiene:

Tweet.select().where(not (Tweet.user << a_users)).sql() 

Ora, questo ancora non è giusto, come hai scoperto (lettori: vedere i commenti per qualche discussione su questo). not restituisce un valore booleano, che non è quello che si desidera e non funzionerà. Peewee ripropone l'operatore ~ per questo; dai un'occhiata alla risposta di @ coleifer.

+0

Nel caso ti stia chiedendo _why_ Peewee userebbe '<<' invece di usare semplicemente 'in' (nel qual caso potresti usare' not in' qui); l'operatore 'in' deve restituire un' bool', non un oggetto query o altro. (Cosa succede se non restituisce un bool? Dipende dalla tua implementazione e versione di Python, potrebbe essere un errore, o potrebbe essere convertito in 'bool', ma in entrambi i casi, non è molto utile ...) – abarnert

+0

I don capisco la tua risposta Per come l'ho capito, quegli operatori sono usati da Peewee per creare un comando SQL, non sono interpretati da Python. Infatti se provi la tua espressione ottieni un '... WHERE False', come nel mio secondo caso senza parentesi. – stenci

+0

Non possono * non * essere interpretati da Python. Peewee fornisce oggetti Python speciali che sovrascrivono operatori come '<<' per costruire una query SQL.In altre parole, in Peewee non c'è nulla che veda mai "Tweet.user << a_users' e ne faccia qualcosa, tutto ciò avviene con metodi su' Tweet.user'. Il risultato è una sorta di linguaggio specifico del dominio (DSL) che funziona perfettamente con Python perché * è * Python. Sfortunatamente, ho indovinato su una soluzione al tuo problema. – kindall

2

So che questo è un "necro -posting ", ma questa domanda viene prima trovata su Google per la query peewee not in, quindi mi piacerebbe aggiungerla qui:

Puoi anche utilizzare il metodo not_in che è descritto nel documento:

Tweet.select().where(Tweet.user.not_in(a_users)) 

Per quanto mi riguarda, sembra molto più leggibile del costrutto ~ ... <<.

+1

Ehi, grazie per aver menzionato questo! Ho aggiornato la mia risposta per includere le modifiche, quindi spero che più gente lo veda. – coleifer