2012-08-10 13 views
13

diciamo che ho un modello Indirizzo con un campo di codice postale. Posso occhiata indirizzi con codice postale che inizia con "123" con questa linea:Django inizia con i campi

Address.objects.filter(postcode__startswith="123") 

Ora, ho bisogno di fare questa ricerca il "contrario". Ho un modello Address con un campo postcode_prefix e ho bisogno di recuperare tutti gli indirizzi per i quali postcode_prefix è un prefisso di un determinato codice, come "12345". Quindi se nel mio db avevo 2 indirizzi con postcode_prefix = "123" e "234", solo il primo sarebbe stato restituito.

Qualcosa di simile:

Address.objects.filter("12345".startswith(postcode_prefix)) 

Il problema è che questo non funziona. L'unica soluzione che posso venire con è quello di eseguire un filtro sul primo carattere, come:

Address.objects.filter(postcode_prefix__startswith="12345"[0]) 

e poi, quando ricevo i risultati, fare una lista di comprensione che li filtra correttamente, in questo modo:

results = [r for r in results if "12345".startswith(r.postcode_prefix)] 

C'è un modo migliore per farlo in django? ringraziamento, Fabrizio

+0

La lunghezza del prefisso è fissa o ha una lunghezza variabile? – cyroxx

+0

lunghezza variabile :) – sfabriz

risposta

8

In termini SQL, ciò che si vuole raggiungere si legge come ('12345' è il codice postale che si sta cercando):

SELECT * 
FROM address 
WHERE '12345' LIKE postcode_prefix||'%' 

questo non è davvero una query standard e non vedo alcuna possibilità di raggiungere questo obiettivo in Django utilizzando solo get()/filtro().

Tuttavia, Django offre un modo per fornire le clausole SQL aggiuntive con extra():

postcode = '12345' 
Address.objects.extra(where=["%s LIKE postcode_prefix||'%%'"], params=[postcode]) 

prega di consultare il Django documentation on extra() per ulteriore riferimento. Si noti inoltre che l'extra contiene puro SQL, quindi è necessario assicurarsi che la clausola sia valida per il proprio database.

Spero che questo funzioni per voi.

+1

Grazie. Questo è probabilmente il modo migliore per farlo, anche se, come dici tu, diventa dipendente da db. Sono felice però che non ci sia una veloce magia django che mi mancava. Grazie mille! Fabrizio – sfabriz

11

Penso che quello che si sta cercando di fare con il tuo "qualcosa come" la linea è correttamente scritto come questo:

Address.objects.filter(postcode__startswith=postcode_prefix) 
+0

In realtà OP vuole il contrario. – cyroxx

+0

Esattamente. Ho bisogno del contrario. Posso farlo con Python, in più di un modo, ma avevo solo bisogno di sapere se mi mancava un modo corretto di django per farlo. :) – sfabriz

0

A. Se non il problema https://code.djangoproject.com/ticket/13363, si potrebbe fare questo:

queryset.extra(select={'myconst': "'this superstring is myconst value'"}).filter(myconst__contains=F('myfield')) 

Forse, saranno risolvere un problema e può funzionare.

B. Se non si tratta del problema 16731 ​​(mi spiace non fornire l'url completo, non un rappresentante sufficiente, vedere un altro ticket sopra) è possibile filtrare per campi aggiunti con ".annotate", con la creazione della funzione di aggreazione personalizzata, come qui: http://coder.cl/2011/09/custom-aggregates-on-django/

C. Ultimo e riuscito. Sono riuscito a farlo usando monkeypatching delle seguenti operazioni:

  1. django.db.models.sql.Query.query_terms
  2. django.db.models.fields.Field.get_prep_lookup
  3. django.db.models.fields.Field.get_db_prep_lookup
  4. django.db.models.sql.where.WhereNode.make_atom

di ricerca personalizzato appena definito '_ inizio', che ha inverso logica di ' _startswith'

0

Una possibile alternativa. (Hanno idea di come si confronta con la soluzione accettata con una colonna come il secondo parametro a come, in tempo di esecuzione)

q=reduce(lambda a,b:a|b, [Q(postcode__startswith=postcode[:i+1]) for i in range(len(postcode))])

Così, si generano tutti i prefissi, ed o insieme ...

Problemi correlati