2009-05-26 9 views
5

J'essaye d'implémenter quelque chose comme des trouveurs dynamiques de Rails en Python (pour webapp/GAE). Les moteurs de recherche dynamiques fonctionnent comme ceci:Finders dynamiques et méthode manquant en Python

  • Votre personne possède des champs: nom, âge et adresse électronique.
  • Supposons que vous vouliez trouver tous les utilisateurs dont le nom est "Robot".

La classe Person a une méthode appelée « find_by_name » qui reçoit le nom et renvoie le résultat de la requête:

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

Au lieu d'avoir à écrire une méthode comme celle pour chaque attribut, je J'aimerais avoir quelque chose comme Methodymy de Ruby qui me permet de le faire.

Jusqu'à présent, j'ai vu ces messages 2 blog: http://blog.iffy.us/?p=43 et http://www.whatspop.com/blog/2008/08/method-missing-in-python.cfm mais je aime entendre ce qui est de la façon de faire « la plus correspond le » il.

Répondre

7

Il n'y a vraiment pas besoin d'utiliser GQL ici - cela complique les choses. Voici une implémentation simple:

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) 

Notez qu'il retourne un objet de requête, que vous pouvez appeler .get(), .fetch() etc sur; C'est plus polyvalent, mais si vous voulez, vous pouvez bien sûr le faire juste retourner une seule entité.

+0

J'ai essayé d'utiliser ce code mais j'obtiens toujours: 'AttributeError (" type object 'FindableModel' n'a pas d'attribut 'find_by_name' ",)'. Pouvez-vous expliquer un peu plus comment l'utiliser? – hakunin

+0

@hakunin Comment l'utilisez-vous? Vous devriez en faire la classe parente de votre modèle. –

+0

Voici le modèle que j'utilise: https://gist.github.com/2014164 J'adorerais utiliser '__getattr__' mais il n'est tout simplement pas appelé pour une raison quelconque. – 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__ est une mauvaise idée ici, utilisez __getattr__, elle ne sera appelée que pour les attributs manquants. –

+0

ok je l'ai changé – Unknown

1

Vous pouvez utiliser une méthode « find_by » et des mots-clés, comme Django fait:

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') 

sur cette route, vous pouvez finir par la conception de votre propre syntaxe de requête. Jetez un oeil à ce que Django fait ...

0
class Person: 

    name = "" 
    age = 0 
    salary = 0 

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

trouver def (clsobj, * args): Personne de retour (name = "Jack", âge = 20)

La boucle for ci-dessous pour tous les inserts @classmethod attributs de classe. Cela rend les méthodes liées "find_by_name", "find_by_age" et "sinf_by_salary" disponibles.

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

impression Person.find_by_name ("jack"). # Âge imprimera valeur 20.

Je ne sais pas si cela la bonne façon de faire les choses. Mais si vous êtes en mesure d'implémenter une "recherche" unifiée pour tous les attributs, alors le script ci-dessus fonctionne.

Questions connexes