2009-07-30 18 views
56

E 'possibile filtrare per immobile?Filtra per immobile

Ho un metodo nel mio modello:

@property 
def myproperty(self): 
    [..] 

e ora voglio filtrare da questa proprietà come:

MyModel.objects.filter(myproperty=[..]) 

è questo in qualche modo possibile?

+0

È in SQLAlchemy: http://docs.sqlalchemy.org/en/latest/orm/extensions/hybrid.html e puoi connettere django con SQLAlchemy tramite https://pypi.python.org/pypi/aldjemy ma sono dubbioso che i due possano essere collegati nel modo in cui vuoi che siano. – rattray

risposta

47

No. I filtri Django operano a livello di database, generando SQL. Per filtrare in base alle proprietà Python, devi caricare l'oggetto in Python per valutare la proprietà - e a quel punto hai già fatto tutto il lavoro per caricarlo.

+2

sfortuna che questa funzione non sia implementata, sarebbe un'estensione interessante per filtrare almeno gli oggetti corrispondenti _after_ il set di risultati è stato compilato. – schneck

+0

come gestirlo in amministrazione? C'è qualche soluzione? – andi

30

Potrei essere frainteso la tua domanda originale, ma c'è un filter integrato in python.

filtered = filter(myproperty, MyModel.objects) 

Ma è meglio usare un list comprehension:

filtered = [x for x in MyModel.objects if x.myproperty()] 

o, meglio ancora, un generator expression:

filtered = (x for x in MyModel.objects if x.myproperty()) 
+8

Che funziona per filtrarlo una volta che hai un oggetto Python, ma sta chiedendo di Django QuerySet.filter, che costruisce query SQL. –

+0

giusto, ma come spiegato sopra, vorrei aggiungere la proprietà al mio filtro di database. il filtraggio dopo che la query è stata eseguita è esattamente ciò che voglio evitare. – schneck

+0

fantastico, grazie mille! –

3

PER FAVORE qualcuno mi corregga, ma credo di aver trovato una soluzione, almeno per il mio caso.

Voglio lavorare su tutti quegli elementi le cui proprietà sono esattamente uguali a ... qualsiasi cosa.

Ma ho diversi modelli e questa routine dovrebbe funzionare per tutti i modelli. E lo fa:

def selectByProperties(modelType, specify): 
    clause = "SELECT * from %s" % modelType._meta.db_table 

    if len(specify) > 0: 
     clause += " WHERE " 
     for field, eqvalue in specify.items(): 
      clause += "%s = '%s' AND " % (field, eqvalue) 
     clause = clause [:-5] # remove last AND 

    print clause 
    return modelType.objects.raw(clause) 

Con questa subroutine universale, posso selezionare tutti quegli elementi che esattamente uguale il mio dizionario di (propertyName, propertyvalue) combinazioni di 'precisare'.

Il primo parametro prende un (models.Model),

il secondo un dizionario come: { "proprietà1": "77", "Property2": "12"}

E crea un'istruzione SQL come

SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12' 

e restituisce un QuerySet su tali elementi.

Questa è una funzione di test:

from myApp.models import myModel 

def testSelectByProperties(): 

    specify = {"property1" : "77" , "property2" : "12"} 
    subset = selectByProperties(myModel, specify) 

    nameField = "property0" 
    ## checking if that is what I expected: 
    for i in subset: 
     print i.__dict__[nameField], 
     for j in specify.keys(): 
      print i.__dict__[j], 
     print 

E? Cosa ne pensi?

7

Sembra che la mia soluzione sia using F() with annotations.

Non filtra per @property, poiché F parla al database prima che gli oggetti vengano portati in python. Ma continuando a metterlo qui come una risposta dal momento che la mia ragione per volere il filtro per proprietà era davvero voler filtrare gli oggetti con il risultato di una semplice aritmetica su due campi diversi.

così, qualcosa sulla falsariga di:

companies = Company.objects\ 
    .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\ 
    .filter(chairs_needed__lt=4) 

anziché definire la proprietà di essere:

@property 
def chairs_needed(self): 
    return self.num_employees - self.num_chairs 

poi fare una lista di comprensione tra tutti gli oggetti.

3

riffing off @ TheGrimmScientist suggerito soluzione alternativa, è possibile effettuare queste "proprietà SQL" definendoli sul Manager o il QuerySet, e il riutilizzo/chain/li compongono:

con un gestore:

class CompanyManager(models.Manager): 
    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyManager() 

Company.objects.with_chairs_needed().filter(chairs_needed__lt=4) 

Con un QuerySet:

class CompanyQuerySet(models.QuerySet): 
    def many_employees(self, n=50): 
     return self.filter(num_employees__gte=n) 

    def needs_fewer_chairs_than(self, n=5): 
     return self.with_chairs_needed().filter(chairs_needed__lt=n) 

    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyQuerySet.as_manager() 

Company.objects.needs_fewer_chairs_than(4).many_employees() 

Vedi https://docs.djangoproject.com/en/1.9/topics/db/managers/ di più. Si noti che sto uscendo dalla documentazione e non ho testato quanto sopra.

Problemi correlati