2009-05-26 8 views
5

Sto cercando di implementare qualcosa come i finder dinamici di Rails in Python (per la webapp/GAE ). I rilevatori dinamici funzionano in questo modo:Finder dinamici e metodo mancanti in Python

  • La persona ha alcuni campi: nome, età e indirizzo email.
  • Supponiamo di voler trovare tutti gli utenti il ​​cui nome è "Robot".

La classe Persona ha un metodo chiamato "find_by_name" che riceve il nome e restituisce il risultato della query:

@classmethod 
def find_by_name(cls, name): 
    return Person.gql("WHERE name = :1", name).get() 

Invece di dover scrivere un metodo del genere per ogni attributo, io Mi piacerebbe avere qualcosa come il metodo_missing di Ruby che mi permette di farlo.

Finora ho visto questi posti 2 del blog: http://blog.iffy.us/?p=43 e http://www.whatspop.com/blog/2008/08/method-missing-in-python.cfm ma mi piacerebbe piace sentire qual è il modo "più appropriata" di farlo.

risposta

7

Non c'è davvero bisogno di usare GQL qui - semplicemente complica le cose. Ecco una semplice implementazione:

class FindableModel(db.Model): 
    def __getattr__(self, name): 
    if not name.startswith("find_by_"): 
     raise AttributeError(name) 
    field = name[len("find_by_"):] 
    return lambda value: self.all().filter(field, value) 

noti che restituisce un oggetto Query, che si può chiamare .get(), .fetch() ecc su; questo è più versatile, ma se vuoi puoi ovviamente farlo restituire una singola entità.

+0

Ho provato a usare questo codice ma ottengo ancora: 'AttributeError (" tipo oggetto 'FindableModel' non ha attributo 'find_by_name' ",)'. Puoi spiegare un po 'di più come usare questo? – hakunin

+0

@hakunin Come lo stai usando? Dovresti fare di questo la classe genitrice del tuo modello. –

+0

Ecco il modello che uso: https://gist.github.com/2014164 Mi piacerebbe usare '__getattr__' ma non viene chiamato per qualche motivo. – hakunin

0
class Person(object): 
    def __getattr__(self, name): 
     if not name.startswith("find_by"): raise AttributeError(name) 
     field_name = name.split("find_by_",1)[1] 
     return lambda name: Person.gql("WHERE %s = :1" % field_name, name).get() 
+1

__getattribute__ è una cattiva idea qui, usa __getattr__, verrà chiamato solo per gli attributi mancanti. –

+0

ok lo ho cambiato – Unknown

1

è possibile utilizzare un metodo di 'find_by' e le parole chiave, come Django fa:

class Person (object): 
    def find_by(self, *kw): 
     qspec = ' AND '.join('%s=%s' % kv for kv in kw.items()) 
     return self.gql('WHERE ' + qspec) 

person.find_by(name='Robot') 
person.find_by(name='Robot', age='2') 

su questa strada si può finire per progettare il proprio sintassi di query. Dai un'occhiata a cosa fa Django ...

0
class Person: 

    name = "" 
    age = 0 
    salary = 0 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

def trovare (clsobj, * args): persona andata e ritorno (name = "Jack", età = 20)

il ciclo for seguito inserti @classmethod per tutti gli attributi di classe. Ciò rende disponibili i metodi associati a "find_by_name", "find_by_age" e "sinf_by_salary".

for attr in Person.__dict__.keys(): 
    setattr(Person, 'find_by_'+attr, find) 
    setattr(Person, 'find_by_'+attr, classmethod(find)) 

stampa Person.find_by_name ("jack"). Età # stamperà valore 20.

Non sono sicuro se questo il modo giusto di fare le cose. Ma se sei in grado di implementare un "find" unificato per tutti gli attributi, allora lo script sopra funziona.

Problemi correlati