9

Corro Django 1.9 con il nuovo JSONField e hanno il seguente modello di prova:Django filtrare l'elenco JSONField di dicts

class Test(TimeStampedModel): 
    actions = JSONField() 

Diciamo che l'azione JSONField assomiglia a questo:

[ 
    { 
    "fixed_key_1": "foo1", 
    "fixed_key_2": { 
     "random_key_1": "bar1", 
     "random_key_2": "bar2", 
    } 
    }, 
    { 
    "fixed_key_1": "foo2", 
    "fixed_key_2": { 
     "random_key_3": "bar2", 
     "random_key_4": "bar3", 
    } 
    } 
] 

voglio essere in grado di filtrare i tasti foo1 e foo2 per ogni elemento della lista. Quando faccio:

>>> Test.objects.filter(actions__1__fixed_key_1="foo2") 

La prova è nel set di query. Ma quando lo faccio:

>>> Test.objects.filter(actions__0__fixed_key_1="foo2") 

Non lo è, il che ha senso. Voglio fare qualcosa di simile:

>>> Test.objects.filter(actions__values__fixed_key_1="foo2") 

O

>>> Test.objects.filter(actions__values__fixed_key_2__values__contains="bar3") 

E avere la prova nel set di query.

Qualche idea se questo può essere fatto e come?

risposta

2

È possibile utilizzare il pacchetto django-jsonfield, suppongo che sia già quello che si sta utilizzando.

from jsonfield import JSONField 
class Test(TimeStampedModel): 
    actions = JSONField() 

Quindi, per cercare di fare una ricerca con una proprietà specifica, si può solo fare questo:

def test_filter(**kwargs): 
    result = Test.objects.filter(actions__contains=kwargs) 
    return result 

Se si utilizza PostgreSQL, forse si può usufruire di PostgreSQL specific model fields.

PS: Se si ha a che fare con un sacco di strutture JSON, è possibile prendere in considerazione l'utilizzo del database NoSQL.

+1

In realtà sto già utilizzando il campo del modello specifico JSONField di PostgreSQL ('da django.contrib.postgres.fields import JSONField').La soluzione funziona quando 'your_property' è noto (' fixed_key_1' e 'fixed_key_2' nel mio caso) ma come posso fare quando non conosco' your_property' ('random_key_ #' nel mio caso)? – Scentle5S

+0

Dovresti rendere '{'fixed_key_1': 'foo2'}' il tuo parametro, ho aggiornato il codice con la funzione generica. – DhiaTN

+1

La cosa è che non so in particolare 'your_property'. Potrebbe essere qualsiasi cosa e non mi interessa nemmeno, voglio solo sapere se JSONField contiene una determinata stringa in uno qualsiasi dei suoi valori, indipendentemente dalla profondità. – Scentle5S

2

Si dovrebbe essere in grado di utilizzare una ricerca __contains per questo, come documentato here. La ricerca sarebbe ancora come quella che DhiaTN ha raccomandato sopra. Quindi, qualcosa di simile a questo dovrebbe funzionare:

Test.objects.filter(actions__contains={'fixed_key_1': 'foo2'}) 
15

Se wan't per filtrare i dati da uno dei campi nel gamma di dicts, si può provare questa query:

Test.objects.filter(actions__contains=[{'fixed_key_1': 'foo2'}]) 

Elencherà tutti gli oggetti Test che hanno almeno un oggetto nel campo actions che contiene la chiave fixed_key_1 del valore foo2.

Inoltre dovrebbe funzionare per la ricerca nidificato, anche se non si conoscono gli indici attuali:

Test(actions=[ 
    {'fixed_key_1': 'foo4', 'fixed_key_3': [ 
     {'key1': 'foo2'}, 
    ]} 
}).save() 

Test.objects.filter(actions__contains=[{'fixed_key_3': [{'key1': 'foo2'}]}]) 

In parole semplici, contiene ignorerà tutto il resto.

Sfortunatamente, se l'elemento nidificato è un oggetto, è necessario conoscere il nome della chiave. La ricerca per valore non funzionerà in quel caso.