2010-02-16 10 views
58

Ho questi modelli:Django, il filtraggio query da metodo dei modelli

def Foo(Models.model): 
    size = models.IntegerField() 
    # other fields 

    def is_active(self): 
     if check_condition: 
       return True 
     else: 
       return False 

def Bar(Models.model): 
    foo = models.ForeignKey("Foo") 
    # other fields 

ora voglio interrogare Bar che stanno avendo attiva di Foo come tale:

Bar.objects.filter(foo.is_active()) 

sto ottenendo errore come

SyntaxError at/
('non-keyword arg after keyword arg' 

Come posso ottenere questo risultato?

risposta

29

Non è possibile eseguire una query su metodi o proprietà del modello. O utilizzare i criteri al suo interno nella query o filtrare in Python utilizzando una comprensione di lista o un genex.

+6

Oppure memorizzare il valore che si desidera filtrare in un campo del database e aggiornarlo quando è necessario (in genere al salvataggio). Quindi puoi filtrare/ordinare come qualsiasi altro campo. –

+2

Se riutilizzo i criteri all'interno della query del metodo, come posso rimanere DRY? I miei metodi sono estremamente importanti per la nostra logica di business e, se detta logica cambia, non posso permettermi di rompere i miei metodi. Rimanere ASCIUTTO è estremamente importante. – Flowpoke

+0

In Python si introduce una potenziale debolezza delle prestazioni dal momento che quando si utilizza il filtro di query viene eseguito a livello di database, ma quando si eseguono le prestazioni a livello di Python di solito è più lento. –

10

Non è possibile filtrare sui metodi, se il metodo is_active su Foo controlla un attributo Foo, è possibile utilizzare la sintassi doppio underscore come Bar.objects.filter(foo__is_active_attribute=True)

+0

Sto ottenendo: Impossibile risolvere la parola chiave 'is_active_attribute' nel campo Le scelte sono: .... tutti i nomi delle variabili elencati qui – Hellnar

+1

Sì, è per questo che ho detto "se il metodo is_active su Foo controlla un attributo ...". Il filtro funziona solo sui campi del database, non sui metodi. Quindi se is_active * sta controllando alcuni attributi nel metodo * puoi controllare la stessa cosa nel tuo filtro. Se sta facendo qualcosa di più complicato, sei fuori di fortuna e hai bisogno di trovare una soluzione diversa. Se vuoi una risposta specifica, pubblica il codice reale per Foo.is_active(). Altrimenti tutto quello che otterrete sono soluzioni pseudo-codice che non dovreste aspettarvi di lavorare verbatim. –

13

Ho avuto simile problema: io sto usando class-based visualizzare object_list e ho dovuto filtrare secondo il metodo del modello. (la memorizzazione delle informazioni nel database non era un'opzione in quanto la proprietà era basata sul tempo e avrei dovuto creare un cronjob e/o ...)

La mia risposta è inefficace e io no sapere come sarà scalare su dati più grandi; ma, funziona:

q = Model.objects.filter(...)... 
# here is the trick 
q_ids = [o.id for o in q if o.method()] 
q = q.filter(id__in=q_ids) 
+4

Questo è l'unico modo che vedo per rimanere DRY, tuttavia ostacolerà le prestazioni con dataset più grandi (ricorda che gli elenchi sono memorizzati in memoria) – Ben

24

È anche possibile utilizzare un gestore personalizzato. Quindi è possibile eseguire qualcosa di simile:

Bar.objects.foo_active() 

E tutto quello che dovete fare è:

class BarManager(models.Manager): 
    def foo_active(self): 
     # use your method to filter results 
     return you_custom_queryset 

Scopri i docs.

+0

il tuo codice è una introduzione molto bella! Grazie – doniyor

0
class Page(models.Model): 
    category = models.ForeignKey(Category) 
    title = models.CharField(max_length=128) 
    url = models.URLField() 
... 

class Category(models.Model): 
    ... 
    open = models.BooleanField(default=True) 

Può essere possibile utilizzare un filtro semplice, per questo tipo di condizioni.

Page.objects.filter(category__open=True) 
Problemi correlati